/** * Lists remote packages available for install using {@link UpdaterData#updateOrInstallAll_NoGUI}. * * @param includeAll True to list and install all packages, including obsolete ones. * @param extendedOutput True to display more details on each package. */ public void listRemotePackages_NoGUI(boolean includeAll, boolean extendedOutput) { List<ArchiveInfo> archives = getRemoteArchives_NoGUI(includeAll); mSdkLog.info("Packages available for installation or update: %1$d\n", archives.size()); int index = 1; for (ArchiveInfo ai : archives) { Archive a = ai.getNewArchive(); if (a != null) { Package p = a.getParentPackage(); if (p != null) { if (extendedOutput) { mSdkLog.info("----------\n"); mSdkLog.info("id: %1$d or \"%2$s\"\n", index, p.installId()); mSdkLog.info( " Type: %1$s\n", p.getClass() .getSimpleName() .replaceAll("Package", "")); // $NON-NLS-1$ //$NON-NLS-2$ String desc = LineUtil.reformatLine(" Desc: %s\n", p.getLongDescription()); mSdkLog.info("%s", desc); // $NON-NLS-1$ } else { mSdkLog.info("%1$ 4d- %2$s\n", index, p.getShortDescription()); } index++; } } } }
private int getDependencyOrder(ArchiveInfo ai) { if (ai == null) { return 0; } // reuse cached value, if any Integer cached = mOrders.get(ai); if (cached != null) { return cached.intValue(); } ArchiveInfo[] deps = ai.getDependsOn(); if (deps == null) { return 0; } // compute dependencies, recursively int n = deps.length; for (ArchiveInfo dep : deps) { n += getDependencyOrder(dep); } // cache it mOrders.put(ai, Integer.valueOf(n)); return n; }
private License getArchiveInfoLicense(ArchiveInfo ai) { Archive a = ai.getNewArchive(); if (a != null) { Package p = a.getParentPackage(); if (p != null) { License lic = p.getLicense(); if (lic != null && lic.getLicenseRef() != null && !lic.getLicense().isEmpty() && lic.getLicense() != null && !lic.getLicense().isEmpty()) { return lic; } } } return null; }
private static void addDependencies( @NonNull List<ArchiveInfo> dependencies, @NonNull ArchiveInfo archive, @NonNull Set<ArchiveInfo> visited) { if (visited.contains(archive)) { return; } visited.add(archive); ArchiveInfo[] dependsOn = archive.getDependsOn(); if (dependsOn != null) { for (ArchiveInfo dependency : dependsOn) { if (!dependencies.contains(dependency)) { dependencies.add(dependency); addDependencies(dependencies, dependency, visited); } } } }
/** * Get list of each asset to be replaced, and the shots it's in. * * @return * @throws PipelineException */ private boolean getShotsUsingAssets() throws PipelineException { ArrayList<ArchiveInfo> archive = mclient.archiveQuery(shotPattern, null); logLine("Looking for shots using lo-res assets."); for (ArchiveInfo curArc : archive) { String name = curArc.getName(); VersionID vid = curArc.getVersionID(); TreeSet<VersionID> allVers = mclient.getCheckedInVersionIDs(name); if (!vid.equals(allVers.last())) continue; NodeVersion ver = mclient.getCheckedInVersion(name, vid); Set<String> srcs = ver.getSourceNames(); for (String loResAsset : pAssetManager.keySet()) { if (srcs.contains(loResAsset)) { // TODO chec if latest. logLine("\t" + getShortName(loResAsset) + ": " + getShortName(name)); AssetInfo tempInfo = pAssetManager.get(loResAsset); if (!tempInfo.getLoHiResShots().containsKey(name)) tempInfo.getLoHiResShots().put(name, null); } // end if } // end for } // end for logLine("Looking for shots using hi-res assets"); /* - Populate lo-res */ for (ArchiveInfo curArc : archive) { String name = curArc.getName(); VersionID vid = curArc.getVersionID(); TreeSet<VersionID> allVers = mclient.getCheckedInVersionIDs(name); if (!vid.equals(allVers.last())) continue; NodeVersion ver = mclient.getCheckedInVersion(name, vid); Set<String> srcs = ver.getSourceNames(); for (String updateAsset : pAssetManager.keySet()) { String hiResAsset = updateAsset.replace(lr, ""); if (srcs.contains(hiResAsset)) { logLine("\t" + getShortName(hiResAsset) + ": " + getShortName(name)); AssetInfo tempInfo = pAssetManager.get(updateAsset); String loRes = tempInfo.getMatchingLoResShot(name); if (loRes == null) { logLine( "!!!\nWARNING:" + getShortName(hiResAsset) + " is used in the " + getShortName(name) + " node which has no matching lo-res model in an anim node." + " So it will not be changed\n!!!"); continue; } tempInfo.getLoHiResShots().put(loRes, name); } // end if } // end for } // end for(ArchiveInfo) logLine(""); for (String updateAsset : potentialUpdates) { TreeMap<String, String> shots = pAssetManager.get(updateAsset).getLoHiResShots(); if (shots.isEmpty()) { logLine(getShortName(updateAsset) + " is not used in any shots"); pAssetManager.remove(updateAsset); } for (String loRes : shots.keySet()) { if (shots.get(loRes) == null) logLine( getShortName(updateAsset) + " is in a hi-res shot, " + getShortName(loRes) + ", but doesn't have a matching hi-res" + "model in the lgt node."); } } if (pAssetManager.isEmpty()) return false; return true; } // end getShotsUsingAssets
/** * Tries to update all the *existing* local packages. This version is intended to run without a * GUI and only outputs to the current {@link ILogger}. * * @param pkgFilter A list of {@link SdkRepoConstants#NODES} or {@link Package#installId()} or * package indexes to limit the packages we can update or install. A null or empty list means * to update everything possible. * @param includeAll True to list and install all packages, including obsolete ones. * @param dryMode True to check what would be updated/installed but do not actually download or * install anything. * @return A list of archives that have been installed. Can be null if nothing was done. */ public List<Archive> updateOrInstallAll_NoGUI( Collection<String> pkgFilter, boolean includeAll, boolean dryMode) { List<ArchiveInfo> archives = getRemoteArchives_NoGUI(includeAll); // Filter the selected archives to only keep the ones matching the filter if (pkgFilter != null && pkgFilter.size() > 0 && archives != null && archives.size() > 0) { // Map filter types to an SdkRepository Package type, // e.g. create a map "platform" => PlatformPackage.class HashMap<String, Class<? extends Package>> pkgMap = new HashMap<String, Class<? extends Package>>(); mapFilterToPackageClass(pkgMap, SdkRepoConstants.NODES); mapFilterToPackageClass(pkgMap, SdkAddonConstants.NODES); // Prepare a map install-id => package instance HashMap<String, Package> installIdMap = new HashMap<String, Package>(); for (ArchiveInfo ai : archives) { Archive a = ai.getNewArchive(); if (a != null) { Package p = a.getParentPackage(); if (p != null) { String id = p.installId(); if (id != null && id.length() > 0 && !installIdMap.containsKey(id)) { installIdMap.put(id, p); } } } } // Now intersect this with the pkgFilter requested by the user, in order to // only keep the classes that the user wants to install. // We also create a set with the package indices requested by the user // and a set of install-ids requested by the user. HashSet<Class<? extends Package>> userFilteredClasses = new HashSet<Class<? extends Package>>(); SparseIntArray userFilteredIndices = new SparseIntArray(); Set<String> userFilteredInstallIds = new HashSet<String>(); for (String type : pkgFilter) { if (installIdMap.containsKey(type)) { userFilteredInstallIds.add(type); } else if (type.replaceAll("[0-9]+", "").length() == 0) { // $NON-NLS-1$ //$NON-NLS-2$ // An all-digit number is a package index requested by the user. int index = Integer.parseInt(type); userFilteredIndices.put(index, index); } else if (pkgMap.containsKey(type)) { userFilteredClasses.add(pkgMap.get(type)); } else { // This should not happen unless there's a mismatch in the package map. mSdkLog.error(null, "Ignoring unknown package filter '%1$s'", type); } } // we don't need the maps anymore pkgMap = null; installIdMap = null; // Now filter the remote archives list to keep: // - any package which class matches userFilteredClasses // - any package index which matches userFilteredIndices // - any package install id which matches userFilteredInstallIds int index = 1; for (Iterator<ArchiveInfo> it = archives.iterator(); it.hasNext(); ) { boolean keep = false; ArchiveInfo ai = it.next(); Archive a = ai.getNewArchive(); if (a != null) { Package p = a.getParentPackage(); if (p != null) { if (userFilteredInstallIds.contains(p.installId()) || userFilteredClasses.contains(p.getClass()) || userFilteredIndices.get(index) > 0) { keep = true; } index++; } } if (!keep) { it.remove(); } } if (archives.size() == 0) { mSdkLog.info( LineUtil.reflowLine( "Warning: The package filter removed all packages. There is nothing to install.\nPlease consider trying to update again without a package filter.\n")); return null; } } if (archives != null && archives.size() > 0) { if (dryMode) { mSdkLog.info("Packages selected for install:\n"); for (ArchiveInfo ai : archives) { Archive a = ai.getNewArchive(); if (a != null) { Package p = a.getParentPackage(); if (p != null) { mSdkLog.info("- %1$s\n", p.getShortDescription()); } } } mSdkLog.info("\nDry mode is on so nothing is actually being installed.\n"); } else { return installArchives(archives, NO_TOOLS_MSG); } } else { mSdkLog.info("There is nothing to install or update.\n"); } return null; }
/** * Validates that all archive licenses are accepted. * * <p>There are 2 cases: <br> * - When {@code acceptLicenses} is given, the licenses specified are automatically accepted and * all those not specified are automatically rejected. <br> * - When {@code acceptLicenses} is empty or null, licenses are collected and there's an input * prompt on StdOut to ask a yes/no question. To output, this uses the current {@link #mSdkLog} * which should be configured to send {@link ILogger#info(String, Object...)} directly to {@link * System#out}. <br> * Finally only accepted licenses are kept in the archive list. * * @param archives The archives to validate. * @param acceptLicenseIds A comma-separated list of licenses ids already approved. * @param numRetries The number of times the command-line will ask to accept a given license when * the input doesn't match the expected y/n/yes/no answer. Use 0 for infinite. Useful for * unit-tests. Once the number of retries is reached, the license is assumed as rejected. * @return True if there are any archives left to install. */ @VisibleForTesting(visibility = Visibility.PRIVATE) boolean acceptLicense(List<ArchiveInfo> archives, String acceptLicenseIds, final int numRetries) { TreeSet<String> acceptedLids = new TreeSet<String>(); if (acceptLicenseIds != null) { acceptedLids.addAll(Arrays.asList(acceptLicenseIds.split(","))); // $NON-NLS-1$ } boolean automated = !acceptedLids.isEmpty(); TreeSet<String> rejectedLids = new TreeSet<String>(); TreeMap<String, License> lidToAccept = new TreeMap<String, License>(); TreeMap<String, List<String>> lidPkgNames = new TreeMap<String, List<String>>(); // Find the licenses needed. Include those already accepted. for (ArchiveInfo ai : archives) { License lic = getArchiveInfoLicense(ai); if (lic == null) { continue; } String lid = getLicenseId(lic); if (!acceptedLids.contains(lid)) { if (automated) { // Automatically reject those not already accepted rejectedLids.add(lid); } else { // Queue it to ask for it to be accepted lidToAccept.put(lid, lic); List<String> list = lidPkgNames.get(lid); if (list == null) { list = new ArrayList<String>(); lidPkgNames.put(lid, list); } list.add(ai.getShortDescription()); } } } // Ask for each license that needs to be asked manually for confirmation nextEntry: for (Map.Entry<String, License> entry : lidToAccept.entrySet()) { String lid = entry.getKey(); License lic = entry.getValue(); mSdkLog.info("-------------------------------\n"); mSdkLog.info("License id: %1$s\n", lid); mSdkLog.info( "Used by: \n - %1$s\n", Joiner.on("\n - ").skipNulls().join(lidPkgNames.get(lid))); mSdkLog.info("-------------------------------\n\n"); mSdkLog.info("%1$s\n", lic.getLicense()); int retries = numRetries; tryAgain: while (true) { try { mSdkLog.info("Do you accept the license '%1$s' [y/n]: ", lid); byte[] buffer = new byte[256]; if (mSdkLog instanceof IReaderLogger) { ((IReaderLogger) mSdkLog).readLine(buffer); } else { System.in.read(buffer); } mSdkLog.info("\n"); String reply = new String(buffer, Charsets.UTF_8); reply = reply.trim().toLowerCase(Locale.US); if ("y".equals(reply) || "yes".equals(reply)) { acceptedLids.add(lid); continue nextEntry; } else if ("n".equals(reply) || "no".equals(reply)) { break tryAgain; } else { mSdkLog.info("Unknown response '%1$s'.\n", reply); if (--retries == 0) { mSdkLog.info("Max number of retries exceeded. Rejecting '%1$s'\n", lid); break tryAgain; } continue tryAgain; } } catch (IOException e) { // Panic. Don't install anything. e.printStackTrace(); return false; } } rejectedLids.add(lid); } // Finally remove all archive which license is rejected or not accepted. for (Iterator<ArchiveInfo> it = archives.iterator(); it.hasNext(); ) { ArchiveInfo ai = it.next(); License lic = getArchiveInfoLicense(ai); if (lic == null) { continue; } String lid = getLicenseId(lic); if (rejectedLids.contains(lid) || !acceptedLids.contains(lid)) { mSdkLog.info( "Package %1$s not installed due to rejected license '%2$s'.\n", ai.getShortDescription(), lid); it.remove(); } } return !archives.isEmpty(); }