diff options
author | Daniel Hartwig <mandyke@gmail.com> | 2012-06-12 18:19:47 +0800 |
---|---|---|
committer | Daniel Hartwig <mandyke@gmail.com> | 2012-06-20 17:05:39 +0800 |
commit | a88745bf22c3e83e5d78331a69f813e451c895a0 (patch) | |
tree | 008c6aeab03af51d680802401cbf3938980b0425 | |
parent | d082e98fcf8d2809fd89d3bc2c3002f5e2e1f5a3 (diff) | |
download | aptitude-a88745bf22c3e83e5d78331a69f813e451c895a0.tar.gz |
Tidy error handling in main, cmdline actions
Error conditions are much stricter, detecting errors is more
reliable, and the exit status of all command-line actions is
well-defined.
All commands will return one of these values as their exit
status:
0 – success
1 – user aborted (install, remove, …); or
no matches (search, why, why-not);
100 – failure
For commands whose arguments are lists of packages or search
patterns the following general conditions hold:
It is a failure if any package argument does not exactly
name a package.
It is a failure if any versioned argument requests a
version which is not available for every package
identified by that argument. Versioned arguments are
those which end with a version or archive (release)
specifier, respectively “=<version>” and “/<archive>”.
If a command includes a request to install, remove, or
purge any package that command will not proceed if any
of the above failures occur. Other commands may still
proceed in case of such failures but will exit with
non-zero status to indicate they were not completely
effective.
Some commands have exceptions and/or extensions to the
general conditions:
install, upgrade, remove, …:
Where a request specifies a virtual package it is a
failure if it has either no provider or multiple
providers. If there is only one provider that package
will be selected instead of the virtual package.
search:
All arguments are considered patterns. Arguments
without an explicit search term will be wrapped in an
implicit ‘?name’ term.
This is a major change from previous versions where the
program would have proceeded and possibly exited with a
status indicating success (0) despite some requested actions
being either invalid or ineffective. The new, stricter
behaviour is desirable for two reasons:
- to prevent the situation where a request to replace one
set of packages with another set proceeds when (some of)
the replacements are not found or unavailable could cause
the undesired removal of arbitrary other packages;
- to make the program more atomic and reliable when used for
automated tasks – by considering the entire request as
being essential to success another program can rely on an
exit status of 0 to mean that the request was completely
carried out.
Summary of changes:
* Most errors are now displayed at the end of a command's
output which makes them easier to spot when there is
lots of output. (Closes: #430392)
* [cmdline]: Virtual packages which have an already
installed provider are only skipped when the
requested action is to install them.
* [cmdline]: install and similar actions have much
stronger error checking and will exit more
reliably with non-zero status on failures
Failures which result in no action and a
non-zero exit status (100):
- a package argument does not exactly name
an available package;
- a versioned argument requests a version
which is not available for every package
it applies to (Closes: #590686);
* [cmdline]: changelog exits with non-zero status on any
error (Closes: #675833)
* [cmdline]: search exit with status 1 if it found no
matches (Closes: #497299)
* [cmdline]: why exits with status 1 if it found no
reasons given the particular arguments
* [cmdline]: show will exit with status 100 if it found
no packages or a named package was not found
* unknown arguments do not show the usage screen
* more errors are reported using GlobalError
* clean up some strings used as error messages
* download_install_manager.cc:
- repeat if package manager result is DoAgain;
- report all download errors not just the first;
* cmdline_util.cc:
- pkgset_from_string by default is no longer an error if
a pattern matches no packages
* [doc]: add section on exit status to the man page
Closes: #430392
Closes: #497299
Closes: #590686
Closes: #675833
29 files changed, 734 insertions, 592 deletions
@@ -1,6 +1,87 @@ [6/8/2012] Version 0.6.9 "All in a days work" +Error conditions are much stricter, detecting errors is more +reliable, and the exit status of all command-line actions is +well-defined. + +All commands will return one of these values as their exit +status: + + 0 – success + 1 – user aborted (install, remove, …); or + no matches (search, why, why-not); + 100 – failure + +For commands whose arguments are lists of packages or search +patterns the following general conditions hold: + + It is a failure if any package argument does not exactly + name a package. + + It is a failure if any versioned argument requests a + version which is not available for every package + identified by that argument. Versioned arguments are + those which end with a version or archive (release) + specifier, respectively “=<version>” and “/<archive>”. + + If a command includes a request to install, remove, or + purge any package that command will not proceed if any + of the above failures occur. Other commands may still + proceed in case of such failures but will exit with + non-zero status to indicate they were not completely + effective. + +Some commands have exceptions and/or extensions to the +general conditions: + + install, upgrade, remove, …: + + Where a request specifies a virtual package it is a + failure if it has either no provider or multiple + providers. If there is only one provider that package + will be selected instead of the virtual package. + + search: + + All arguments are considered patterns. Arguments + without an explicit search term will be wrapped in an + implicit ‘?name’ term. + +This is a major change from previous versions where the +program would have proceeded and possibly exited with a +status indicating success (0) despite some requested actions +being either invalid or ineffective. The new, stricter +behaviour is desirable for two reasons: + +- to prevent the situation where a request to replace one + set of packages with another set proceeds when (some of) + the replacements are not found or unavailable could cause + the undesired removal of arbitrary other packages; + +- to make the program more atomic and reliable when used for + automated tasks – by considering the entire request as + being essential to success another program can rely on an + exit status of 0 to mean that the request was completely + carried out. + +- Crashes and serious errors: + + * [cmdline]: install and similar actions have much + stronger error checking and will exit more + reliably with non-zero status on failures + + Failures which result in no action and a + non-zero exit status (100): + - a package argument does not exactly name + an available package; + - a versioned argument requests a version + which is not available for every package + it applies to (Closes: #590686); + + * [cmdline]: changelog exits with non-zero status on any + error (Closes: #675833) + - New features: * [cmdline]: Regular expressions are now supported to match names @@ -29,6 +110,16 @@ Version 0.6.9 "All in a days work" no bug reports suggests that noone has noticed they were broken, but they work now anyway + * [cmdline]: Virtual packages which have an already + installed provider are only skipped when the + requested action is to install them. + + * [cmdline]: search exit with status 1 if it found no + matches (Closes: #497299) + + * [cmdline]: why exits with status 1 if it found no + reasons given the particular arguments + - Internal changes: * Unified the way packages are selected from command line @@ -42,11 +133,23 @@ Version 0.6.9 "All in a days work" subtle quirks with our parser (such as "-qq" not being valid when it is fine for other apt programs). + * download_install_manager.cc: + - repeat if package manager result is DoAgain; + - report all download errors not just the first; + - Cosmetic and UI bugs: * [cmdline]: Use arch-qualified names for virtual packages in more places as this is what apt-utils do. + * [cmdline]: Most errors are now displayed at the end of a command's + output which makes them easier to spot when there is + lots of output. (Closes: #430392) + +- Documentation: + + * [doc]: add section on exit status to the man page + [5/11/2012] Version 0.6.8 "Never need a reason, never need a rhyme" diff --git a/doc/en/manpage.xml b/doc/en/manpage.xml index 28eeb68b..8b03d591 100644 --- a/doc/en/manpage.xml +++ b/doc/en/manpage.xml @@ -2338,6 +2338,53 @@ The following packages will be REMOVED: </refsect1> <refsect1> + <title>Exit Status</title> + + <variablelist> + <varlistentry> + <term><literal>0</literal></term> + + <listitem> + <para>Success.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>1</literal></term> + + <listitem> + <para>User aborted or no matches.</para> + + <para> + For most commands this means that the user aborted the + operation before it was completed. + </para> + + <para> + For the <command>search</command>, + <command>versions</command>, <command>why</command>, and + <command>why-not</command> commands this indicates that + no matches were found. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>100</literal></term> + + <listitem> + <para>Failure.</para> + + <para> + There was an error and some or all of the requested + actions could not be performed. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> <title>Environment</title> <variablelist> diff --git a/src/cmdline/cmdline_action.cc b/src/cmdline/cmdline_action.cc index 4a8393cb..9f42e421 100644 --- a/src/cmdline/cmdline_action.cc +++ b/src/cmdline/cmdline_action.cc @@ -220,7 +220,7 @@ namespace bool cmdline_applyaction(cmdline_pkgaction_type action, pkgCache::PkgIterator pkg, - std::set<pkgCache::PkgIterator> &seen_virtual_packages, + pkgset &seen_virtual_packages, pkgset &to_install, pkgset &to_hold, pkgset &to_remove, pkgset &to_purge, int verbose, @@ -232,86 +232,99 @@ bool cmdline_applyaction(cmdline_pkgaction_type action, const shared_ptr<terminal_metrics> &term_metrics) { // Handle virtual packages. - if(!pkg.ProvidesList().end()) + if(!pkg.ProvidesList().end() && pkg.VersionList().end()) { - if(pkg.VersionList().end()) - { - const bool seen_in_first_pass = - seen_virtual_packages.find(pkg) != seen_virtual_packages.end(); + const bool seen_in_first_pass = + seen_virtual_packages.find(pkg) != seen_virtual_packages.end(); - if(!seen_in_first_pass) - { - for(pkgCache::PrvIterator prv=pkg.ProvidesList(); !prv.end(); ++prv) - { - if(prv.OwnerPkg().CurrentVer()==prv.OwnerVer()) - { - if(verbose>0) + if(!seen_in_first_pass) + { + switch(action) + { + case cmdline_install: + case cmdline_installauto: + for(pkgCache::PrvIterator prv=pkg.ProvidesList(); + prv.end() == false; + ++prv) + { + if(prv.OwnerPkg().CurrentVer() == prv.OwnerVer()) + { + if(verbose > 0) printf(_("Note: \"%s\", providing the virtual package\n" " \"%s\", is already installed.\n"), prv.OwnerPkg().FullName(true).c_str(), pkg.FullName(true).c_str()); - return true; - } - else if((*apt_cache_file)[prv.OwnerPkg()].InstVerIter(*apt_cache_file)==prv.OwnerVer()) - { - if(verbose>0) + return true; + } + else if((*apt_cache_file)[prv.OwnerPkg()].InstVerIter(*apt_cache_file)==prv.OwnerVer()) + { + if(verbose > 0) printf(_("Note: \"%s\", providing the virtual package\n" " \"%s\", is already going to be installed.\n"), prv.OwnerPkg().FullName(true).c_str(), pkg.FullName(true).c_str()); - return true; - } - } - } + return true; + } + } + break; + default: + break; + } + } - seen_virtual_packages.insert(pkg); + seen_virtual_packages.insert(pkg); - // See if there's only one possible package to install. - pkgvector cands; + // See if there's only one possible package to install. + pkgvector cands; - for(pkgCache::PrvIterator prv=pkg.ProvidesList(); - !prv.end(); ++prv) - { - if((*apt_cache_file)[prv.OwnerPkg()].CandidateVerIter(*apt_cache_file)==prv.OwnerVer()) - cands.push_back(prv.OwnerPkg()); - } + for(pkgCache::PrvIterator prv=pkg.ProvidesList(); + !prv.end(); ++prv) + { + if((*apt_cache_file)[prv.OwnerPkg()].CandidateVerIter(*apt_cache_file)==prv.OwnerVer()) + cands.push_back(prv.OwnerPkg()); + } - if(cands.size()==0) - { - if(!seen_in_first_pass) - printf(_("\"%s\" exists in the package database, but it is not a\n" - "real package and no package provides it.\n"), - pkg.FullName(true).c_str()); - return false; - } - else if(cands.size()>1) - { - if(!seen_in_first_pass) - { - printf(_("\"%s\" is a virtual package provided by:\n"), - pkg.FullName(true).c_str()); - cmdline_show_pkglist(cands, term_metrics); - printf(_("You must choose one to install.\n")); - } - return false; - } - else if(cands.size()==1) - { - if(!seen_in_first_pass) - { - printf(_("Note: selecting \"%s\" instead of the\n" - "virtual package \"%s\"\n"), - cands[0].FullName(true).c_str(), - pkg.FullName(true).c_str()); - } - pkg = cands[0]; - } - } + if(cands.size()==0) + { + if(!seen_in_first_pass) + printf(_("\"%s\" exists in the package database, but it is not a\n" + "real package and no package provides it.\n"), + pkg.FullName(true).c_str()); + return false; + } + else if(cands.size()>1) + { + if(!seen_in_first_pass) + { + printf(_("\"%s\" is a virtual package provided by:\n"), + pkg.FullName(true).c_str()); + cmdline_show_pkglist(cands, term_metrics); + printf(_("You must choose one to install.\n")); + printf("\n"); + _error->Error(_("Package '%s' has no installation candidate"), + pkg.FullName(true).c_str()); + } + return false; + } + else if(cands.size()==1) + { + if(!seen_in_first_pass) + { + printf(_("Note: selecting \"%s\" instead of the\n" + " virtual package \"%s\"\n"), + cands[0].FullName(true).c_str(), pkg.Name()); + } + pkg = cands[0]; + } } pkgCache::VerIterator ver=pkg.CurrentVer(); if(action==cmdline_install || action == cmdline_installauto) - ver=cmdline_find_ver(pkg, source, sourcestr); + { + ver=cmdline_find_ver(pkg, source, sourcestr); + if(ver.end() == true) + return false; + } pkgDepCache::StateCache &pkg_state((*apt_cache_file)[pkg]); @@ -479,57 +492,32 @@ bool cmdline_applyaction(string s, if(!cmdline_parse_source(s, source, package, sourcestr)) return false; - // Handle task installation. Won't work if tasksel isn't installed. - aptitude::apt::task task; - string arch; - if(cmdline_parse_task(package, task, arch) == true) - { - printf(_("Note: selecting the task \"%s: %s\" for installation\n"), - task.name.c_str(), cw::util::transcode(task.shortdesc).c_str()); - - pkgset pkgset; - aptitude::apt::get_task_packages(&pkgset, task, arch); - for(pkgset::iterator pkg = pkgset.begin(); - pkg != pkgset.end(); - ++pkg) - { - rval = cmdline_applyaction(action, *pkg, - seen_virtual_packages, - to_install, to_hold, to_remove, to_purge, - verbose, source, - sourcestr, - policy, arch_only, - allow_auto, - term_metrics) && rval; - } - - // break out. - return rval; - } - // This is harmless for other commands, but it won't make sense. if(source == cmdline_version_version && action != cmdline_install && action != cmdline_forbid_version && action != cmdline_installauto && action != cmdline_build_depends) - { - printf(_("You can only specify a package version with an 'install' command or a 'forbid-version' command.\n")); - return false; - } + return _error->Error(_("You can only specify a package version with an" + " 'install' command or a 'forbid-version' command")); if(source == cmdline_version_archive && action != cmdline_install && action != cmdline_installauto && action != cmdline_build_depends) - { - printf(_("You can only specify a package archive with an 'install' command.\n")); - return false; - } + return _error->Error(_("You can only specify a package archive with an" + " 'install' command")); pkgset pkgset; - if(aptitude::cmdline::pkgset_from_string(&pkgset, package) == false) + if(aptitude::cmdline::pkgset_from_string(&pkgset, package, + GlobalError::ERROR, + GlobalError::WARNING) == false) { + // pkgset_from_string generates a warning for patterns with no + // matches. + if(is_pattern(package) == true) + return false; + // Assume the user asked for a source package. if(action == cmdline_build_depends) return cmdline_do_build_depends(package, diff --git a/src/cmdline/cmdline_action.h b/src/cmdline/cmdline_action.h index 37510d31..663dd05a 100644 --- a/src/cmdline/cmdline_action.h +++ b/src/cmdline/cmdline_action.h @@ -102,7 +102,7 @@ namespace aptitude */ bool cmdline_applyaction(cmdline_pkgaction_type action, pkgCache::PkgIterator pkg, - std::set<pkgCache::PkgIterator> &seen_virtual_packages, + pkgset &seen_virtual_packages, pkgset &to_install, pkgset &to_hold, pkgset &to_remove, pkgset &to_purge, int verbose, diff --git a/src/cmdline/cmdline_changelog.cc b/src/cmdline/cmdline_changelog.cc index 17c79fca..3c01fc49 100644 --- a/src/cmdline/cmdline_changelog.cc +++ b/src/cmdline/cmdline_changelog.cc @@ -177,7 +177,6 @@ void set_name(temp::name n, temp::name *target) single_download_progress::failure(msg); _error->Error(_("Changelog download failed: %s"), msg.c_str()); - _error->DumpErrors(); out_changelog_file = temp::name(); aptitude::cmdline::exit_main(); @@ -290,17 +289,16 @@ void do_cmdline_changelog(const vector<string> &packages, string default_release = aptcfg->Find("APT::Default-Release"); + _error->PushToStack(); for(vector<string>::const_iterator i=packages.begin(); i!=packages.end(); ++i) { // We need to do this because some code (see above) checks - // PendingError to see whether everything is OK. In addition, - // dumping errors means we get sensible error message output - // (this will be true even if the PendingError check is removed - // ... which it arguably should be). - _error->DumpErrors(); + // PendingError to see whether everything is OK. + _error->MergeWithStack(); + _error->PushToStack(); string input=*i; - cmdline_version_source source; + cmdline_version_source source = cmdline_version_cand; string package, sourcestr; if(!cmdline_parse_source(input, source, package, sourcestr)) @@ -429,7 +427,7 @@ void do_cmdline_changelog(const vector<string> &packages, _error->Error(_("Couldn't run pager %s"), pager); } - _error->DumpErrors(); + _error->MergeWithStack(); } // TODO: fetch them all in one go. @@ -437,16 +435,13 @@ int cmdline_changelog(int argc, char *argv[]) { shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); OpProgress progress; apt_init(&progress, false); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; vector<string> packages; for(int i=1; i<argc; ++i) @@ -454,7 +449,5 @@ int cmdline_changelog(int argc, char *argv[]) do_cmdline_changelog(packages, term); - _error->DumpErrors(); - - return 0; + return _error->PendingError() ? 100 : 0; } diff --git a/src/cmdline/cmdline_changelog.h b/src/cmdline/cmdline_changelog.h index 580b8fb4..2be98d5f 100644 --- a/src/cmdline/cmdline_changelog.h +++ b/src/cmdline/cmdline_changelog.h @@ -40,7 +40,7 @@ namespace aptitude /** \brief Display the changelog of each of the given package specifiers. * * The specifiers are literal package names, with optional version/archive - * descriptors. DumpErrors() is called after each changelog is displayed. + * descriptors. */ void do_cmdline_changelog(const std::vector<std::string> &packages, const boost::shared_ptr<aptitude::cmdline::terminal_metrics> &term_metrics); diff --git a/src/cmdline/cmdline_check_resolver.cc b/src/cmdline/cmdline_check_resolver.cc index cc112c0e..01077801 100644 --- a/src/cmdline/cmdline_check_resolver.cc +++ b/src/cmdline/cmdline_check_resolver.cc @@ -157,17 +157,14 @@ namespace int cmdline_check_resolver(int argc, char *argv[], const char *status_fname) { - _error->DumpErrors(); + consume_errors(); OpProgress progress; apt_init(&progress, true, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; aptitude_universe u(*apt_cache_file); diff --git a/src/cmdline/cmdline_clean.cc b/src/cmdline/cmdline_clean.cc index 3a9670f7..7037b560 100644 --- a/src/cmdline/cmdline_clean.cc +++ b/src/cmdline/cmdline_clean.cc @@ -53,12 +53,12 @@ int cmdline_clean(int argc, char *argv[], bool simulate) { const string archivedir = aptcfg->FindDir("Dir::Cache::archives"); - _error->DumpErrors(); + consume_errors(); if(argc != 1) { - fprintf(stderr, _("E: The clean command takes no arguments\n")); - return -1; + _error->Error(_("The clean command takes no arguments")); + return 100; } if(simulate) @@ -77,20 +77,13 @@ int cmdline_clean(int argc, char *argv[], bool simulate) } if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; pkgAcquire fetcher; fetcher.Clean(archivedir); fetcher.Clean(archivedir+"partial/"); - int rval=_error->PendingError() ? -1 : 0; - - _error->DumpErrors(); - - return rval; + return _error->PendingError() ? 100 : 0; } // Shamelessly stolen from apt-get: @@ -127,12 +120,12 @@ int cmdline_autoclean(int argc, char *argv[], bool simulate) const string archivedir = aptcfg->FindDir("Dir::Cache::archives"); const shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); if(argc != 1) { - fprintf(stderr, _("E: The autoclean command takes no arguments\n")); - return -1; + _error->Error(_("The autoclean command takes no arguments")); + return 100; } // Lock the archive directory @@ -144,8 +137,7 @@ int cmdline_autoclean(int argc, char *argv[], bool simulate) if (_error->PendingError() == true) { _error->Error(_("Unable to lock the download directory")); - _error->DumpErrors(); - return -1; + return 100; } } @@ -154,19 +146,14 @@ int cmdline_autoclean(int argc, char *argv[], bool simulate) apt_init(progress.get(), false); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; LogCleaner cleaner(simulate); int rval=0; if(!(cleaner.Go(archivedir, *apt_cache_file) && cleaner.Go(archivedir+"partial/", *apt_cache_file)) || _error->PendingError()) - rval=-1; - - _error->DumpErrors(); + rval = 100; if(simulate) printf(_("Would free %sB of disk space\n"), @@ -177,4 +164,3 @@ int cmdline_autoclean(int argc, char *argv[], bool simulate) return rval; } - diff --git a/src/cmdline/cmdline_do_action.cc b/src/cmdline/cmdline_do_action.cc index 8d088379..36ded861 100644 --- a/src/cmdline/cmdline_do_action.cc +++ b/src/cmdline/cmdline_do_action.cc @@ -1,6 +1,7 @@ // cmdline_do_action.cc // // Copyright (C) 2004, 2010 Daniel Burrows +// Copyright (C) 2012 Daniel Hartwig // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -101,7 +102,7 @@ int cmdline_do_action(int argc, char *argv[], { shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); cmdline_pkgaction_type default_action=cmdline_install; @@ -157,8 +158,7 @@ int cmdline_do_action(int argc, char *argv[], { // Should never happen. _error->Error(_("Invalid operation %s"), argv[0]); - _error->DumpErrors(); - return -1; + return 100; } if(resolver_mode == resolver_mode_default) @@ -178,10 +178,7 @@ int cmdline_do_action(int argc, char *argv[], upgrade_mode == no_upgrade), status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; // In case we aren't root. if(!simulate) @@ -190,10 +187,7 @@ int cmdline_do_action(int argc, char *argv[], apt_cache_file->ReleaseLock(); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; pkgPolicy policy(&(*apt_cache_file)->GetCache()); ReadPinFile(policy); @@ -230,8 +224,8 @@ int cmdline_do_action(int argc, char *argv[], { if(argc != 1) { - cerr << _("Unexpected pattern argument following \"keep-all\"") << endl; - return -1; + _error->Error(_("Unexpected pattern argument following \"keep-all\"")); + return 100; } for(pkgCache::PkgIterator i=(*apt_cache_file)->PkgBegin(); @@ -334,6 +328,9 @@ int cmdline_do_action(int argc, char *argv[], } } + if(_error->PendingError() == true) + return 100; + if(resolver_mode == resolver_mode_safe) { if(!aptitude::cmdline::safe_resolve_deps(verbose, @@ -342,8 +339,9 @@ int cmdline_do_action(int argc, char *argv[], safe_resolver_show_actions, term)) { - fprintf(stderr, _("Unable to safely resolve dependencies, try running with --full-resolver.\n")); - return -1; + _error->Error(_("Unable to safely resolve dependencies, try" + " running with --full-resolver")); + return 100; } } @@ -366,10 +364,7 @@ int cmdline_do_action(int argc, char *argv[], aptitude::cmdline::apply_user_tags(user_tags); if(!(*apt_cache_file)->save_selection_list(*progress)) - { - _error->DumpErrors(); - return -1; - } + return 100; else return 0; } @@ -391,14 +386,18 @@ int cmdline_do_action(int argc, char *argv[], download_install_manager m(download_only, sigc::ptr_fun(&run_dpkg_directly)); + // FIXME: Temporary work-around for bug #677175 in apt. + const size_t prev_err_stack_count = _error->StackCount(); + int rval = (cmdline_do_download(&m, verbose, term, term, term, term) - == download_manager::success ? 0 : -1); + == download_manager::success ? 0 : 100); - if(_error->PendingError()) - rval = -1; + while(_error->StackCount() > prev_err_stack_count) + _error->MergeWithStack(); - _error->DumpErrors(); + if(_error->PendingError()) + rval = 100; return rval; } diff --git a/src/cmdline/cmdline_download.cc b/src/cmdline/cmdline_download.cc index e3ccb80c..8eede4d6 100644 --- a/src/cmdline/cmdline_download.cc +++ b/src/cmdline/cmdline_download.cc @@ -42,28 +42,23 @@ int cmdline_download(int argc, char *argv[]) if(argc<=1) { - printf(_("download: you must specify at least one package to download\n")); - return -1; + _error->Error(_("download: you must specify at least one package to download")); + return 100; } - _error->DumpErrors(); + consume_errors(); shared_ptr<OpProgress> progress = make_text_progress(false, term, term, term); apt_init(progress.get(), false); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; pkgSourceList list; if(!list.ReadMainList()) { _error->Error(_("Couldn't read source list")); - - _error->DumpErrors(); - return -1; + return 100; } std::pair<download_signal_log *, boost::shared_ptr<acquire_download_progress> > @@ -76,7 +71,7 @@ int cmdline_download(int argc, char *argv[]) for(int i=1; i<argc; ++i) { - cmdline_version_source source; + cmdline_version_source source = cmdline_version_cand; string name, sourcestr; if(!cmdline_parse_source(argv[i], source, name, sourcestr)) continue; @@ -103,7 +98,8 @@ int cmdline_download(int argc, char *argv[]) continue; if(!ver.Downloadable()) - _error->Error(_("No downloadable files for %s version %s; perhaps it is a local or obsolete package?"), + _error->Error(_("No downloadable files for %s version %s;" + " perhaps it is a local or obsolete package?"), name.c_str(), ver.VerStr()); get_archive(&fetcher, &list, apt_package_records, @@ -113,10 +109,7 @@ int cmdline_download(int argc, char *argv[]) if(fetcher.Run()!=pkgAcquire::Continue) // We failed or were cancelled - { - _error->DumpErrors(); - return -1; - } + return 100; return 0; } diff --git a/src/cmdline/cmdline_dump_resolver.cc b/src/cmdline/cmdline_dump_resolver.cc index 44f0e2b1..0c4e66ae 100644 --- a/src/cmdline/cmdline_dump_resolver.cc +++ b/src/cmdline/cmdline_dump_resolver.cc @@ -31,17 +31,14 @@ using namespace std; int cmdline_dump_resolver(int argc, char *argv[], const char *status_fname) { - _error->DumpErrors(); + consume_errors(); OpProgress progress; apt_init(&progress, true, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; aptitude_universe u(*apt_cache_file); diff --git a/src/cmdline/cmdline_extract_cache_subset.cc b/src/cmdline/cmdline_extract_cache_subset.cc index e4620534..dde531a8 100644 --- a/src/cmdline/cmdline_extract_cache_subset.cc +++ b/src/cmdline/cmdline_extract_cache_subset.cc @@ -54,8 +54,9 @@ namespace aptitude { if(argc < 2) { - fprintf(stderr, _("extract-cache-entries: at least one argument is required (the directory\nto which to write files).\n")); - return -1; + _error->Error(_("extract-cache-entries: at least one argument is" + " required (the directory\nto which to write files)")); + return 100; } const shared_ptr<terminal_io> term = create_terminal(); @@ -66,12 +67,8 @@ namespace aptitude apt_init(progress.get(), true); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; - bool ok = true; pkgset packages; if(argc == 2) { @@ -82,22 +79,22 @@ namespace aptitude else { for(int i = 2; i < argc; ++i) - ok &= pkgset_from_string(&packages, argv[i]); + pkgset_from_string(&packages, argv[i]); } - if(!ok) + if(_error->PendingError() == true) + return 100; + + if(packages.size() == 0) { - _error->DumpErrors(); - return 2; + printf(_("No packages were selected by the given search pattern;" + " nothing to do.\n")); + return 0; } aptitude::apt::make_truncated_state_copy(out_dir, packages); - bool copy_ok = !_error->PendingError(); - - _error->DumpErrors(); - - return copy_ok ? 0 : 1; + return _error->PendingError() == true ? 100 : 0; } } } diff --git a/src/cmdline/cmdline_forget_new.cc b/src/cmdline/cmdline_forget_new.cc index e1485f52..4d3aadb4 100644 --- a/src/cmdline/cmdline_forget_new.cc +++ b/src/cmdline/cmdline_forget_new.cc @@ -47,14 +47,14 @@ int cmdline_forget_new(int argc, char *argv[], { const shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); // NB: perhaps we should allow forgetting the new state of just // a few packages? if(argc != 1) { - fprintf(stderr, _("E: The forget-new command takes no arguments\n")); - return -1; + _error->Error(_("The forget-new command takes no arguments")); + return 100; } shared_ptr<OpProgress> progress = make_text_progress(false, term, term, term); @@ -62,10 +62,7 @@ int cmdline_forget_new(int argc, char *argv[], apt_init(progress.get(), false, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; // In case we aren't root. if(!simulate) @@ -74,10 +71,7 @@ int cmdline_forget_new(int argc, char *argv[], apt_cache_file->ReleaseLock(); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; if(simulate) printf(_("Would forget what packages are new\n")); @@ -88,11 +82,7 @@ int cmdline_forget_new(int argc, char *argv[], (*apt_cache_file)->save_selection_list(*progress); if(_error->PendingError()) - { - _error->DumpErrors(); - - return -1; - } + return 100; } return 0; diff --git a/src/cmdline/cmdline_prompt.cc b/src/cmdline/cmdline_prompt.cc index 25fadaa7..150c98fb 100644 --- a/src/cmdline/cmdline_prompt.cc +++ b/src/cmdline/cmdline_prompt.cc @@ -475,7 +475,10 @@ static bool prompt_essential(const shared_ptr<terminal_metrics> &term_metrics) if(!ok) { - printf(_("WARNING: Performing this action will probably cause your system to break!\n Do NOT continue unless you know EXACTLY what you are doing!\n")); + printf(_("WARNING: Performing this action will probably cause your" + " system to break!\n" + " Do NOT continue unless you know EXACTLY what you" + " are doing!\n")); string untranslated_prompt = N_("I am aware that this is a very bad idea"); string prompt = _(untranslated_prompt.c_str()); @@ -739,8 +742,8 @@ bool cmdline_show_preview(bool as_upgrade, pkgset &to_install, printf(_("Need to get %sB of archives. "), SizeToStr(f.DebBytes).c_str()); } - else - _error->DumpErrors(); + // else + // _error->DumpErrors(); if((*apt_cache_file)->UsrSize() >=0) printf(_("After unpacking %sB will be used.\n"), diff --git a/src/cmdline/cmdline_resolver.cc b/src/cmdline/cmdline_resolver.cc index d4f1ff14..22b97aac 100644 --- a/src/cmdline/cmdline_resolver.cc +++ b/src/cmdline/cmdline_resolver.cc @@ -887,7 +887,7 @@ cmdline_resolve_deps(pkgset &to_install, aptitude_solution sol = calculate_current_solution(true, term_metrics); if(_error->PendingError()) - _error->DumpErrors(); + _error->DumpErrors(); if(sol != lastsol || redisplay) { @@ -1111,7 +1111,8 @@ cmdline_resolve_deps(pkgset &to_install, } catch(cwidget::util::Exception &e) { - cout << _("*** ERROR: search aborted by fatal exception. You may continue\n searching, but some solutions will be unreachable.") + cout << _("*** ERROR: search aborted by fatal exception. You may continue\n" + " searching, but some solutions will be unreachable.") << endl << endl << e.errmsg(); diff --git a/src/cmdline/cmdline_search.cc b/src/cmdline/cmdline_search.cc index cae90e9f..0d670cdb 100644 --- a/src/cmdline/cmdline_search.cc +++ b/src/cmdline/cmdline_search.cc @@ -126,8 +126,6 @@ namespace search_progress_display->done(); - _error->DumpErrors(); - std::sort(output.begin(), output.end(), aptitude::cmdline::package_results_lt(sort_policy)); output.erase(std::unique(output.begin(), output.end(), @@ -154,7 +152,7 @@ namespace delete p; } - return 0; + return output.empty() ? 1 : 0; } } @@ -171,13 +169,10 @@ int cmdline_search(int argc, char *argv[], const char *status_fname, pkg_sortpolicy *s=parse_sortpolicy(sort); - if(!s) - { - _error->DumpErrors(); - return -1; - } + if(s == NULL) + return 100; - _error->DumpErrors(); + consume_errors(); const unsigned int screen_width = term->get_screen_width(); if(!width.empty()) @@ -191,9 +186,8 @@ int cmdline_search(int argc, char *argv[], const char *status_fname, if(!cw::util::transcode(display_format.c_str(), wdisplay_format)) { - _error->DumpErrors(); - fprintf(stderr, _("iconv of %s failed.\n"), display_format.c_str()); - return -1; + _error->Error(_("iconv of %s failed"), display_format.c_str()); + return 100; } boost::scoped_ptr<column_definition_list> columns; @@ -202,15 +196,12 @@ int cmdline_search(int argc, char *argv[], const char *status_fname, pkg_item::pkg_columnizer::defaults)); if(columns.get() == NULL) - { - _error->DumpErrors(); - return -1; - } + return 100; if(argc<=1) { - fprintf(stderr, _("search: You must provide at least one search term\n")); - return -1; + _error->Error(_("search: You must provide at least one search term")); + return 100; } shared_ptr<OpProgress> progress = @@ -219,10 +210,7 @@ int cmdline_search(int argc, char *argv[], const char *status_fname, apt_init(progress.get(), true, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; vector<ref_ptr<pattern> > matchers; @@ -232,11 +220,7 @@ int cmdline_search(int argc, char *argv[], const char *status_fname, ref_ptr<pattern> m = parse(arg); if(!m.valid()) - { - _error->DumpErrors(); - - return -1; - } + return 100; matchers.push_back(m); } diff --git a/src/cmdline/cmdline_show.cc b/src/cmdline/cmdline_show.cc index 279da823..018c07c7 100644 --- a/src/cmdline/cmdline_show.cc +++ b/src/cmdline/cmdline_show.cc @@ -527,13 +527,20 @@ bool do_cmdline_show_target(const pkgCache::PkgIterator &pkg, bool has_explicit_source, const shared_ptr<terminal_metrics> &term_metrics) { - if(verbose == 0 || has_explicit_source) + if(has_explicit_source == true) { - // HACK: default to current-or-candidate behavior. This should be - // done in a more up-front way :-(. - if(source == cmdline_version_cand) - source = cmdline_version_curr_or_cand; + pkgCache::VerIterator ver = cmdline_find_ver(pkg, source, sourcestr, + GlobalError::NOTICE); + if(ver.end() == true) + return false; + + show_version(ver, verbose, term_metrics); + } + else if(verbose == 0) + { + _error->PushToStack(); pkgCache::VerIterator ver = cmdline_find_ver(pkg, source, sourcestr); + _error->RevertToStack(); if(ver.end()) ver = pkg.VersionList(); @@ -554,7 +561,7 @@ bool do_cmdline_show_target(const pkgCache::PkgIterator &pkg, bool do_cmdline_show(string s, int verbose, const shared_ptr<terminal_metrics> &term_metrics) { - cmdline_version_source source; + cmdline_version_source source = cmdline_version_curr_or_cand; string name, sourcestr; string default_release = aptcfg->Find("APT::Default-Release"); bool has_explicit_source = false; @@ -593,23 +600,23 @@ int cmdline_show(int argc, char *argv[], int verbose) { shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); shared_ptr<OpProgress> progress = make_text_progress(true, term, term, term); apt_init(progress.get(), false); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; + bool found_any = false; for(int i=1; i<argc; ++i) - do_cmdline_show(argv[i], verbose, term); - - int rval = _error->PendingError() == true ? -1 : 0; + found_any |= do_cmdline_show(argv[i], verbose, term); - _error->DumpErrors(GlobalError::DEBUG); + if(!found_any) + { + _error->Error(_("No packages found")); + return 100; + } - return rval; + return _error->PendingError() ? 100 : 0; } diff --git a/src/cmdline/cmdline_simulate.cc b/src/cmdline/cmdline_simulate.cc index e63bd632..445e85ae 100644 --- a/src/cmdline/cmdline_simulate.cc +++ b/src/cmdline/cmdline_simulate.cc @@ -71,11 +71,11 @@ int cmdline_simulate(bool as_upgrade, pkgPackageManager::OrderResult Res=PM.DoInstall(); if(Res==pkgPackageManager::Failed) - return -1; + return 100; else if(Res!=pkgPackageManager::Completed) { _error->Error(_("Internal Error, Ordering didn't finish")); - return -1; + return 100; } else return 0; diff --git a/src/cmdline/cmdline_update.cc b/src/cmdline/cmdline_update.cc index e5035e38..119f6647 100644 --- a/src/cmdline/cmdline_update.cc +++ b/src/cmdline/cmdline_update.cc @@ -48,29 +48,27 @@ int cmdline_update(int argc, char *argv[], int verbose) { shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); if(argc!=1) { - fprintf(stderr, _("E: The update command takes no arguments\n")); - return -1; + _error->Error(_("The update command takes no arguments")); + return 100; } // Don't exit if there's an error: it probably means that there // was a problem loading the package lists, so go ahead and try to // download new ones. - _error->DumpErrors(); + consume_errors(); download_update_manager m; m.pre_autoclean_hook.connect(sigc::ptr_fun(print_autoclean_msg)); int rval = (cmdline_do_download(&m, verbose, term, term, term, term) - == download_manager::success ? 0 : -1); + == download_manager::success ? 0 : 100); if(_error->PendingError()) - rval = -1; - - _error->DumpErrors(); + rval = 100; return rval; } diff --git a/src/cmdline/cmdline_user_tag.cc b/src/cmdline/cmdline_user_tag.cc index ca61d783..3474cd9a 100644 --- a/src/cmdline/cmdline_user_tag.cc +++ b/src/cmdline/cmdline_user_tag.cc @@ -93,58 +93,50 @@ namespace aptitude action = action_remove; else { - fprintf(stderr, "Internal error: cmdline_user_tag encountered an unknown command name \"%s\"\n", - argv[0]); - return -1; + _error->Error("Internal error: cmdline_user_tag encountered an" + " unknown command name \"%s\"\n", + argv[0]); + return 100; } if(argc < 3) { - fprintf(stderr, - _("%s: too few arguments; expected at least a tag name and a package.\n"), - argv[0]); - return -1; + _error->Error(_("%s: too few arguments; expected at least a tag" + " name and a package.\n"), + argv[0]); + return 100; } - _error->DumpErrors(); + consume_errors(); OpProgress progress; apt_init(&progress, true); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; std::string tag(argv[1]); - bool all_ok = true; + pkgset pkgset; for(int i = 2; i < argc; ++i) - { - pkgset packages; - if(pkgset_from_string(&packages, argv[i]) == false) - all_ok = false; - else - { - for(pkgset::const_iterator it = packages.begin(); - it != packages.end(); - ++it) - do_user_tag(action, tag, *it, verbose); - } - } + pkgset_from_string(&pkgset, argv[i]); + + if(pkgset.empty() == true) + { + _error->Error(_("No packages found")); + return 100; + } - if(all_ok == false) - _error->DumpErrors(); + for(pkgset::const_iterator it = pkgset.begin(); + it != pkgset.end(); + ++it) + do_user_tag(action, tag, *it, verbose); shared_ptr<OpProgress> text_progress = make_text_progress(false, term, term, term); if(!(*apt_cache_file)->save_selection_list(*text_progress)) - return 1; - - if(!all_ok) - return 2; + return 100; - return 0; + return _error->PendingError() == true ? 100 : 0; } } } diff --git a/src/cmdline/cmdline_util.cc b/src/cmdline/cmdline_util.cc index d7b1dcb4..9fc39b55 100644 --- a/src/cmdline/cmdline_util.cc +++ b/src/cmdline/cmdline_util.cc @@ -39,6 +39,7 @@ #include <generic/apt/matching/match.h> #include <generic/apt/matching/parse.h> #include <generic/apt/matching/pattern.h> +#include <generic/apt/matching/serialize.h> #include <generic/apt/tasks.h> // System includes: @@ -71,15 +72,16 @@ using boost::shared_ptr; namespace { - const int no_install_run_from_ui_preview_return = -1; - const int ui_preview_install_failed_return = -1; + const int no_install_run_from_ui_preview_return = 1; + const int ui_preview_install_failed_return = 100; // Completion routine for the UI preview; causes the program to - // return 0 if the install succeded and 1 otherwise. + // return 0 if the install succeded, 1 if the user cancelled, + // and 100 otherwise. // // There's a question in my mind of what to do if the user cancels // the preview or runs multiple previews. At the moment we return - // -1 if the preview is cancelled and the result of the last install + // 1 if the preview is cancelled and the result of the last install // run otherwise. void ui_preview_complete(bool success, int *result) { @@ -150,7 +152,8 @@ void cmdline_show_pkglist(pkgvector &items, pkgCache::VerIterator cmdline_find_ver(pkgCache::PkgIterator pkg, cmdline_version_source source, - string sourcestr) + string sourcestr, + GlobalError::MsgType error_type) { switch(source) { @@ -165,9 +168,13 @@ pkgCache::VerIterator cmdline_find_ver(pkgCache::PkgIterator pkg, if(candver.end()) { if(source == cmdline_version_cand) - printf(_("No candidate version found for %s\n"), pkg.FullName(true).c_str()); + _error->Insert(error_type, + _("No candidate version found for %s"), + pkg.FullName(true).c_str()); else - printf(_("No current or candidate version found for %s\n"), pkg.FullName(true).c_str()); + _error->Insert(error_type, + _("No current or candidate version found for %s"), + pkg.FullName(true).c_str()); } return candver; @@ -191,9 +198,10 @@ pkgCache::VerIterator cmdline_find_ver(pkgCache::PkgIterator pkg, return ver; } - printf(_("Unable to find an archive \"%s\" for the package \"%s\"\n"), - sourcestr.c_str(), - pkg.FullName(true).c_str()); + _error->Insert(error_type, + _("Unable to find an archive \"%s\" for the package \"%s\""), + sourcestr.c_str(), + pkg.FullName(true).c_str()); return pkgCache::VerIterator(*apt_cache_file, 0); case cmdline_version_version: @@ -201,14 +209,15 @@ pkgCache::VerIterator cmdline_find_ver(pkgCache::PkgIterator pkg, if(sourcestr==ver.VerStr()) return ver; - printf(_("Unable to find a version \"%s\" for the package \"%s\"\n"), - sourcestr.c_str(), - pkg.FullName(true).c_str()); + _error->Insert(error_type, + _("Unable to find a version \"%s\" for the package \"%s\""), + sourcestr.c_str(), + pkg.FullName(true).c_str()); return pkgCache::VerIterator(*apt_cache_file, 0); default: - printf(_("Internal error: invalid value %i passed to cmdline_find_ver!\n"), - source); + _error->Error(_("Internal error: invalid value %i passed to cmdline_find_ver!"), + source); return pkg.VersionList(); } } @@ -220,7 +229,7 @@ bool cmdline_parse_source(const string &input, { string scratch=input; - source=cmdline_version_cand; + // source=cmdline_version_cand; sourcestr=""; if(scratch.find('/')!=scratch.npos) @@ -236,10 +245,8 @@ bool cmdline_parse_source(const string &input, if(scratch.find('=')!=scratch.npos) { if(source==cmdline_version_archive) - { - printf(_("You cannot specify both an archive and a version for a package\n")); - return false; - } + return _error->Error(_("You cannot specify both an archive and a" + " version for a package")); source=cmdline_version_version; string::size_type loc=scratch.rfind('='); @@ -253,30 +260,6 @@ bool cmdline_parse_source(const string &input, return true; } -bool cmdline_parse_task(string pattern, - aptitude::apt::task &task, - string &arch) -{ - const string::size_type archfound = pattern.find_last_of(':'); - arch = "native"; - if(archfound != string::npos) - { - arch = pattern.substr(archfound+1); - pattern.erase(archfound); - } - - if(pattern[pattern.length() - 1] != '^') - return false; - pattern.erase(pattern.length() - 1); - - const aptitude::apt::task *t = aptitude::apt::find_task(pattern); - if(t == NULL) - return _error->Error(_("Couldn't find task '%s'"), pattern.c_str()); - - task = *t; - return true; -} - namespace { /** \brief Used to display some statistics about how the cache @@ -465,7 +448,7 @@ download_manager::result cmdline_do_download(download_manager *m, // otherwise. OpProgress tmpProgress; // Dump errors so we don't spuriously think we failed. - _error->DumpErrors(); + consume_errors(); apt_load_cache(&tmpProgress, false, NULL); initial_stats = compute_apt_stats(); } @@ -480,7 +463,7 @@ download_manager::result cmdline_do_download(download_manager *m, // Dump errors here because prepare() might check for pending errors // and think something failed. - _error->DumpErrors(); + consume_errors(); if(!m->prepare(*progress, *log.get(), log.get())) return download_manager::failure; @@ -584,38 +567,53 @@ namespace aptitude if(apt_source_list == NULL) return NULL; + source_package rval = source_package(); + bool done = false; + + _error->PushToStack(); for(pkgSourceList::const_iterator i = apt_source_list->begin(); - i != apt_source_list->end(); ++i) + done != true && i != apt_source_list->end(); + ++i) { if((*i)->GetDist() != archive) continue; vector<pkgIndexFile *> *indexes = (*i)->GetIndexFiles(); - for(vector<pkgIndexFile *>::const_iterator j = indexes->begin(); - j != indexes->end(); ++j) + for(vector<pkgIndexFile *>::const_iterator j = indexes->begin(); + done != true && j != indexes->end(); + ++j) { std::auto_ptr<pkgSrcRecords::Parser> p((*j)->CreateSrcParser()); if(_error->PendingError()) - return source_package(); - if(p.get() != 0) + done = true; + else if(p.get() != 0) { // Step through the file until we reach the end or find // the package: while(p.get()->Step() == true) { if(_error->PendingError() == true) - return source_package(); + { + done = true; + break; + } if(p.get()->Package() == source_name) - return source_package(p.get()); + { + rval = source_package(p.get()); + done = true; + break; + } } } } } - return source_package(); + _error->RevertToStack(); + + return rval; } source_package find_source_package(const std::string &package, @@ -652,7 +650,6 @@ namespace aptitude // version. case cmdline_version_archive: - _error->DumpErrors(); rval = find_source_by_archive(source_package_name, version_source_string); break; @@ -670,7 +667,8 @@ namespace aptitude { pkgCache::VerIterator ver = cmdline_find_ver(pkg, version_source, - version_source_string); + version_source_string, + GlobalError::NOTICE); if(!ver.end()) { @@ -719,7 +717,6 @@ namespace aptitude break; // We would have tried already if it was possible. case cmdline_version_archive: - _error->DumpErrors(); rval = find_source_by_archive(source_package_name, version_source_string); break; @@ -868,52 +865,129 @@ namespace aptitude return pkg; } - bool pkgset_from_pattern(pkgset *packages, const string &pattern, - GlobalError::MsgType error_type) + bool pkgset_from_task(pkgset * const pkgset, string pattern, + GlobalError::MsgType error_type) { - using aptitude::matching::pkg_results_list; - using aptitude::matching::search_cache; - using cwidget::util::ref_ptr; + const string::size_type archfound = pattern.find_last_of(':'); + string arch = "native"; + if(archfound != string::npos) + { + arch = pattern.substr(archfound+1); + pattern.erase(archfound); + } - if(aptitude::matching::is_pattern(pattern) == false) + if(pattern[pattern.length() - 1] != '^') return false; + pattern.erase(pattern.length() - 1); - ref_ptr<aptitude::matching::pattern> p(aptitude::matching::parse(pattern)); - if(p.valid() == false) + const aptitude::apt::task *t = aptitude::apt::find_task(pattern); + if(t == NULL) return _error->Insert(error_type, - _("Unable to parse pattern '%s'"), pattern.c_str()); + _("Couldn't find task '%s'"), pattern.c_str()); + + printf(_("Note: selecting the task \"%s: %s\" for installation\n"), + t->name.c_str(), cw::util::transcode(t->shortdesc).c_str()); + + aptitude::apt::get_task_packages(pkgset, *t, arch); + return true; + } - pkg_results_list matches; - ref_ptr<search_cache> search_info(search_cache::create()); - search(p, search_info, - matches, - *apt_cache_file, - *apt_package_records); + bool pkgset_from_pattern(pkgset * const pkgset, + cw::util::ref_ptr<aptitude::matching::pattern> pattern, + string pattern_str, + GlobalError::MsgType error_type) + { + namespace m = aptitude::matching; + + m::pkg_results_list matches; + cw::util::ref_ptr<m::search_cache> search_info(m::search_cache::create()); + m::search(pattern, + search_info, + matches, + *apt_cache_file, + *apt_package_records); if(matches.empty() == true) - return _error->Insert(error_type, - _("Couldn't find any package for pattern '%s'"), - pattern.c_str()); + { + if(pattern_str.empty() == true) + pattern_str = m::serialize_pattern(pattern); + return _error->Insert(error_type, + _("Couldn't find any package for pattern '%s'"), + pattern_str.c_str()); + } - for(pkg_results_list::const_iterator it = matches.begin(); + for(m::pkg_results_list::const_iterator it = matches.begin(); it != matches.end(); ++it) + pkgset->insert(it->first); + + return true; + } + + bool pkgset_from_regex(pkgset * const pkgset, string pattern, + GlobalError::MsgType error_type) + { + namespace m = aptitude::matching; + using cw::util::ref_ptr; + + static const char * const isregex = ".?+|[^$"; + if(pattern.find_first_of(isregex) == std::string::npos) + return false; + + std::string regex = pattern; + size_t archfound = regex.find_last_of(':'); + std::string arch = "native"; + if(archfound != std::string::npos) { - packages->insert(it->first); + arch = regex.substr(archfound+1); + if(arch.find_first_of(isregex) == std::string::npos) + regex.erase(archfound); + else + archfound = std::string::npos; } - return true; + + ref_ptr<m::pattern> p = m::pattern::make_name(regex); + if(p.valid() == false) + return false; + if(archfound != std::string::npos) + p = m::pattern::make_and(p, m::pattern::make_architecture(arch)); + + return pkgset_from_pattern(pkgset, p, pattern, error_type); + } + + bool pkgset_from_pattern(pkgset * const pkgset, string pattern, + GlobalError::MsgType error_type) + { + namespace m = aptitude::matching; + using cwidget::util::ref_ptr; + + if(m::is_pattern(pattern) == false) + return false; + + ref_ptr<m::pattern> p(m::parse(pattern)); + if(p.valid() == false) + return false; + + return pkgset_from_pattern(pkgset, p, pattern, error_type); } - bool pkgset_from_string(pkgset *packages, const string &str, - GlobalError::MsgType error_type) + bool pkgset_from_string(pkgset * const pkgset, string str, + GlobalError::MsgType error_type, + GlobalError::MsgType pattern_error_type) { bool found = true; _error->PushToStack(); - pkgCache::PkgIterator pkg = pkg_from_name(str, error_type); - if(pkg.end() == false) - packages->insert(pkg); - else if(pkgset_from_pattern(packages, str, error_type) == false) + if(aptitude::matching::is_pattern(str) == false) + { + pkgCache::PkgIterator pkg = pkg_from_name(str, error_type); + if(pkg.end() == false) + pkgset->insert(pkg); + else if(pkgset_from_task(pkgset, str, error_type) == false && + pkgset_from_regex(pkgset, str, error_type) == false) + found = false; + } + else if(pkgset_from_pattern(pkgset, str, pattern_error_type) == false) found = false; if(found == true) diff --git a/src/cmdline/cmdline_util.h b/src/cmdline/cmdline_util.h index 2e10b005..77b18140 100644 --- a/src/cmdline/cmdline_util.h +++ b/src/cmdline/cmdline_util.h @@ -66,7 +66,8 @@ void cmdline_show_stringlist(strvector &items, */ pkgCache::VerIterator cmdline_find_ver(pkgCache::PkgIterator pkg, cmdline_version_source source, - string sourcestr); + string sourcestr, + GlobalError::MsgType error_type = GlobalError::ERROR); /** Starts up the visual UI in preview mode, and exits with status 0 * when the UI shuts down. @@ -95,10 +96,6 @@ bool cmdline_parse_source(const string &input, string &package, string &sourcestr); -bool cmdline_parse_task(std::string pattern, - aptitude::apt::task &task, - std::string &arch); - /** Run the given download and post-download commands using the * standard command-line UI. Runs the preparation routine, the * actual download, and the post-download commands. @@ -444,12 +441,21 @@ namespace aptitude } }; + bool pkgset_from_task(pkgset * const pkgset, string pattern, + GlobalError::MsgType error_type = GlobalError::ERROR); + + /** \brief Fill a pkgset using the given regex to match package + * names. + */ + bool pkgset_from_regex(pkgset * const pkgset, string pattern, + GlobalError::MsgType error_type = GlobalError::ERROR); + /** \brief Fill a pkgset using the given matching pattern. * * This does not try any string as a search pattern, only those * which contain explicit search terms or regex characters. */ - bool pkgset_from_pattern(pkgset *packages, const string &pattern, + bool pkgset_from_pattern(pkgset * const pkgset, string pattern, GlobalError::MsgType error_type = GlobalError::ERROR); /** \brief Fill a pkgset using the given string. If the @@ -461,8 +467,9 @@ namespace aptitude * TODO: Should be replaced with cacheset functions once we have * become more compatible with them. */ - bool pkgset_from_string(pkgset *packages, const string &str, - GlobalError::MsgType error_type = GlobalError::ERROR); + bool pkgset_from_string(pkgset * const pkgset, string str, + GlobalError::MsgType error_type = GlobalError::ERROR, + GlobalError::MsgType pattern_error_type = GlobalError::NOTICE); } } diff --git a/src/cmdline/cmdline_versions.cc b/src/cmdline/cmdline_versions.cc index 57e95d17..ba6df3fa 100644 --- a/src/cmdline/cmdline_versions.cc +++ b/src/cmdline/cmdline_versions.cc @@ -51,6 +51,7 @@ #include <sigc++/bind.h> #include <cwidget/generic/util/ref_ptr.h> +#include <cwidget/generic/util/ssprintf.h> #include <vector> @@ -252,7 +253,7 @@ namespace const shared_ptr<terminal_metrics> &term_metrics, const shared_ptr<terminal_output> &term_output) { - // Set to -1 if any exact-name matches fail. Also set to -1 if + // Set to 100 if any exact-name matches fail. Also set to 1 if // there are no results at all. int return_value = 0; @@ -291,16 +292,16 @@ namespace if(output_size == output.size() && (*pIt)->get_type() == m::pattern::exact_name) { - return_value = 1; - _error->Error(_("No such package \"%s\""), + return_value = 100; + _error->Error(_("Unable to locate package %s"), (*pIt)->get_exact_name_name().c_str()); } } search_progress_display->done(); - if(output.empty()) - return_value = 2; + if(output.empty() && return_value == 0) + return_value = 1; // Decide how and whether to group the results. Not initialized // so the compiler will check that we always assign a value. @@ -388,7 +389,7 @@ namespace break; default: - _error->Error("Internal error: invalid show-package-names option."); + _error->Error("Internal error: invalid show-package-names option"); do_show_package_names = package_names_should_auto_show; break; } @@ -544,12 +545,9 @@ int cmdline_versions(int argc, char *argv[], const char *status_fname, pkg_sortpolicy *sort_policy = parse_sortpolicy(sort); if(!sort_policy) - { - _error->DumpErrors(); - return -1; - } + return 100; - _error->DumpErrors(); + consume_errors(); const unsigned int screen_width = term->get_screen_width(); if(!width.empty()) @@ -563,9 +561,8 @@ int cmdline_versions(int argc, char *argv[], const char *status_fname, if(!cw::util::transcode(display_format.c_str(), wdisplay_format)) { - _error->DumpErrors(); - fprintf(stderr, _("iconv of %s failed.\n"), display_format.c_str()); - return -1; + _error->Error(_("iconv of %s failed"), display_format.c_str()); + return 100; } boost::scoped_ptr<cw::config::column_definition_list> columns; @@ -574,15 +571,12 @@ int cmdline_versions(int argc, char *argv[], const char *status_fname, pkg_item::pkg_columnizer::defaults)); if(columns.get() == NULL) - { - _error->DumpErrors(); - return -1; - } + return 100; if(argc <= 1) { - fprintf(stderr, _("versions: You must provide at least one package selector\n")); - return -1; + _error->Error(_("versions: You must provide at least one package selector")); + return 100; } OpProgress progress; @@ -590,28 +584,34 @@ int cmdline_versions(int argc, char *argv[], const char *status_fname, apt_init(&progress, true, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; std::vector<cw::util::ref_ptr<m::pattern> > matchers; + bool parsing_arguments_failed = false; + for(int i = 1; i < argc; ++i) { const char * const arg = argv[i]; - cw::util::ref_ptr<m::pattern> m = m::parse(arg); - if(!m.valid()) - { - _error->DumpErrors(); - - return -1; - } - - matchers.push_back(m); + cw::util::ref_ptr<m::pattern> m; + const pkgCache::PkgIterator pkg = (*apt_cache_file)->FindPkg(arg); + if(pkg.end() == false) + m = m::pattern::make_exact_name(pkg.Name()); + else if(m::is_pattern(arg) == true) + m = m::parse(arg); + else + _error->Error(_("Unable to locate package %s"), arg); + + if(m.valid() == false) + parsing_arguments_failed = true; + else + matchers.push_back(m); } + if(parsing_arguments_failed == true) + return 100; + return do_search_versions(matchers, sort_policy, *columns, diff --git a/src/cmdline/cmdline_why.cc b/src/cmdline/cmdline_why.cc index 2fccc43a..402cc272 100644 --- a/src/cmdline/cmdline_why.cc +++ b/src/cmdline/cmdline_why.cc @@ -1355,13 +1355,14 @@ int cmdline_why(int argc, char *argv[], { const shared_ptr<terminal_io> term = create_terminal(); - _error->DumpErrors(); + consume_errors(); if(argc < 2) { - fprintf(stderr, _("%s: this command requires at least one argument (the package to query).\n"), - argv[0]); - return -1; + _error->Error(_("%s: this command requires at least one argument (the" + " package to query)"), + argv[0]); + return 100; } OpProgress progress; @@ -1369,10 +1370,7 @@ int cmdline_why(int argc, char *argv[], apt_init(&progress, true, status_fname); if(_error->PendingError()) - { - _error->DumpErrors(); - return -1; - } + return 100; // Keep track of whether any argument couldn't be parsed, but // don't bail until we finish parsing, so we can display all @@ -1381,10 +1379,10 @@ int cmdline_why(int argc, char *argv[], const char *pkgname = argv[argc - 1]; bool is_removal = is_why_not; - pkgCache::PkgIterator pkg = (*apt_cache_file)->FindPkg(argv[argc - 1]); + pkgCache::PkgIterator pkg = (*apt_cache_file)->FindPkg(pkgname); if(pkg.end()) { - _error->Error(_("No package named \"%s\" exists."), pkgname); + _error->Error(_("Unable to locate package %s"), pkgname); parsing_arguments_failed = true; } @@ -1406,13 +1404,9 @@ int cmdline_why(int argc, char *argv[], matchers.push_back(p); } - - - _error->DumpErrors(); - int rval; if(parsing_arguments_failed) - rval = -1; + rval = 100; else rval = do_why(matchers, pkg, diff --git a/src/generic/apt/download_install_manager.cc b/src/generic/apt/download_install_manager.cc index 9c779f86..7c9aa835 100644 --- a/src/generic/apt/download_install_manager.cc +++ b/src/generic/apt/download_install_manager.cc @@ -39,7 +39,8 @@ using namespace std; download_install_manager::download_install_manager(bool _download_only, const run_dpkg_in_terminal_func &_run_dpkg_in_terminal) - : log(NULL), download_only(_download_only), pm(new pkgDPkgPM(*apt_cache_file)), + : log(NULL), download_only(_download_only), + pm(new pkgDPkgPM(*apt_cache_file)), run_dpkg_in_terminal(_run_dpkg_in_terminal) { } @@ -102,7 +103,7 @@ bool download_install_manager::prepare(OpProgress &progress, download_manager::result download_install_manager::finish_pre_dpkg(pkgAcquire::RunResult res) { - if(res != pkgAcquire::Continue) + if(res == pkgAcquire::Failed) return failure; bool failed=false; @@ -110,15 +111,18 @@ download_manager::result download_install_manager::finish_pre_dpkg(pkgAcquire::R i != fetcher->ItemsEnd(); ++i) { if((*i)->Status == pkgAcquire::Item::StatDone && - (*i)->Complete) + (*i)->Complete == true) continue; if((*i)->Status == pkgAcquire::Item::StatIdle) - continue; + { + // Transient = true; + continue; + } failed=true; - _error->Error(_("Failed to fetch %s: %s"), (*i)->DescURI().c_str(), (*i)->ErrorText.c_str()); - break; + _error->Warning(_("Failed to fetch %s: %s"), + (*i)->DescURI().c_str(), (*i)->ErrorText.c_str()); } if(download_only) @@ -148,13 +152,17 @@ download_manager::result download_install_manager::finish_pre_dpkg(pkgAcquire::R // control the code at dpkg's end), them's the breaks. apt_cache_file->ReleaseLock(); - result rval = success; + download_manager::result rval; const pkgPackageManager::OrderResult pre_fork_result = pm->DoInstallPreFork(); - if(pre_fork_result == pkgPackageManager::Failed) - rval = failure; + switch(pre_fork_result) + { + case pkgPackageManager::Completed: rval = success; break; + case pkgPackageManager::Failed: rval = failure; break; + case pkgPackageManager::Incomplete: rval = do_again; break; + } return rval; } @@ -171,7 +179,7 @@ pkgPackageManager::OrderResult download_install_manager::run_dpkg(int status_fd) switch(pmres) { case pkgPackageManager::Failed: - _error->DumpErrors(); + _error->DumpErrors(std::cerr, GlobalError::WARNING, false); cerr << _("A package failed to install. Trying to recover:") << endl; if(system("DPKG_NO_TSTP=1 dpkg --configure -a") != 0) { /* ignore */ } break; @@ -191,16 +199,15 @@ void download_install_manager::finish_post_dpkg(pkgPackageManager::OrderResult d OpProgress *progress, const sigc::slot1<void, result> &k) { - result rval = success; - + result rval; switch(dpkg_result) { case pkgPackageManager::Failed: rval = failure; break; case pkgPackageManager::Completed: + rval = success; break; - case pkgPackageManager::Incomplete: rval = do_again; break; @@ -208,15 +215,23 @@ void download_install_manager::finish_post_dpkg(pkgPackageManager::OrderResult d fetcher->Shutdown(); + if(_error->PendingError() == true) + rval = failure; + // Get the archives again. This was necessary for multi-CD // installs, according to my comments in an old commit log in the // Subversion repository. - if(!pm->GetArchives(fetcher, &src_list, apt_package_records)) - rval = failure; - else if(!apt_cache_file->GainLock()) + if(rval == do_again) + { + if(!pm->GetArchives(fetcher, &src_list, apt_package_records)) + rval = failure; + } + + if(!apt_cache_file->GainLock()) // This really shouldn't happen. { - _error->Error(_("Could not regain the system lock! (Perhaps another apt or dpkg is running?)")); + _error->Error(_("Could not regain the system lock! (Perhaps another" + " apt or dpkg is running?)")); rval = failure; } @@ -257,7 +272,7 @@ void download_install_manager::finish(pkgAcquire::RunResult result, { const download_manager::result pre_res = finish_pre_dpkg(result); - if(pre_res == success && !download_only) + if(pre_res != failure && !download_only) { run_dpkg_in_terminal(sigc::mem_fun(*this, &download_install_manager::run_dpkg), sigc::bind(sigc::mem_fun(*this, &download_install_manager::finish_post_dpkg), @@ -268,7 +283,6 @@ void download_install_manager::finish(pkgAcquire::RunResult result, else { pkgPackageManager::OrderResult res; - switch(pre_res) { case success: @@ -278,7 +292,6 @@ void download_install_manager::finish(pkgAcquire::RunResult result, res = pkgPackageManager::Incomplete; break; case failure: - default: res = pkgPackageManager::Failed; break; } diff --git a/src/generic/apt/matching/pattern.cc b/src/generic/apt/matching/pattern.cc index 75339e1d..5743a2a7 100644 --- a/src/generic/apt/matching/pattern.cc +++ b/src/generic/apt/matching/pattern.cc @@ -79,9 +79,7 @@ namespace aptitude bool is_pattern(const std::string &s) { - // regex characters are ".?+*|[^$" - // pattern characters are "~?" - return s.find_first_of("~?.?+*|[^$") != s.npos; + return s.find_first_of("~?") != s.npos; } } } diff --git a/src/generic/apt/matching/pattern.h b/src/generic/apt/matching/pattern.h index 96d48550..5aad42f8 100644 --- a/src/generic/apt/matching/pattern.h +++ b/src/generic/apt/matching/pattern.h @@ -2021,8 +2021,8 @@ namespace aptitude * This is used in situations where it would be counterintuitive * for all strings to be treated as search patterns, but where we * want search patterns to be available. Strings are considered - * to be seach patterns if they contain a tilde (~), a question - * mark (?), or any regex characters (.?+*|[^$). + * to be seach patterns if they contain a tilde (~) or a question + * mark (?). * * \return \b true if the string qualifies as a search pattern. */ diff --git a/src/main.cc b/src/main.cc index e7007243..47b305d4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -440,7 +440,9 @@ namespace { // ForTranslators: both the translated and the untranslated // log level names are accepted here. - _error->Error(_("Unknown log level name \"%s\" (expected \"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", or \"off\")."), + _error->Error(_("Unknown log level name \"%s\" (expected \"trace\"," + " \"debug\", \"info\", \"warn\", \"error\"," + " \"fatal\", or \"off\")."), level_name.c_str()); return; } @@ -449,7 +451,7 @@ namespace if(!targetLogger) { - _error->Error(_("Invalid logger name \"%s\"."), + _error->Error(_("Invalid logger name \"%s\""), logger_name.c_str()); return; } @@ -511,27 +513,6 @@ namespace } } -// Ensure that the cache is always closed when main() exits. Without -// this, there might be dangling flyweights hanging around, and those -// can trigger aborts when the static flyweight pool is destroyed. -// -// TBH, I think it might be worth writing our own flyweight stand-in -// to avoid this particular bit of stupid. On the other hand, it -// might be better to fully shut down the cache all the time, to -// better detect leaks and so on? I'm undecided -- and it shouldn't -// take too long to clear out the cache. -struct close_cache_on_exit -{ - close_cache_on_exit() - { - } - - ~close_cache_on_exit() - { - apt_shutdown(); - } -}; - void do_message_logged(std::ostream &out, const char *sourceFilename, int sourceLineNumber, @@ -628,7 +609,16 @@ int main(int argc, const char *argv[]) const char * const rootdir = getenv("APT_ROOT_DIR"); apt_preinit(rootdir); - close_cache_on_exit close_on_exit; + // Ensure that the cache is always closed when main() exits. Without + // this, there might be dangling flyweights hanging around, and those + // can trigger aborts when the static flyweight pool is destroyed. + // + // TBH, I think it might be worth writing our own flyweight stand-in + // to avoid this particular bit of stupid. On the other hand, it + // might be better to fully shut down the cache all the time, to + // better detect leaks and so on? I'm undecided -- and it shouldn't + // take too long to clear out the cache. + atexit(&apt_shutdown); // NOTE: this can of course be spoofed. Anyone bothering to is off their // rocker. @@ -664,7 +654,7 @@ int main(int argc, const char *argv[]) if(cmdl.Parse(argc, argv) == false) { _error->DumpErrors(); - return 1; + return 100; } if(aptcfg->FindB("help", false) == true) @@ -755,10 +745,10 @@ int main(int argc, const char *argv[]) if(read_user_tag_applications(user_tags) == false) { _error->DumpErrors(); - return 1; + return 100; } - group_by_option group_by_mode; + group_by_option group_by_mode = group_by_auto; try { group_by_mode = parse_group_by_option(group_by_mode_string); @@ -766,10 +756,9 @@ int main(int argc, const char *argv[]) catch(std::exception &ex) { _error->Error("%s", ex.what()); - group_by_mode = group_by_auto; } - show_package_names_option show_package_names_mode; + show_package_names_option show_package_names_mode = show_package_names_auto; if(show_package_names_mode_string == "never" || show_package_names_mode_string == P_("--show-package-names|never")) show_package_names_mode = show_package_names_never; @@ -780,14 +769,11 @@ int main(int argc, const char *argv[]) show_package_names_mode_string == P_("--show-package-names|always")) show_package_names_mode = show_package_names_always; else - { - _error->Error("%s", - (boost::format(_("Invalid package names display mode \"%s\" (should be \"never\", \"auto\", or \"always\").")) - % show_package_names_mode_string).str().c_str()); - show_package_names_mode = show_package_names_auto; - } + _error->Error(_("Invalid package names display mode \"%s\" (should be" + " \"never\", \"auto\", or \"always\")."), + show_package_names_mode_string.c_str()); - aptitude::why::roots_string_mode why_display_mode; + aptitude::why::roots_string_mode why_display_mode = aptitude::why::no_summary; if(show_why_summary_mode == "no-summary" || show_why_summary_mode == _("no-summary")) why_display_mode = aptitude::why::no_summary; else if(show_why_summary_mode == "first-package" || show_why_summary_mode == _("first-package")) @@ -799,13 +785,13 @@ int main(int argc, const char *argv[]) else if(show_why_summary_mode == "all-packages-with-dep-versions" || show_why_summary_mode == _("all-packages-with-dep-versions")) why_display_mode = aptitude::why::show_chain_with_versions; else - { - // ForTranslators: "why" here is the aptitude command name and - // should not be translated. - _error->Error(_("Invalid \"why\" summary mode \"%s\": expected \"no-summary\", \"first-package\", \"first-package-and-type\", \"all-packages\", or \"all-packages-with-dep-versions\"."), - show_why_summary_mode.c_str()); - why_display_mode = aptitude::why::no_summary; - } + // ForTranslators: "why" here is the aptitude command name and + // should not be translated. + _error->Error(_("Invalid \"why\" summary mode \"%s\": expected" + " \"no-summary\", \"first-package\"," + " \"first-package-and-type\", \"all-packages\"," + " or \"all-packages-with-dep-versions\"."), + show_why_summary_mode.c_str()); apply_config_file_logging_levels(aptcfg); @@ -840,28 +826,21 @@ int main(int argc, const char *argv[]) ++num_startup_actions; if(num_startup_actions > 1) - { - fprintf(stderr, "%s", - _("Only one of --auto-clean-on-startup, --clean-on-startup, -i, and -u may be specified\n")); - usage(); - exit(1); - } + _error->Error(_("Only one of --auto-clean-on-startup," + " --clean-on-startup, -i, and -u may be specified")); } if((update_only || install_only || autoclean_only || clean_only) && cmdline_mode == true) - { - fprintf(stderr, "%s\n", - _("-u, -i, and --clean-on-startup may not be specified in command-line mode (eg, with 'install')")); - usage(); - exit(1); - } + _error->Error(_("-u, -i, --clean-on-startup, and --autoclean-on-startup" + " may not be specified in command-line mode (eg, with" + " 'install')")); // Abort now if there were any errors. if(_error->PendingError() == true) { _error->DumpErrors(); - return 1; + return 100; } _error->MergeWithStack(); @@ -869,44 +848,41 @@ int main(int argc, const char *argv[]) // Possibly run off and do other commands. if(cmdline_mode == true) { + using namespace aptitude::cmdline; + try { // Connect up the "please consume errors" routine for the // command-line. - consume_errors.connect(sigc::mem_fun(_error, (void (GlobalError::*)()) &GlobalError::DumpErrors)); - - if(update_only || install_only || autoclean_only || clean_only) - { - fprintf(stderr, "%s\n", - _("-u, -i, and --clean-on-startup may not be specified with a command")); - usage(); - exit(1); - } + consume_errors.connect( + sigc::mem_fun(_error, + (void (GlobalError::*)()) &GlobalError::PushToStack)); int filec = cmdl.FileSize(); char **filev = const_cast<char **>(cmdl.FileList); + int rval = 0; // TODO: warn the user if they passed --full-resolver to // something other than "upgrade" or do_action. if(!strcasecmp(filev[0], "update")) - return cmdline_update(filec, filev, verbose); + rval = cmdline_update(filec, filev, verbose); else if(!strcasecmp(filev[0], "clean")) - return cmdline_clean(filec, filev, simulate); + rval = cmdline_clean(filec, filev, simulate); else if(!strcasecmp(filev[0], "autoclean")) - return cmdline_autoclean(filec, filev, simulate); + rval = cmdline_autoclean(filec, filev, simulate); else if(!strcasecmp(filev[0], "forget-new")) - return cmdline_forget_new(filec, filev, + rval = cmdline_forget_new(filec, filev, status_fname, simulate); else if(!strcasecmp(filev[0], "search")) - return cmdline_search(filec, filev, + rval = cmdline_search(filec, filev, status_fname, package_display_format, width, sort_policy, disable_columns, debug_search); else if(!strcasecmp(filev[0], "versions")) - return cmdline_versions(filec, filev, + rval = cmdline_versions(filec, filev, status_fname, version_display_format, width, sort_policy, @@ -915,11 +891,11 @@ int main(int argc, const char *argv[]) group_by_mode, show_package_names_mode); else if(!strcasecmp(filev[0], "why")) - return cmdline_why(filec, filev, + rval = cmdline_why(filec, filev, status_fname, verbose, why_display_mode, false); else if(!strcasecmp(filev[0], "why-not")) - return cmdline_why(filec, filev, + rval = cmdline_why(filec, filev, status_fname, verbose, why_display_mode, true); else if( (!strcasecmp(filev[0], "install")) || @@ -939,71 +915,75 @@ int main(int argc, const char *argv[]) (!strcasecmp(filev[0], "keep-all")) || (!strcasecmp(filev[0], "build-dep")) || (!strcasecmp(filev[0], "build-depends"))) - { - return cmdline_do_action(filec, filev, - status_fname, - simulate, assume_yes, download_only, - fix_broken, showvers, showdeps, - showsize, showwhy, - visual_preview, always_prompt, - resolver_mode, safe_resolver_show_resolver_actions, - safe_resolver_no_new_installs, safe_resolver_no_new_upgrades, - user_tags, - arch_only, queue_only, verbose); - } + rval = cmdline_do_action(filec, filev, + status_fname, + simulate, assume_yes, download_only, + fix_broken, showvers, showdeps, + showsize, showwhy, + visual_preview, always_prompt, + resolver_mode, safe_resolver_show_resolver_actions, + safe_resolver_no_new_installs, safe_resolver_no_new_upgrades, + user_tags, + arch_only, queue_only, verbose); else if(!strcasecmp(filev[0], "add-user-tag") || !strcasecmp(filev[0], "remove-user-tag")) - return aptitude::cmdline::cmdline_user_tag(filec, filev, - quiet, verbose); + rval = cmdline_user_tag(filec, filev, + quiet, verbose); else if(!strcasecmp(filev[0], "extract-cache-subset")) - return aptitude::cmdline::extract_cache_subset(filec, - filev); + rval = extract_cache_subset(filec, filev); else if(!strcasecmp(filev[0], "download")) - return cmdline_download(filec, filev); + rval = cmdline_download(filec, filev); else if(!strcasecmp(filev[0], "changelog")) - return cmdline_changelog(filec, filev); + rval = cmdline_changelog(filec, filev); else if(!strcasecmp(filev[0], "moo")) - return cmdline_moo(filec, filev, verbose); + rval = cmdline_moo(filec, filev, verbose); else if(!strcasecmp(filev[0], "show")) - return cmdline_show(filec, filev, verbose); + rval = cmdline_show(filec, filev, verbose); else if(!strcasecmp(filev[0], "dump-resolver")) - return cmdline_dump_resolver(filec, filev, status_fname); + rval = cmdline_dump_resolver(filec, filev, status_fname); else if(!strcasecmp(filev[0], "check-resolver")) - return cmdline_check_resolver(filec, filev, status_fname); + rval = cmdline_check_resolver(filec, filev, status_fname); else if(!strcasecmp(filev[0], "help")) - { - usage(); - exit(0); - } + usage(); // Debugging/profiling commands: else if(!strcasecmp(filev[0], "nop")) { OpTextProgress p(aptcfg->FindI("Quiet", 0)); - _error->DumpErrors(); apt_init(&p, true); - exit(0); } else if(!strcasecmp(filev[0], "nop-noselections")) { OpTextProgress p(aptcfg->FindI("Quiet", 0)); - _error->DumpErrors(); apt_init(&p, false); - exit(0); } else if(!strcasecmp(filev[0], "dump-config")) { OpTextProgress p(aptcfg->FindI("Quiet", 0)); apt_init(&p, false); _config->Dump(std::cout); - _error->DumpErrors(); - exit(0); } else { - fprintf(stderr, _("Unknown command \"%s\"\n"), filev[0]); - usage(); - exit(1); + _error->Error(_("Unknown command \"%s\""), filev[0]); + rval = 100; } + + while(_error->StackCount() > 0) + _error->MergeWithStack(); + + if(_error->PendingError() == true && rval == 0) + rval = 100; + + // Do not dump errors if user aborted. + if(rval == 1) + return rval; + + if(aptcfg->FindI("quiet", 0) > 0) + _error->DumpErrors(); + else + _error->DumpErrors(GlobalError::DEBUG); + + return rval; } catch(StdinEOFException) { @@ -1017,7 +997,7 @@ int main(int argc, const char *argv[]) std::string backtrace = e.get_backtrace(); if(!backtrace.empty()) fprintf(stderr, _("Backtrace:\n%s\n"), backtrace.c_str()); - return -1; + return 100; } } @@ -1103,11 +1083,11 @@ int main(int argc, const char *argv[]) if(!backtrace.empty()) fprintf(stderr, _("Backtrace:\n%s\n"), backtrace.c_str()); - return -1; + return 100; } - // The cache is closed when the close_on_exit object declared - // above is destroyed. + // The cache is closed by apt_shutdown, which was registered + // earlier with atexit(3). return 0; } @@ -1257,7 +1257,8 @@ namespace void install_or_remove_packages() { boost::shared_ptr<download_install_manager> m = - boost::make_shared<download_install_manager>(false, sigc::ptr_fun(&run_dpkg_with_cwidget_suspended)); + boost::make_shared<download_install_manager>(false, + sigc::ptr_fun(&run_dpkg_with_cwidget_suspended)); m->post_forget_new_hook.connect(package_states_changed.make_slot()); |