| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- using Invercargill;
- using Invercargill.DataStructures;
- /**
- * `usm update [-y|--yes] [<packages>]` — bring installed packages up to
- * the newest version their repositories offer.
- *
- * Without package names every installed package with a newer repository
- * version becomes a resolution root; with names exactly those packages
- * do (already-current names are skipped with a note). Either way there
- * is one resolution, one {@link Usm.TransactionSummary}, one confirm —
- * and the downloads happen only once the plan is accepted.
- *
- * Dependencies already installed at the resolved version are left alone;
- * an installed package moving to a different version is removed
- * (RemoveType.UPGRADE) and the new version installed in its place. The
- * old version's state directory is kept, which is what makes `usm
- * downgrade` possible.
- */
- private int update_main(string[] args) {
- var assume_yes = false;
- var package_names = new Vector<string>();
- for(int i = 2; i < args.length; i++) {
- var argument = args[i];
- if(argument == "-y" || argument == "--yes") {
- assume_yes = true;
- }
- else if(argument.has_prefix("-")) {
- printerr(@"Unknown option \"$argument\"\n");
- return update_usage();
- }
- else {
- package_names.add(argument);
- }
- }
- var progress = new Usm.Cli.ProgressBar();
- Usm.SystemState state = null;
- try {
- state = new Usm.SystemState(paths);
- }
- catch(Error e) {
- printerr(@"This system is not managed by usm: $(e.message)\n");
- return 245;
- }
- try {
- printerr("Refreshing repositories...\n");
- var resolver = new Usm.Resolver(new Usm.ResourceFinder());
- foreach(var repo in state.get_repositories()) {
- state.refresh_list(repo, (f, c, t) => printerr(@"Refreshing list for $(repo.name): downloading $f $c/$t bytes\r"));
- var listing = state.get_latest_list(repo);
- if(listing != null) {
- resolver.load_listing(repo, listing);
- }
- printerr("\n");
- }
- // Cached packages can satisfy dependencies, including the old
- // versions kept behind by earlier updates
- resolver.load_cache(paths);
- var installed_by_name = new Dictionary<string, Usm.CachedPackage>();
- var installed_versions = new Dictionary<string, Usm.Version>();
- foreach(var installed in state.get_installed_packages()) {
- var manifest = installed.get_manifest();
- Usm.Version seen;
- if(installed_versions.try_get(manifest.name, out seen) && !manifest.version.greater_than(seen)) {
- continue;
- }
- installed_by_name.set(manifest.name, state.resolve_installed(installed));
- installed_versions.set(manifest.name, manifest.version);
- }
- var roots = new Vector<Usm.AbstractPackage>();
- if(package_names.length > 0) {
- foreach(var package_name in package_names) {
- Usm.CachedPackage installed;
- if(!installed_by_name.try_get(package_name, out installed)) {
- printerr(@"No installed package named \"$package_name\"\n");
- return 254;
- }
- var target = resolver.find_package(package_name);
- if(target == null) {
- printerr(@"No package named \"$package_name\" found in any repository or the cache\n");
- return 254;
- }
- Usm.Version installed_version;
- installed_versions.try_get(package_name, out installed_version);
- if(!target.manifest.version.greater_than(installed_version)) {
- print(@"\"$package_name\" is already up to date.\n");
- continue;
- }
- roots.add(target);
- }
- if(roots.length == 0) {
- return 0;
- }
- }
- else {
- foreach(var pair in installed_by_name) {
- var target = resolver.find_package(pair.key);
- if(target != null && target.manifest.version.greater_than(installed_versions[pair.key])) {
- roots.add(target);
- }
- }
- if(roots.length == 0) {
- print("All installed packages are up to date.\n");
- return 0;
- }
- }
- var spm = new Usm.SystemPackageManager(state.config);
- Usm.ResolutionResult resolution;
- try {
- resolution = resolver.resolve(roots, spm);
- }
- catch(Usm.ResolverError e) {
- printerr("%s\n".printf(e.message));
- return 240;
- }
- // Build the transaction set WITHOUT downloading: dependencies
- // already installed at the resolved version stay as-is (so an
- // update plan names only what actually moves), and repository
- // packages join as their cache directories carrying the listing
- // manifest — the plan is confirmed before a single byte moves
- var current_names = new HashSet<string>();
- foreach(var package in resolution.install_order) {
- Usm.Version installed_version;
- if(installed_versions.try_get(package.manifest.name, out installed_version)
- && installed_version.compare(package.manifest.version) == 0) {
- current_names.add(package.manifest.name);
- }
- }
- var cached_packages = new HashSet<Usm.CachedPackage>();
- uint download_count = 0;
- int64 download_bytes = 0;
- var download_sizes_known = true;
- foreach(var package in resolution.install_order) {
- if(current_names.contains(package.manifest.name)) {
- continue;
- }
- if(package.repository == null) {
- if(package.package_path != null) {
- cached_packages.add(new Usm.CachedPackage(Path.get_dirname((!)package.package_path)));
- }
- continue;
- }
- var path = state.generate_cache_path(package.manifest);
- cached_packages.add(new Usm.CachedPackage(path) {
- known_manifest = package.manifest
- });
- if(File.new_for_path(Path.build_filename(path, "package.usmc")).query_exists()) {
- continue;
- }
- download_count++;
- var size = install_package_download_size(package.repository, package.repository_entry);
- if(size == null) {
- download_sizes_known = false;
- }
- else {
- download_bytes += size;
- }
- }
- // The installed versions being replaced by a different version
- var to_remove = new HashSet<Usm.CachedPackage>();
- foreach(var package in resolution.install_order) {
- Usm.CachedPackage installed;
- Usm.Version installed_version;
- if(!installed_by_name.try_get(package.manifest.name, out installed)) {
- continue;
- }
- if(installed_versions.try_get(package.manifest.name, out installed_version)
- && installed_version.compare(package.manifest.version) != 0) {
- to_remove.add(installed);
- }
- }
- var install_order = new Vector<string>();
- foreach(var package in resolution.install_order) {
- install_order.add(package.manifest.name);
- }
- // The exact reverse: dependents are removed before their providers
- var remove_order = new Vector<string>();
- foreach(var package in resolution.removal_order) {
- remove_order.add(package.manifest.name);
- }
- var transaction = new Usm.Transaction() {
- paths = paths,
- resource_finder = new Usm.ResourceFinder(paths),
- to_remove = to_remove,
- to_install = cached_packages,
- install_order = install_order,
- remove_order = remove_order,
- state = state
- };
- // Planning before the prompt populates the rebuildDependants
- // entries so the summary shows the whole transaction
- try {
- transaction.strategise();
- }
- catch(Usm.TransactionError e) {
- printerr(@"$(e.message)\n");
- return 240;
- }
- var summary = new Usm.TransactionSummary() {
- to_install = cached_packages.to_vector(),
- to_remove = to_remove.to_vector(),
- to_rebuild = transaction.rebuilds,
- download_count = download_count,
- download_bytes = download_sizes_known ? download_bytes : -1
- };
- if(!Usm.Cli.confirm_transaction(summary, assume_yes)) {
- print("Aborted.\n");
- return 1;
- }
- // Only now that the plan is confirmed do the packages transfer
- install_download_packages(state, resolution, current_names);
- if(resolution.system_packages.any()) {
- if(!install_system_packages(spm, resolution.system_packages)) {
- return 239;
- }
- }
- printerr("\nRunning transaction...\n");
- transaction.progress_updated.connect(progress.on_transaction_progress);
- transaction.run();
- progress.finish();
- }
- catch(Error e) {
- progress.fail();
- printerr(@"Error: $(e.message)\n");
- return 238;
- }
- return 0;
- }
- private int update_usage() {
- printerr("USAGE:\n\tusm update [-y|--yes] [<packages>]\n");
- return 255;
- }
|