diff options
author | David Kalnischkies <david@kalnischkies.de> | 2015-09-25 19:58:43 +0200 |
---|---|---|
committer | David Kalnischkies <david@kalnischkies.de> | 2015-11-04 18:04:00 +0100 |
commit | 64e3414e00906e6eaa72d7b63ca76d1c59ecadf6 (patch) | |
tree | 5425586b556798bc1dbbb35c53e697a5a916394e | |
parent | b49068c566d749130e023536d54588c948c16edf (diff) |
allow all dpkg selections to be set via apt-mark and libapt
As we have support for 'hold', we need support for undoing a hold which
in effect means that we implemented most other states as well, just that
they weren't exposed in the interface directly so far.
-rw-r--r-- | apt-pkg/statechanges.cc | 88 | ||||
-rw-r--r-- | apt-pkg/statechanges.h | 18 | ||||
-rw-r--r-- | apt-private/private-cmndline.cc | 28 | ||||
-rw-r--r-- | cmdline/apt-mark.cc | 102 | ||||
-rw-r--r-- | doc/apt-mark.8.xml | 110 | ||||
-rw-r--r-- | doc/apt-verbatim.ent | 41 | ||||
-rwxr-xr-x | test/integration/test-apt-mark | 40 |
7 files changed, 297 insertions, 130 deletions
diff --git a/apt-pkg/statechanges.cc b/apt-pkg/statechanges.cc index a20319d2d..dc446a665 100644 --- a/apt-pkg/statechanges.cc +++ b/apt-pkg/statechanges.cc @@ -14,46 +14,62 @@ class StateChanges::Private { public: APT::VersionVector hold; + APT::VersionVector unhold; APT::VersionVector install; + APT::VersionVector deinstall; + APT::VersionVector purge; APT::VersionVector error; }; -void StateChanges::Hold(pkgCache::VerIterator const &Ver) -{ - d->hold.push_back(Ver); -} -APT::VersionVector& StateChanges::Hold() -{ - return d->hold; -} -void StateChanges::Unhold(pkgCache::VerIterator const &Ver) -{ - d->install.push_back(Ver); -} -APT::VersionVector& StateChanges::Unhold() -{ - return d->install; +#define APT_GETTERSETTER(Name, Container) \ +void StateChanges::Name(pkgCache::VerIterator const &Ver) \ +{ \ + Container.push_back(Ver); \ +}\ +APT::VersionVector& StateChanges::Name() \ +{ \ + return Container; \ } +APT_GETTERSETTER(Hold, d->hold) +APT_GETTERSETTER(Unhold, d->unhold) +APT_GETTERSETTER(Install, d->install) +APT_GETTERSETTER(Remove, d->deinstall) +APT_GETTERSETTER(Purge, d->purge) +#undef APT_GETTERSETTER APT::VersionVector& StateChanges::Error() { return d->error; } -void StateChanges::Discard() +void StateChanges::clear() { d->hold.clear(); + d->unhold.clear(); d->install.clear(); + d->deinstall.clear(); + d->purge.clear(); d->error.clear(); } +bool StateChanges::empty() const +{ + return d->hold.empty() && + d->unhold.empty() && + d->install.empty() && + d->deinstall.empty() && + d->purge.empty() && + d->error.empty(); +} + bool StateChanges::Save(bool const DiscardOutput) { d->error.clear(); - if (d->hold.empty() && d->install.empty()) + if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty()) return true; std::vector<std::string> Args = debSystem::GetDpkgBaseCommand(); // ensure dpkg knows about the package so that it keeps the status we set + if (d->hold.empty() == false || d->install.empty() == false) { APT::VersionVector makeDpkgAvailable; auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; }; @@ -94,6 +110,24 @@ bool StateChanges::Save(bool const DiscardOutput) else fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str()); }; + for (auto const &V: d->unhold) + { + if (V.ParentPkg()->CurrentVer != 0) + state = "install"; + else + state = "deinstall"; + dpkgName(V); + } + if (d->purge.empty() == false) + { + state = "purge"; + std::for_each(d->purge.begin(), d->purge.end(), dpkgName); + } + if (d->deinstall.empty() == false) + { + state = "deinstall"; + std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName); + } if (d->hold.empty() == false) { state = "hold"; @@ -108,16 +142,16 @@ bool StateChanges::Save(bool const DiscardOutput) if (ExecWait(dpkgSelections, "dpkg --set-selections") == false) { - if (d->hold.empty()) - std::swap(d->install, d->error); - else if (d->install.empty()) - std::swap(d->hold, d->error); - else - { - std::swap(d->hold, d->error); - std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error)); - d->install.clear(); - } + std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error)); + d->purge.clear(); + std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error)); + d->deinstall.clear(); + std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error)); + d->hold.clear(); + std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error)); + d->unhold.clear(); + std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error)); + d->install.clear(); } return d->error.empty(); } diff --git a/apt-pkg/statechanges.h b/apt-pkg/statechanges.h index fa60c5864..1eaf21a3a 100644 --- a/apt-pkg/statechanges.h +++ b/apt-pkg/statechanges.h @@ -14,14 +14,20 @@ class APT_PUBLIC StateChanges { public: // getter/setter for the different states - APT::VersionVector& Hold(); - void Hold(pkgCache::VerIterator const &Ver); - APT::VersionVector& Unhold(); - void Unhold(pkgCache::VerIterator const &Ver); +#define APT_GETTERSETTER(Name) \ + APT::VersionVector& Name(); \ + void Name(pkgCache::VerIterator const &Ver) + APT_GETTERSETTER(Hold); + APT_GETTERSETTER(Unhold); + APT_GETTERSETTER(Install); + APT_GETTERSETTER(Remove); + APT_GETTERSETTER(Purge); APT::VersionVector& Error(); +#undef APT_GETTERSETTER - // forgets all unsaved changes - void Discard(); + // operate on all containers at once + void clear(); + bool empty() const; /** commit the staged changes to the database(s). * diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index 7190fe50b..5d6fd3c2e 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -227,19 +227,31 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ { if (CmdMatches("auto", "manual", "hold", "unhold", "showauto", - "showmanual", "showhold", "showholds", "install", + "showmanual", "showhold", "showholds", "markauto", "unmarkauto")) + { + addArg('f',"file","Dir::State::extended_states",CommandLine::HasArg); + } + else if (CmdMatches("install", "remove", "deinstall", "purge", + "showinstall", "showinstalls", "showremove", "showremoves", + "showdeinstall", "showdeinstalls", "showpurge", "showpurges")) ; else return false; - addArg('v',"verbose","APT::MarkAuto::Verbose",0); - addArg('s',"simulate","APT::Mark::Simulate",0); - addArg('s',"just-print","APT::Mark::Simulate",0); - addArg('s',"recon","APT::Mark::Simulate",0); - addArg('s',"dry-run","APT::Mark::Simulate",0); - addArg('s',"no-act","APT::Mark::Simulate",0); - addArg('f',"file","Dir::State::extended_states",CommandLine::HasArg); + if (CmdMatches("markauto", "unmarkauto")) + { + addArg('v',"verbose","APT::MarkAuto::Verbose",0); + } + + if (strncmp(Cmd, "show", strlen("show")) != 0) + { + addArg('s',"simulate","APT::Mark::Simulate",0); + addArg('s',"just-print","APT::Mark::Simulate",0); + addArg('s',"recon","APT::Mark::Simulate",0); + addArg('s',"dry-run","APT::Mark::Simulate",0); + addArg('s',"no-act","APT::Mark::Simulate",0); + } return true; } diff --git a/cmdline/apt-mark.cc b/cmdline/apt-mark.cc index 9d1d0863e..6080c7ea3 100644 --- a/cmdline/apt-mark.cc +++ b/cmdline/apt-mark.cc @@ -167,8 +167,8 @@ static bool ShowAuto(CommandLine &CmdL) return true; } /*}}}*/ -/* DoHold - mark packages as hold by dpkg {{{*/ -static bool DoHold(CommandLine &CmdL) +// DoSelection - wrapping around dpkg selections /*{{{*/ +static bool DoSelection(CommandLine &CmdL) { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); @@ -179,29 +179,39 @@ static bool DoHold(CommandLine &CmdL) if (pkgset.empty() == true) return _error->Error(_("No packages found")); - bool const MarkHold = strcasecmp(CmdL.FileList[0],"hold") == 0; - - auto const part = std::stable_partition(pkgset.begin(), pkgset.end(), - [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; }); - - auto const doneBegin = MarkHold ? pkgset.begin() : part; - auto const doneEnd = MarkHold ? part : pkgset.end(); - - std::for_each(doneBegin, doneEnd, [&MarkHold](pkgCache::VerIterator const &V) { - if (MarkHold == true) - ioprintf(c1out, _("%s was already set on hold.\n"), V.ParentPkg().FullName(true).c_str()); - else - ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str()); - }); - - if (doneBegin == pkgset.begin() && doneEnd == pkgset.end()) - return true; - - auto const changeBegin = MarkHold ? part : pkgset.begin(); - auto const changeEnd = MarkHold ? pkgset.end() : part; - APT::StateChanges marks; - std::move(changeBegin, changeEnd, std::back_inserter(MarkHold ? marks.Hold() : marks.Unhold())); + if (strcasecmp(CmdL.FileList[0], "hold") == 0 || strcasecmp(CmdL.FileList[0], "unhold") == 0) + { + auto const part = std::stable_partition(pkgset.begin(), pkgset.end(), + [](pkgCache::VerIterator const &V) { return V.ParentPkg()->SelectedState == pkgCache::State::Hold; }); + + bool const MarkHold = strcasecmp(CmdL.FileList[0],"hold") == 0; + auto const doneBegin = MarkHold ? pkgset.begin() : part; + auto const doneEnd = MarkHold ? part : pkgset.end(); + std::for_each(doneBegin, doneEnd, [&MarkHold](pkgCache::VerIterator const &V) { + if (MarkHold == true) + ioprintf(c1out, _("%s was already set on hold.\n"), V.ParentPkg().FullName(true).c_str()); + else + ioprintf(c1out, _("%s was already not hold.\n"), V.ParentPkg().FullName(true).c_str()); + }); + + if (doneBegin == pkgset.begin() && doneEnd == pkgset.end()) + return true; + + auto const changeBegin = MarkHold ? part : pkgset.begin(); + auto const changeEnd = MarkHold ? pkgset.end() : part; + std::move(changeBegin, changeEnd, std::back_inserter(MarkHold ? marks.Hold() : marks.Unhold())); + } + else + { + // FIXME: Maybe show a message for unchanged states here as well? + if (strcasecmp(CmdL.FileList[0], "purge") == 0) + std::swap(marks.Purge(), pkgset); + else if (strcasecmp(CmdL.FileList[0], "deinstall") == 0 || strcasecmp(CmdL.FileList[0], "remove") == 0) + std::swap(marks.Remove(), pkgset); + else //if (strcasecmp(CmdL.FileList[0], "install") == 0) + std::swap(marks.Install(), pkgset); + } pkgset.clear(); bool success = true; @@ -211,30 +221,44 @@ static bool DoHold(CommandLine &CmdL) if (success == false) _error->Error(_("Executing dpkg failed. Are you root?")); } - for (auto Ver : marks.Hold()) ioprintf(c1out,_("%s set on hold.\n"), Ver.ParentPkg().FullName(true).c_str()); for (auto Ver : marks.Unhold()) ioprintf(c1out,_("Canceled hold on %s.\n"), Ver.ParentPkg().FullName(true).c_str()); - + for (auto Ver : marks.Purge()) + ioprintf(c1out,_("Selected %s for purge.\n"), Ver.ParentPkg().FullName(true).c_str()); + for (auto Ver : marks.Remove()) + ioprintf(c1out,_("Selected %s for removal.\n"), Ver.ParentPkg().FullName(true).c_str()); + for (auto Ver : marks.Install()) + ioprintf(c1out,_("Selected %s for installation.\n"), Ver.ParentPkg().FullName(true).c_str()); return success; } /*}}}*/ -/* ShowHold - show packages set on hold in dpkg status {{{*/ -static bool ShowHold(CommandLine &CmdL) +static bool ShowSelection(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); if (unlikely(Cache == NULL)) return false; + pkgCache::State::PkgSelectedState selector; + if (strncasecmp(CmdL.FileList[0], "showpurge", strlen("showpurge")) == 0) + selector = pkgCache::State::Purge; + else if (strncasecmp(CmdL.FileList[0], "showdeinstall", strlen("showdeinstall")) == 0 || + strncasecmp(CmdL.FileList[0], "showremove", strlen("showremove")) == 0) + selector = pkgCache::State::DeInstall; + else if (strncasecmp(CmdL.FileList[0], "showhold", strlen("showhold")) == 0) + selector = pkgCache::State::Hold; + else //if (strcasecmp(CmdL.FileList[0], "showinstall", strlen("showinstall")) == 0) + selector = pkgCache::State::Install; + std::vector<string> packages; if (CmdL.FileList[1] == 0) { packages.reserve(50); // how many holds are realistic? I hope just a few… for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P) - if (P->SelectedState == pkgCache::State::Hold) + if (P->SelectedState == selector) packages.push_back(P.FullName(true)); } else @@ -243,7 +267,7 @@ static bool ShowHold(CommandLine &CmdL) APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(CacheFile, CmdL.FileList + 1, helper); packages.reserve(pkgset.size()); for (APT::PackageSet::const_iterator P = pkgset.begin(); P != pkgset.end(); ++P) - if (P->SelectedState == pkgCache::State::Hold) + if (P->SelectedState == selector) packages.push_back(P.FullName(true)); } @@ -295,15 +319,19 @@ int main(int argc,const char *argv[]) /*{{{*/ CommandLine::Dispatch Cmds[] = {{"help",&ShowHelp}, {"auto",&DoAuto}, {"manual",&DoAuto}, - {"hold",&DoHold}, - {"unhold",&DoHold}, + {"hold",&DoSelection}, + {"unhold",&DoSelection}, + {"install",&DoSelection}, + {"remove",&DoSelection}, // dpkg uses deinstall, but we use remove everywhere else + {"deinstall",&DoSelection}, + {"purge",&DoSelection}, {"showauto",&ShowAuto}, {"showmanual",&ShowAuto}, - {"showhold",&ShowHold}, - // be nice and forgive the typo - {"showholds",&ShowHold}, - // be nice and forgive it as it is technical right - {"install",&DoHold}, + {"showhold",&ShowSelection}, {"showholds",&ShowSelection}, + {"showinstall",&ShowSelection}, {"showinstalls",&ShowSelection}, + {"showdeinstall",&ShowSelection}, {"showdeinstalls",&ShowSelection}, + {"showremove",&ShowSelection}, {"showremoves",&ShowSelection}, + {"showpurge",&ShowSelection}, {"showpurges",&ShowSelection}, // obsolete commands for compatibility {"markauto", &DoMarkAuto}, {"unmarkauto", &DoMarkAuto}, diff --git a/doc/apt-mark.8.xml b/doc/apt-mark.8.xml index 94f24437e..8dd157a60 100644 --- a/doc/apt-mark.8.xml +++ b/doc/apt-mark.8.xml @@ -14,7 +14,7 @@ &apt-email; &apt-product; <!-- The last update date --> - <date>2012-06-09T00:00:00Z</date> + <date>2015-09-25T00:00:00Z</date> </refentryinfo> <refmeta> @@ -26,31 +26,37 @@ <!-- Man page title --> <refnamediv> <refname>apt-mark</refname> - <refpurpose>mark/unmark a package as being automatically-installed</refpurpose> + <refpurpose>show, set and unset various settings for a package</refpurpose> </refnamediv> &synopsis-command-apt-mark; <refsect1><title>Description</title> - <para><command>apt-mark</command> will change whether a package has - been marked as being automatically installed. + <para><command>apt-mark</command> can be used as a unified frontend to set + various settings for a package like marking a package as being + automatically/manually installed or changing <command>dpkg</command> + selections such as hold, install, deinstall and purge which are respected + e.g. by <command>apt-get dselect-upgrade</command> or <command>aptitude</command>. </para> + </refsect1><refsect1><title>Automatically and manually installed packages</title> <para> When you request that a package is installed, and as a result other packages are installed to satisfy its dependencies, the - dependencies are marked as being automatically installed. Once - these automatically installed packages are no longer depended on - by any manually installed packages, they will be removed by e.g. - <command>apt-get</command> or <command>aptitude</command>. + dependencies are marked as being automatically installed, while + package you installed explicitely is marked as manually installed. + Once a automatically installed package is no longer depended on + by any manually installed package it is considered no longer needed + and e.g. <command>apt-get</command> or <command>aptitude</command> + will at least suggest removing them. </para> - <variablelist> + <variablelist> <varlistentry><term><option>auto</option></term> <listitem><para><literal>auto</literal> is used to mark a package as being automatically installed, which will cause the package to be removed when no more manually installed packages depend on this package. </para></listitem> - </varlistentry> + </varlistentry> <varlistentry><term><option>manual</option></term> <listitem><para><literal>manual</literal> is used to mark a @@ -58,23 +64,7 @@ package from being automatically removed if no other packages depend on it. </para></listitem> - </varlistentry> - - <varlistentry><term><option>hold</option></term> - <listitem><para><literal>hold</literal> is used to mark a - package as held back, which will prevent the package from being - automatically installed, upgraded or removed. - The command is only a wrapper around <command>dpkg --set-selections</command> - and the state is therefore maintained by &dpkg; and not affected - by the <option>--file</option> option. - </para></listitem> - </varlistentry> - - <varlistentry><term><option>unhold</option></term> - <listitem><para><literal>unhold</literal> is used to cancel a - previously set hold on a package to allow all actions again. - </para></listitem> - </varlistentry> + </varlistentry> <varlistentry><term><option>showauto</option></term> <listitem><para><literal>showauto</literal> is used to print a @@ -82,38 +72,66 @@ All automatically installed packages will be listed if no package is given. If packages are given only those which are automatically installed will be shown. </para></listitem> - </varlistentry> + </varlistentry> <varlistentry><term><option>showmanual</option></term> <listitem><para><literal>showmanual</literal> can be used in the same way as <literal>showauto</literal> except that it will print a list of manually installed packages instead. </para></listitem> + </varlistentry> + </variablelist> + + <refsect2><title>Options</title> + <variablelist> + <varlistentry> + <term><option>-f=&synopsis-param-filename;</option></term> + <term><option>--file=&synopsis-param-filename;</option></term> + <listitem><para> + Read/Write package stats from the filename given with the parameter + &synopsis-param-filename; instead of from the default location, which + is <filename>extended_status</filename> in the directory defined + by the Configuration Item: <literal>Dir::State</literal>. + </para></listitem> </varlistentry> + </variablelist> + </refsect2> - <varlistentry><term><option>showhold</option></term> - <listitem><para><literal>showhold</literal> is used to print a list - of packages on hold in the same way as for the other show commands. + </refsect1><refsect1><title>Prevent changes for a package</title> + <variablelist> + <varlistentry><term><option>hold</option></term> + <listitem><para><literal>hold</literal> is used to mark a + package as held back, which will prevent the package from being + automatically installed, upgraded or removed. </para></listitem> - </varlistentry> + </varlistentry> + <varlistentry><term><option>unhold</option></term> + <listitem><para><literal>unhold</literal> is used to cancel a + previously set hold on a package to allow all actions again. + </para></listitem> + </varlistentry> - </variablelist> - </refsect1> - - <refsect1><title>options</title> - - <variablelist> - <varlistentry> - <term><option>-f=&synopsis-param-filename;</option></term> - <term><option>--file=&synopsis-param-filename;</option></term> - <listitem><para> - Read/Write package stats from the filename given with the parameter - &synopsis-param-filename; instead of from the default location, which - is <filename>extended_status</filename> in the directory defined - by the Configuration Item: <literal>Dir::State</literal>.</para></listitem> + <varlistentry><term><option>showhold</option></term> + <listitem><para><literal>showhold</literal> is used to print a list + of packages on hold in the same way as for the other show commands. + </para></listitem> </varlistentry> + </variablelist> + </refsect1><refsect1><title>Shedule packages for install, remove and purge</title> + <para> + Some frontends like <command>apt-get dselect-upgrade</command> can be used to + apply previously sheduled changes to the install state of packages. Such changes + can be sheduled with the <option>install</option>, <option>remove</option> + (also known as <option>deinstall</option>) and <option>purge</option> commands. + Packages with a specific selection can be displayed with <option>showinstall</option>, + <option>showremove</option> and <option>showpurge</option> respectively. + More information about these so called dpkg selections can be found in &dpkg;. + </para> + </refsect1> + <refsect1><title>Options</title> + <variablelist> &apt-commonoptions; </variablelist> </refsect1> diff --git a/doc/apt-verbatim.ent b/doc/apt-verbatim.ent index 448e6c2df..f5e322e11 100644 --- a/doc/apt-verbatim.ent +++ b/doc/apt-verbatim.ent @@ -394,18 +394,47 @@ </cmdsynopsis></refsynopsisdiv>"> <!ENTITY synopsis-command-apt-mark "<refsynopsisdiv><cmdsynopsis> <command>apt-mark</command> - <arg><option>-f=&synopsis-param-filename;</option></arg> + <group choice='plain'> + <group choice='req'> + <arg choice='plain'><option>-f=&synopsis-param-filename;</option></arg> + <arg choice='plain'> + <group choice='req'> + <arg choice='plain'>auto</arg> + <arg choice='plain'>manual</arg> + </group> + &synopsis-arg-pkg; + </arg> + <arg choice='plain'> + <group choice='req'> + <arg choice='plain'>showauto</arg> + <arg choice='plain'>showmanual</arg> + </group> + <arg choice='opt' rep='repeat'><replaceable>&synopsis-pkg;</replaceable></arg> + </arg> + </group> + &synopsis-help; + </group> +</cmdsynopsis><cmdsynopsis><command>apt-mark</command> <group choice='plain'> <arg choice='plain'> <group choice='req'> - <arg choice='plain'>auto</arg> - <arg choice='plain'>manual</arg> - <arg choice='plain'>showauto</arg> - <arg choice='plain'>showmanual</arg> + <arg choice='plain'>hold</arg> + <arg choice='plain'>unhold</arg> + <arg choice='plain'>install</arg> + <arg choice='plain'>remove</arg> + <arg choice='plain'>purge</arg> </group> &synopsis-arg-pkg; </arg> - &synopsis-help; + <arg choice='plain'> + <group choice='req'> + <arg choice='plain'>showhold</arg> + <arg choice='plain'>showinstall</arg> + <arg choice='plain'>showremove</arg> + <arg choice='plain'>showpurge</arg> + </group> + <arg choice='opt' rep='repeat'><replaceable>&synopsis-pkg;</replaceable></arg> + </arg> </group> </cmdsynopsis></refsynopsisdiv>"> <!ENTITY synopsis-command-apt-sortpkgs "<refsynopsisdiv><cmdsynopsis> diff --git a/test/integration/test-apt-mark b/test/integration/test-apt-mark index ec4ed8316..47ade45b1 100755 --- a/test/integration/test-apt-mark +++ b/test/integration/test-apt-mark @@ -112,3 +112,43 @@ Inst uninstalled (1 unstable [all]) Inst uninstalled-native (1 unstable [amd64]) Conf uninstalled (1 unstable [all]) Conf uninstalled-native (1 unstable [amd64])' aptget install uninstalled uninstalled-native -s +testsuccess aptmark unhold uninstalled uninstalled-native + +testselections() { + testsuccess aptmark hold "$1" + testsuccessequal "$1" aptmark showholds "$1" + testsuccess aptmark unhold "$1" + testsuccessequal "$1" aptmark showinstalls "$1" + testsuccess aptmark hold "$1" + testsuccessequal "$1" aptmark showholds "$1" + testsuccess aptmark install "$1" + testsuccessequal "$1" aptmark showinstalls "$1" + testsuccess aptmark remove "$1" + testsuccessequal "$1" aptmark showremoves "$1" + testsuccess aptmark purge "$1" + testsuccessequal "$1" aptmark showpurges "$1" +} +testselections 'foo' +testselections 'bar' + +testsuccessequal 'Reading package lists... +Building dependency tree... +Reading state information... +The following packages will be REMOVED: + bar* foo* +0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded. +Purg bar [1] +Purg foo [1]' aptget dselect-upgrade -s + +testuninstalledselections() { + testsuccess aptmark hold "$1" + testsuccessequal "$1" aptmark showholds "$1" + testsuccess aptmark unhold "$1" + testsuccessequal "$1" aptmark showremoves "$1" + testsuccess aptmark hold "$1" + testsuccessequal "$1" aptmark showholds "$1" + testsuccess aptmark install "$1" + testsuccessequal "$1" aptmark showinstalls "$1" +} +testuninstalledselections 'uninstalled' +testuninstalledselections 'uninstalled-native' |