summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2023-05-02 13:56:30 +0000
committerJulian Andres Klode <jak@debian.org>2023-05-02 13:56:30 +0000
commited818cfe5c53503f8096056f599e639a9308b3da (patch)
tree5c52fba7ad6dd08817b48c3008ee32297443f047
parent64a449186387cea2cf8ebed4f7890995b48300a7 (diff)
parenta19f606aad717fe5c9c69237c3af53feb547115e (diff)
Merge branch 'pu/snapshot' into 'main'
Add --snapshot and --update support See merge request apt-team/apt!291
-rw-r--r--apt-pkg/deb/debmetaindex.cc106
-rw-r--r--apt-pkg/deb/debmetaindex.h2
-rw-r--r--apt-pkg/indexfile.cc3
-rw-r--r--apt-pkg/indexfile.h1
-rw-r--r--apt-pkg/init.cc3
-rw-r--r--apt-pkg/sourcelist.cc1
-rw-r--r--apt-private/private-cmndline.cc6
-rw-r--r--apt-private/private-install.cc5
-rw-r--r--apt-private/private-update.cc4
-rw-r--r--apt-private/private-update.h1
-rw-r--r--apt-private/private-upgrade.cc4
-rw-r--r--doc/apt-get.8.xml24
-rw-r--r--doc/apt.conf.5.xml24
-rw-r--r--doc/examples/configure-index13
-rw-r--r--doc/sources.list.5.xml17
-rwxr-xr-xtest/integration/test-apt-get-install-update111
-rwxr-xr-xtest/integration/test-snapshot191
17 files changed, 510 insertions, 6 deletions
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index c6005f1c8..4133540ab 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -123,6 +123,9 @@ class APT_HIDDEN debReleaseIndexPrivate /*{{{*/
time_t DateMaxFuture;
time_t NotBefore;
+ std::string Snapshot;
+ std::string SnapshotsServer;
+
std::vector<std::string> Architectures;
std::vector<std::string> NoSupportForAll;
std::vector<std::string> SupportedComponents;
@@ -479,6 +482,7 @@ bool debReleaseIndex::Load(std::string const &Filename, std::string * const Erro
Suite = Section.FindS("Suite");
Codename = Section.FindS("Codename");
ReleaseNotes = Section.FindS("Release-Notes");
+ d->SnapshotsServer = Section.FindS("Snapshots");
{
std::string const archs = Section.FindS("Architectures");
if (archs.empty() == false)
@@ -789,6 +793,18 @@ bool debReleaseIndex::SetDateMaxFuture(time_t const DateMaxFuture)
return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Date-Max-Future", URI.c_str(), Dist.c_str());
return true;
}
+bool debReleaseIndex::SetSnapshot(std::string const Snapshot)
+{
+ if (d->Snapshot.empty())
+ d->Snapshot = Snapshot;
+ else if (d->Snapshot != Snapshot)
+ return _error->Error(_("Conflicting values set for option %s regarding source %s %s"), "Snapshot", URI.c_str(), Dist.c_str());
+ return true;
+}
+std::string debReleaseIndex::GetSnapshotsServer() const
+{
+ return d->SnapshotsServer;
+}
bool debReleaseIndex::SetSignedBy(std::string const &pSignedBy)
{
if (SignedBy.empty() == true && pSignedBy.empty() == false)
@@ -1123,6 +1139,17 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
return defVal;
return StringToBool(opt->second, defVal);
}
+ static std::string GetSnapshotOption(std::map<std::string, std::string> const &Options, char const * const name, const std::string defVal="")
+ {
+ std::map<std::string, std::string>::const_iterator const opt = Options.find(name);
+ if (opt == Options.end())
+ return defVal;
+ int boolVal = StringToBool(opt->second, -1);
+ if (boolVal != -1)
+ return boolVal ? _config->Find("APT::Snapshot") : "";
+ return opt->second;
+ }
+
static std::vector<std::string> GetMapKeys(std::map<std::string, std::string> const &Options)
{
@@ -1167,7 +1194,7 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
return true;
}
- static debReleaseIndex * GetDebReleaseIndexBy(std::vector<metaIndex *> &List, std::string const &URI,
+ static debReleaseIndex * GetDebReleaseIndexBy(std::vector<metaIndex *> &List, std::string URI,
std::string const &Dist, std::map<std::string, std::string> const &Options)
{
std::map<std::string, std::string> ReleaseOptions{{
@@ -1182,6 +1209,8 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
ReleaseOptions.emplace("ALLOW_WEAK", "true");
if (GetBoolOption(Options, "allow-downgrade-to-insecure", _config->FindB("Acquire::AllowDowngradeToInsecureRepositories")))
ReleaseOptions.emplace("ALLOW_DOWNGRADE_TO_INSECURE", "true");
+ if (GetBoolOption(Options, "SHADOWED", false))
+ ReleaseOptions.emplace("SHADOWED", "true");
auto InReleasePath = Options.find("inrelease-path");
if (InReleasePath != Options.end())
@@ -1221,10 +1250,78 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
}
protected:
+ // This is a duplicate of pkgAcqChangelog::URITemplate() with some changes to work
+ // on metaIndex instead of cache structures, and using Snapshots
+ std::string SnapshotServer(debReleaseIndex const *Rls) const
+ {
+ if (Rls->GetLabel().empty() && Rls->GetOrigin().empty())
+ return "";
+ std::string const serverConfig = "Acquire::Snapshots::URI";
+ std::string server;
+#define APT_EMPTY_SERVER \
+ if (server.empty() == false) \
+ { \
+ if (server != "no") \
+ return server; \
+ return ""; \
+ }
+#define APT_CHECK_SERVER(X, Y) \
+ if (not Rls->Get##X().empty()) \
+ { \
+ std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls->Get##X(); \
+ server = _config->Find(specialServerConfig); \
+ APT_EMPTY_SERVER \
+ }
+ // this way e.g. Debian-Security can fallback to Debian
+ APT_CHECK_SERVER(Label, "Override::")
+ APT_CHECK_SERVER(Origin, "Override::")
- bool CreateItemInternal(std::vector<metaIndex *> &List, std::string const &URI,
+ server = Rls->GetSnapshotsServer();
+ APT_EMPTY_SERVER
+
+ APT_CHECK_SERVER(Label, "")
+ APT_CHECK_SERVER(Origin, "")
+#undef APT_CHECK_SERVER
+#undef APT_EMPTY_SERVER
+ return "";
+ }
+ bool CreateItemInternal(std::vector<metaIndex *> &List, std::string URI,
+ std::string const &Dist, std::string const &Section,
+ bool const &IsSrc, std::map<std::string, std::string> Options) const
+ {
+ auto Snapshot = GetSnapshotOption(Options, "snapshot");
+ if (not Snapshot.empty()) {
+ std::map<std::string, std::string> SnapshotOptions = Options;
+
+ Options.emplace("SHADOWED", "true");
+
+ auto const Deb = GetDebReleaseIndexBy(List, URI, Dist, Options);
+ std::string filename;
+ if (not ReleaseFileName(Deb, filename))
+ return _error->Error("Cannot identify snapshot server for %s %s - run update without snapshot id first", URI.c_str(), Dist.c_str());
+ auto OldDeb = dynamic_cast<debReleaseIndex *>(Deb->UnloadedClone());
+ if (not OldDeb->Load(filename, nullptr))
+ return _error->Error("Cannot identify snapshot server for %s %s - run update without snapshot id first", URI.c_str(), Dist.c_str());
+ auto Server = SnapshotServer(OldDeb);
+ delete OldDeb;
+
+ if (Server.empty())
+ return _error->Error("Snapshots not supported for %s %s", URI.c_str(), Dist.c_str());
+
+ auto SnapshotURI = SubstVar(Server, "@SNAPSHOTID@", Snapshot);
+
+ if (not CreateItemInternalOne(List, SnapshotURI, Dist, Section, IsSrc, SnapshotOptions))
+ return false;
+ }
+ if (not CreateItemInternalOne(List, URI, Dist, Section, IsSrc, Options))
+ return false;
+
+
+ return true;
+ }
+ bool CreateItemInternalOne(std::vector<metaIndex *> &List, std::string URI,
std::string const &Dist, std::string const &Section,
- bool const &IsSrc, std::map<std::string, std::string> const &Options) const
+ bool const &IsSrc, std::map<std::string, std::string> Options) const
{
auto const Deb = GetDebReleaseIndexBy(List, URI, Dist, Options);
if (Deb == nullptr)
@@ -1263,7 +1360,8 @@ class APT_HIDDEN debSLTypeDebian : public pkgSourceList::Type /*{{{*/
Deb->SetValidUntilMax(GetTimeOption(Options, "valid-until-max")) == false ||
Deb->SetValidUntilMin(GetTimeOption(Options, "valid-until-min")) == false ||
Deb->SetCheckDate(GetTriStateOption(Options, "check-date")) == false ||
- Deb->SetDateMaxFuture(GetTimeOption(Options, "date-max-future")) == false)
+ Deb->SetDateMaxFuture(GetTimeOption(Options, "date-max-future")) == false ||
+ Deb->SetSnapshot(GetSnapshotOption(Options, "snapshot")) == false)
return false;
std::map<std::string, std::string>::const_iterator const signedby = Options.find("signed-by");
diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h
index 717f08e2b..a1a9c41b5 100644
--- a/apt-pkg/deb/debmetaindex.h
+++ b/apt-pkg/deb/debmetaindex.h
@@ -51,6 +51,8 @@ class APT_HIDDEN debReleaseIndex : public metaIndex
bool SetValidUntilMax(time_t const Valid);
bool SetCheckDate(TriState const CheckDate);
bool SetDateMaxFuture(time_t const DateMaxFuture);
+ bool SetSnapshot(std::string Snapshot);
+ std::string GetSnapshotsServer() const; // As defined in the Release file
bool SetSignedBy(std::string const &SignedBy);
std::map<std::string, std::string> GetReleaseOptions();
diff --git a/apt-pkg/indexfile.cc b/apt-pkg/indexfile.cc
index f13b52940..1176903f4 100644
--- a/apt-pkg/indexfile.cc
+++ b/apt-pkg/indexfile.cc
@@ -121,6 +121,7 @@ std::string IndexTarget::Option(OptionKeys const EnumKey) const /*{{{*/
APT_CASE(ALLOW_WEAK);
APT_CASE(ALLOW_DOWNGRADE_TO_INSECURE);
APT_CASE(INRELEASE_PATH);
+ APT_CASE(SHADOWED);
#undef APT_CASE
case FILENAME:
{
@@ -221,6 +222,8 @@ unsigned long pkgDebianIndexTargetFile::Size() const /*{{{*/
/*}}}*/
bool pkgDebianIndexTargetFile::Exists() const /*{{{*/
{
+ if (Target.OptionBool(IndexTarget::SHADOWED))
+ return false;
return FileExists(IndexFileName());
}
/*}}}*/
diff --git a/apt-pkg/indexfile.h b/apt-pkg/indexfile.h
index d0b045a9d..95cee5dbc 100644
--- a/apt-pkg/indexfile.h
+++ b/apt-pkg/indexfile.h
@@ -91,6 +91,7 @@ class APT_PUBLIC IndexTarget /*{{{*/
ALLOW_WEAK,
ALLOW_DOWNGRADE_TO_INSECURE,
INRELEASE_PATH,
+ SHADOWED,
};
std::string Option(OptionKeys const Key) const;
bool OptionBool(OptionKeys const Key) const;
diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc
index b9d9b15d2..f70dbf308 100644
--- a/apt-pkg/init.cc
+++ b/apt-pkg/init.cc
@@ -209,6 +209,9 @@ bool pkgInitConfig(Configuration &Cnf)
Cnf.CndSet("Acquire::Changelogs::URI::Origin::Ubuntu", "https://changelogs.ubuntu.com/changelogs/pool/@CHANGEPATH@/changelog");
Cnf.CndSet("Acquire::Changelogs::AlwaysOnline::Origin::Ubuntu", true);
+ Cnf.CndSet("Acquire::Snapshots::URI::Origin::Debian", "https://snapshot.debian.org/archive/debian/@SNAPSHOTID@/");
+ Cnf.CndSet("Acquire::Snapshots::URI::Override::Label::Debian-Security", "https://snapshot.debian.org/archive/debian-security/@SNAPSHOTID@/");
+ Cnf.CndSet("Acquire::Snapshots::URI::Origin::Ubuntu", "https://snapshot.ubuntu.com/ubuntu/@SNAPSHOTID@/");
Cnf.CndSet("DPkg::Path", "/usr/sbin:/usr/bin:/sbin:/bin");
diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc
index 0ac59fcfc..055cf4142 100644
--- a/apt-pkg/sourcelist.cc
+++ b/apt-pkg/sourcelist.cc
@@ -120,6 +120,7 @@ bool pkgSourceList::Type::ParseStanza(vector<metaIndex *> &List, /*{{{*/
mapping.insert(std::make_pair("Valid-Until-Max", std::make_pair("valid-until-max", false)));
mapping.insert(std::make_pair("Check-Date", std::make_pair("check-date", false)));
mapping.insert(std::make_pair("Date-Max-Future", std::make_pair("date-max-future", false)));
+ mapping.insert(std::make_pair("Snapshot", std::make_pair("snapshot", false)));
mapping.insert(std::make_pair("Signed-By", std::make_pair("signed-by", false)));
mapping.insert(std::make_pair("PDiffs", std::make_pair("pdiffs", false)));
mapping.insert(std::make_pair("By-Hash", std::make_pair("by-hash", false)));
diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc
index f607c4ccc..980d00530 100644
--- a/apt-private/private-cmndline.cc
+++ b/apt-private/private-cmndline.cc
@@ -88,6 +88,7 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons
addArg('g', "generate", "APT::Cache::Generate", 0);
addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg);
addArg('t', "default-release", "APT::Default-Release", CommandLine::HasArg);
+ addArg('S', "snapshot", "APT::Snapshot", CommandLine::HasArg);
addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg);
addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg);
@@ -189,13 +190,15 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
addArg(0, "reinstall", "APT::Get::ReInstall", 0);
addArg(0, "solver", "APT::Solver", CommandLine::HasArg);
addArg(0, "planner", "APT::Planner", CommandLine::HasArg);
+ addArg('U', "update", "APT::Update", 0);
if (CmdMatches("upgrade"))
{
addArg(0, "new-pkgs", "APT::Get::Upgrade-Allow-New",
CommandLine::Boolean);
}
}
- else if (CmdMatches("update"))
+
+ else if (CmdMatches("update") || CmdMatches("install"))
{
addArg(0, "list-cleanup", "APT::Get::List-Cleanup", 0);
addArg(0, "allow-insecure-repositories", "Acquire::AllowInsecureRepositories", 0);
@@ -267,6 +270,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const
addArg('m',"ignore-missing","APT::Get::Fix-Missing",0);
addArg('t',"target-release","APT::Default-Release",CommandLine::HasArg);
addArg('t',"default-release","APT::Default-Release",CommandLine::HasArg);
+ addArg('S', "snapshot", "APT::Snapshot", CommandLine::HasArg);
addArg(0,"download","APT::Get::Download",0);
addArg(0,"fix-missing","APT::Get::Fix-Missing",0);
addArg(0,"ignore-hold","APT::Ignore-Hold",0);
diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc
index 08d58a53c..13ed35e2a 100644
--- a/apt-private/private-install.cc
+++ b/apt-private/private-install.cc
@@ -36,6 +36,7 @@
#include <apt-private/private-install.h>
#include <apt-private/private-json-hooks.h>
#include <apt-private/private-output.h>
+#include <apt-private/private-update.h>
#include <apti18n.h>
/*}}}*/
@@ -852,6 +853,10 @@ struct PkgIsExtraInstalled {
bool DoInstall(CommandLine &CmdL)
{
CacheFile Cache;
+
+ if (_config->FindB("APT::Update") && not DoUpdate())
+ return false;
+
Cache.InhibitActionGroups(true);
if (Cache.BuildSourceList() == false)
return false;
diff --git a/apt-private/private-update.cc b/apt-private/private-update.cc
index f1734fea2..d6f7d62dd 100644
--- a/apt-private/private-update.cc
+++ b/apt-private/private-update.cc
@@ -51,7 +51,11 @@ bool DoUpdate(CommandLine &CmdL)
{
if (CmdL.FileSize() != 1)
return _error->Error(_("The update command takes no arguments"));
+ return DoUpdate();
+}
+bool DoUpdate()
+{
CacheFile Cache;
// Get the source list
diff --git a/apt-private/private-update.h b/apt-private/private-update.h
index e584f70cf..8ca706c55 100644
--- a/apt-private/private-update.h
+++ b/apt-private/private-update.h
@@ -6,5 +6,6 @@
class CommandLine;
APT_PUBLIC bool DoUpdate(CommandLine &CmdL);
+APT_PUBLIC bool DoUpdate();
#endif
diff --git a/apt-private/private-upgrade.cc b/apt-private/private-upgrade.cc
index 97603dc16..143879fe6 100644
--- a/apt-private/private-upgrade.cc
+++ b/apt-private/private-upgrade.cc
@@ -11,6 +11,7 @@
#include <apt-private/private-install.h>
#include <apt-private/private-json-hooks.h>
#include <apt-private/private-output.h>
+#include <apt-private/private-update.h>
#include <apt-private/private-upgrade.h>
#include <iostream>
@@ -21,6 +22,9 @@
// this is actually performing the various upgrade operations
static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags)
{
+ if (_config->FindB("APT::Update") && not DoUpdate())
+ return false;
+
CacheFile Cache;
auto VolatileCmdL = GetPseudoPackages(Cache.GetSourceList(), CmdL, AddVolatileBinaryFile, "");
diff --git a/doc/apt-get.8.xml b/doc/apt-get.8.xml
index 6d28fe116..beecfd27c 100644
--- a/doc/apt-get.8.xml
+++ b/doc/apt-get.8.xml
@@ -528,6 +528,16 @@
Configuration Item: <literal>APT::Get::List-Cleanup</literal>.</para></listitem>
</varlistentry>
+ <varlistentry><term><option>-S</option></term>
+ <term><option>--snapshot</option></term>
+ <listitem><para>This option controls the snapshot chosen for archives with <literal>Snapshot: enable</literal>
+ in the source entry. For example, <option>-S 20220102T030405Z</option> selects a snapshot from January 2nd,
+ 2022 at 03:04:05 UTC.
+ Configuration Item: <literal>APT::Snapshot</literal>;
+ see also the &sources-list; manual page.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry><term><option>-t</option></term>
<term><option>--target-release</option></term>
<term><option>--default-release</option></term>
@@ -657,6 +667,20 @@
<listitem><para>Fail the update command if any error occured, even a transient one.</para></listitem>
</varlistentry>
+ <varlistentry><term><option>-U</option></term><term><option>--update</option></term>
+ <listitem><para>Run the <option>update</option> command before the specified command. This is supported for commands
+ installing, removing, or upgrading packages such as
+ <option>install</option>, <option>remove</option>, <option>safe-upgrade</option>, <option>full-upgrade</option>.
+ This can be useful to ensure a command always installs the latest versions, or, in combination with the
+ <option>--snapshot</option> option to make sure the snapshot is present when install is being run.
+ </para>
+ <para>Caveat: Due to technical limitations, locks are acquired individually for each phase, hence an install
+ may fail to acquire locks after successfully executing the update. Until this is resolved, this is merely
+ syntactic sugar for <literal>apt update &amp;&amp; apt install</literal></para>
+ </listitem>
+ </varlistentry>
+
+
&apt-commonoptions;
</variablelist>
diff --git a/doc/apt.conf.5.xml b/doc/apt.conf.5.xml
index 189fb7d7d..e815a58a1 100644
--- a/doc/apt.conf.5.xml
+++ b/doc/apt.conf.5.xml
@@ -211,6 +211,10 @@ APT::Compressor::rev {
version is available. Contains release name, codename or release version. Examples: 'stable', 'testing',
'unstable', '&debian-stable-codename;', '&debian-testing-codename;', '4.0', '5.0*'. See also &apt-preferences;.</para></listitem>
</varlistentry>
+ <varlistentry><term><option>Snapshot</option></term>
+ <listitem><para>Snapshot to use for all repositories configured with <literal>Snapshot: yes</literal>. See also &sources-list;, the <option>--snapshot</option> option that sets this value, and <option>Acquire::Snapshots::URI</option> below.</para></listitem>
+ </varlistentry>
+
<varlistentry><term><option>Ignore-Hold</option></term>
<listitem><para>Ignore held packages; this global option causes the problem resolver to
@@ -647,6 +651,26 @@ APT::Compressor::rev {
this source can't be used to acquire changelog files from. Another source will be tried
if available in this case.
</para></listitem>
+</varlistentry>
+
+ <varlistentry><term><option>Snapshots::URI</option> scope</term>
+ <listitem><para>
+ Like changelogs, snapshots can only be acquired if an URI is known from where to get them.
+ Preferable the Release file indicates this in a 'Snapshots' field. If this isn't
+ available the Label/Origin field of the Release file is used to check if a
+ <literal>Acquire::Snapshots::URI::Label::<replaceable>LABEL</replaceable></literal> or
+ <literal>Acquire::Snapshots::URI::Origin::<replaceable>ORIGIN</replaceable></literal> option
+ exists and if so this value is taken. The value in the Release file can be overridden
+ with <literal>Acquire::Snapshots::URI::Override::Label::<replaceable>LABEL</replaceable></literal>
+ or <literal>Acquire::Snapshots::URI::Override::Origin::<replaceable>ORIGIN</replaceable></literal>.
+
+ The value should be a normal URI to a directory, except that the snapshot ID replaced with the
+ placeholder <literal>@SNAPSHOTID</literal>.
+
+ The special value '<literal>no</literal>' is available for this option indicating that
+ this source cannot be used to acquire snapshots from. Another source will be tried
+ if available in this case.
+ </para></listitem>
</varlistentry>
</variablelist>
diff --git a/doc/examples/configure-index b/doc/examples/configure-index
index beafbbcd4..e6d7c31ea 100644
--- a/doc/examples/configure-index
+++ b/doc/examples/configure-index
@@ -59,6 +59,9 @@ APT
VersionedKernelPackages "<LIST>"; // regular expressions to be protected from autoremoval (kernel uname will be appended)
Protect-Kernels "<BOOL>"; // whether to protect installed kernels against autoremoval (default: true)
+ // Currently active snapshot
+ Snapshot "<STRING>";
+
// Options for apt-get
Get
{
@@ -170,7 +173,7 @@ APT
DropTranslation "<BOOL>";
};
- Update
+ Update "<BOOL>"
{
Pre-Invoke {"touch /var/lib/apt/pre-update-stamp"; };
Post-Invoke {"touch /var/lib/apt/post-update-stamp"; };
@@ -398,6 +401,14 @@ Acquire
Override::Origin::* "<STRING>";
Override::Label::* "<STRING>";
};
+ Snapshots::URI
+ {
+ // Origin::Debian "https://snapshot.debian.org/snapshot/@SNAPSHOTID@/";
+ Origin::* "<STRING>";
+ Label::* "<STRING>";
+ Override::Origin::* "<STRING>";
+ Override::Label::* "<STRING>";
+ };
Changelogs::AlwaysOnline "<BOOL>"; // even if the changelog file exists get it online (as the file is incomplete)
Changelogs::AlwaysOnline::Origin::* "<BOOL>";
};
diff --git a/doc/sources.list.5.xml b/doc/sources.list.5.xml
index 478694c77..4fa7a245b 100644
--- a/doc/sources.list.5.xml
+++ b/doc/sources.list.5.xml
@@ -392,6 +392,23 @@ Signed-By:
or, if that fails, a <filename>Release</filename> file and its associated <filename>Release.gpg</filename> file. By setting this option,
the specified path will be tried instead of the InRelease file,
and the fallback to <filename>Release</filename> files will be disabled.
+ </para></listitem>
+
+ <listitem><para><option>Snapshot</option> (<option>snapshot</option>)
+ allows selecting an earlier version of the archive from the snapshot service. Supported
+ values are: </para>
+ <itemizedlist>
+ <listitem>
+ <para><literal>enable</literal> to allow selecting a snapshot with the <option>--snapshot</option> option, or</para>
+ </listitem>
+ <listitem>
+ <para>a snapshot ID to select a specific snapshot.</para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Snapshot IDs are usually timestamps in the form of <literal>YYYYMMDDTHHMMSSZ</literal>, such as
+ <literal>20220102T030405Z</literal> which is the January 2nd, 2022 at 03:04:05 UTC, servers may
+ however support additional types of IDs, and APT does not perform any checks so far.
</para></listitem>
</itemizedlist>
diff --git a/test/integration/test-apt-get-install-update b/test/integration/test-apt-get-install-update
new file mode 100755
index 000000000..33be6e3c7
--- /dev/null
+++ b/test/integration/test-apt-get-install-update
@@ -0,0 +1,111 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+
+setupenvironment
+configarchitecture 'amd64'
+
+buildsimplenativepackage 'awesome' 'native' '42' 'stable'
+buildsimplenativepackage 'foo' 'all' '1.0' 'stable'
+buildsimplenativepackage 'libbar' 'all' '1.0' 'stable'
+
+setupaptarchive --no-update
+changetowebserver
+testfailureequal "Reading package lists...
+Building dependency tree...
+E: Unable to locate package awesome" aptget install awesome -s
+
+msgmsg "apt-get {install,remove} {-U, --update}"
+for command in install remove; do
+ for option in -U --update; do
+testsuccessequal "Get:1 http://localhost:${APTHTTPPORT} stable InRelease [$(stat -c %s aptarchive/dists/stable/InRelease) B]
+Get:2 http://localhost:${APTHTTPPORT} stable/main Sources [$(stat -c %s aptarchive/dists/stable/main/source/Sources.gz) B]
+Get:3 http://localhost:${APTHTTPPORT} stable/main amd64 Packages [$(stat -c %s aptarchive/dists/stable/main/binary-amd64/Packages.gz) B]
+Get:4 http://localhost:${APTHTTPPORT} stable/main all Packages [$(stat -c %s aptarchive/dists/stable/main/binary-all/Packages.gz) B]
+Get:5 http://localhost:${APTHTTPPORT} stable/main Translation-en [$(stat -c %s aptarchive/dists/stable/main/i18n/Translation-en.gz) B]
+Reading package lists...
+Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+ awesome
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst awesome (42 stable [amd64])
+Conf awesome (42 stable [amd64])" \
+ aptget $command $option awesome+ -s
+ find rootdir/var/lib/apt/lists/ -type f -delete
+ done
+done
+
+msgmsg "apt {install,remove} {-U, --update}"
+
+for command in install remove; do
+ for option in -U --update; do
+testsuccessequal "Get:1 http://localhost:${APTHTTPPORT} stable InRelease [$(stat -c %s aptarchive/dists/stable/InRelease) B]
+Get:2 http://localhost:${APTHTTPPORT} stable/main Sources [$(stat -c %s aptarchive/dists/stable/main/source/Sources.gz) B]
+Get:3 http://localhost:${APTHTTPPORT} stable/main amd64 Packages [$(stat -c %s aptarchive/dists/stable/main/binary-amd64/Packages.gz) B]
+Get:4 http://localhost:${APTHTTPPORT} stable/main all Packages [$(stat -c %s aptarchive/dists/stable/main/binary-all/Packages.gz) B]
+Get:5 http://localhost:${APTHTTPPORT} stable/main Translation-en [$(stat -c %s aptarchive/dists/stable/main/i18n/Translation-en.gz) B]
+Reading package lists...
+Building dependency tree...
+All packages are up to date.
+Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+ awesome
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst awesome (42 stable [amd64])
+Conf awesome (42 stable [amd64])" \
+ apt $command $option awesome+ -s
+ find rootdir/var/lib/apt/lists/ -type f -delete
+ done
+done
+
+msgmsg "apt-get *upgrade {-U, --update}"
+
+for command in upgrade dist-upgrade full-upgrade; do
+ for option in -U --update; do
+testsuccessequal "Get:1 http://localhost:${APTHTTPPORT} stable InRelease [$(stat -c %s aptarchive/dists/stable/InRelease) B]
+Get:2 http://localhost:${APTHTTPPORT} stable/main Sources [$(stat -c %s aptarchive/dists/stable/main/source/Sources.gz) B]
+Get:3 http://localhost:${APTHTTPPORT} stable/main amd64 Packages [$(stat -c %s aptarchive/dists/stable/main/binary-amd64/Packages.gz) B]
+Get:4 http://localhost:${APTHTTPPORT} stable/main all Packages [$(stat -c %s aptarchive/dists/stable/main/binary-all/Packages.gz) B]
+Get:5 http://localhost:${APTHTTPPORT} stable/main Translation-en [$(stat -c %s aptarchive/dists/stable/main/i18n/Translation-en.gz) B]
+Reading package lists...
+Reading package lists...
+Building dependency tree...
+Calculating upgrade...
+The following NEW packages will be installed:
+ awesome
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst awesome (42 stable [amd64])
+Conf awesome (42 stable [amd64])" \
+ aptget $command $option awesome -s
+ find rootdir/var/lib/apt/lists/ -type f -delete
+ done
+done
+
+msgmsg "apt *upgrade {-U, --update}"
+
+for command in upgrade dist-upgrade full-upgrade; do
+ for option in -U --update; do
+testsuccessequal "Get:1 http://localhost:${APTHTTPPORT} stable InRelease [$(stat -c %s aptarchive/dists/stable/InRelease) B]
+Get:2 http://localhost:${APTHTTPPORT} stable/main Sources [$(stat -c %s aptarchive/dists/stable/main/source/Sources.gz) B]
+Get:3 http://localhost:${APTHTTPPORT} stable/main amd64 Packages [$(stat -c %s aptarchive/dists/stable/main/binary-amd64/Packages.gz) B]
+Get:4 http://localhost:${APTHTTPPORT} stable/main all Packages [$(stat -c %s aptarchive/dists/stable/main/binary-all/Packages.gz) B]
+Get:5 http://localhost:${APTHTTPPORT} stable/main Translation-en [$(stat -c %s aptarchive/dists/stable/main/i18n/Translation-en.gz) B]
+Reading package lists...
+Building dependency tree...
+All packages are up to date.
+Reading package lists...
+Building dependency tree...
+Calculating upgrade...
+The following NEW packages will be installed:
+ awesome
+0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+Inst awesome (42 stable [amd64])
+Conf awesome (42 stable [amd64])" \
+ apt $command $option awesome -s
+ find rootdir/var/lib/apt/lists/ -type f -delete
+ done
+done
diff --git a/test/integration/test-snapshot b/test/integration/test-snapshot
new file mode 100755
index 000000000..609e3ade0
--- /dev/null
+++ b/test/integration/test-snapshot
@@ -0,0 +1,191 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+
+setupenvironment
+configarchitecture 'amd64'
+
+buildsimplenativepackage 'awesome' 'native' '42' 'stable'
+buildsimplenativepackage 'foo' 'all' '1.0' 'stable'
+buildsimplenativepackage 'libbar' 'all' '1.0' 'stable'
+
+getlabelfromsuite() { echo 'Testcases'; }
+getoriginfromsuite() { echo 'Debian'; }
+
+setupaptarchive --no-update
+changetowebserver
+testsuccess aptget update
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris --snapshot OPTIONNOTSET
+
+# Enable the snapshot feature
+sed -i 's/http:/[snapshot=enable] http:/' rootdir/etc/apt/sources.list.d/*
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris
+
+for option in -S --snapshot; do
+testsuccessequal "'https://snapshot.debian.org/archive/debian/BANANA/dists/stable/InRelease' snapshot.debian.org_archive_debian_BANANA_dists_stable_InRelease 0
+'https://snapshot.debian.org/archive/debian/BANANA/dists/stable/main/source/Sources.xz' snapshot.debian.org_archive_debian_BANANA_dists_stable_main_source_Sources 0
+'https://snapshot.debian.org/archive/debian/BANANA/dists/stable/main/binary-amd64/Packages.xz' snapshot.debian.org_archive_debian_BANANA_dists_stable_main_binary-amd64_Packages 0
+'https://snapshot.debian.org/archive/debian/BANANA/dists/stable/main/binary-all/Packages.xz' snapshot.debian.org_archive_debian_BANANA_dists_stable_main_binary-all_Packages 0
+'https://snapshot.debian.org/archive/debian/BANANA/dists/stable/main/i18n/Translation-en.xz' snapshot.debian.org_archive_debian_BANANA_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris $option BANANA
+done
+
+
+# Let us update for realz
+mkdir aptarchive/snapshot/BANANA -p
+cp -a aptarchive/dists aptarchive/snapshot/BANANA
+
+testsuccessequal "Hit:1 http://localhost:${APTHTTPPORT} stable InRelease
+Get:2 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable InRelease [$(stat -c %s aptarchive/dists/stable/InRelease) B]
+Get:3 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main Sources [$(stat -c %s aptarchive/dists/stable/main/source/Sources.gz) B]
+Get:4 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main amd64 Packages [$(stat -c %s aptarchive/dists/stable/main/binary-amd64/Packages.gz) B]
+Get:5 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main all Packages [$(stat -c %s aptarchive/dists/stable/main/binary-all/Packages.gz) B]
+Get:6 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main Translation-en [$(stat -c %s aptarchive/dists/stable/main/i18n/Translation-en.gz) B]
+Reading package lists..." \
+ aptget update -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/" -SBANANA
+
+msgmsg "Cache constructed without snapshot"
+testsuccessequal "Package files:
+ 500 http://localhost:${APTHTTPPORT} stable/main all Packages
+ release o=Debian,a=stable,n=stable,l=Testcases,c=main,b=all
+ origin localhost
+ 500 http://localhost:${APTHTTPPORT} stable/main amd64 Packages
+ release o=Debian,a=stable,n=stable,l=Testcases,c=main,b=amd64
+ origin localhost
+Pinned packages:" \
+ aptcache policy -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/"
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/pool/awesome_42_amd64.deb' awesome_42_amd64.deb $(stat -c %s aptarchive/pool/awesome_42_amd64.deb) " \
+ aptget install --print-uris -qq awesome
+
+msgmsg "Cache constructed with snapshot"
+testsuccessequal "Package files:
+ 500 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main all Packages
+ release o=Debian,a=stable,n=stable,l=Testcases,c=main,b=all
+ origin localhost
+ 500 http://localhost:${APTHTTPPORT}/snapshot/BANANA stable/main amd64 Packages
+ release o=Debian,a=stable,n=stable,l=Testcases,c=main,b=amd64
+ origin localhost
+Pinned packages:" \
+ aptcache policy -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/" -SBANANA
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/snapshot/BANANA/pool/awesome_42_amd64.deb' awesome_42_amd64.deb $(stat -c %s aptarchive/pool/awesome_42_amd64.deb) " \
+ aptget install --print-uris -qq awesome -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/" -SBANANA
+
+
+releasechanger() {
+ # modifying the Release files in lists… bad stuff. Good that this is only a test…
+ sed -i "s#^${1}: .*#${1}: ${2}#" $(find rootdir/var/lib/apt/lists -name '*Release')
+ rm -f rootdir/var/cache/apt/*.bin
+}
+
+msgmsg "Origin: Ubuntu"
+releasechanger 'Origin' 'Ubuntu'
+testsuccessequal "'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/InRelease' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_InRelease 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/source/Sources.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_source_Sources 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/binary-amd64/Packages.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_binary-amd64_Packages 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/binary-all/Packages.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_binary-all_Packages 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/i18n/Translation-en.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris $option BANANA
+
+msgmsg "Label: Debian"
+releasechanger 'Label' 'Debian'
+testsuccessequal "'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/InRelease' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_InRelease 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/source/Sources.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_source_Sources 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/binary-amd64/Packages.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_binary-amd64_Packages 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/binary-all/Packages.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_binary-all_Packages 0
+'https://snapshot.ubuntu.com/ubuntu/BANANA/dists/stable/main/i18n/Translation-en.xz' snapshot.ubuntu.com_ubuntu_BANANA_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris $option BANANA
+
+testsuccessequal "'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/InRelease' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris -o Acquire::Snapshots::URI::Label::Debian="http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/" -SBANANA
+
+msgmsg "Snapshots: set in the InRelease file"
+sed -i '/^Origin: / a\
+Snapshots: https://example.org/snapshots/@SNAPSHOTID@/' $(find rootdir/var/lib/apt/lists -name '*Release')
+rm -f rootdir/var/cache/apt/*.bin
+
+testsuccessequal "'https://example.org/snapshots/BANANA/dists/stable/InRelease' example.org_snapshots_BANANA_dists_stable_InRelease 0
+'https://example.org/snapshots/BANANA/dists/stable/main/source/Sources.xz' example.org_snapshots_BANANA_dists_stable_main_source_Sources 0
+'https://example.org/snapshots/BANANA/dists/stable/main/binary-amd64/Packages.xz' example.org_snapshots_BANANA_dists_stable_main_binary-amd64_Packages 0
+'https://example.org/snapshots/BANANA/dists/stable/main/binary-all/Packages.xz' example.org_snapshots_BANANA_dists_stable_main_binary-all_Packages 0
+'https://example.org/snapshots/BANANA/dists/stable/main/i18n/Translation-en.xz' example.org_snapshots_BANANA_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris -SBANANA
+
+releasechanger 'Snapshots' 'no'
+testfailuremsg "E: Snapshots not supported for http://localhost:${APTHTTPPORT}/ stable
+E: Snapshots not supported for http://localhost:${APTHTTPPORT}/ stable
+E: The list of sources could not be read." aptget update --print-uris -S BANANA
+
+msgmsg "Snapshot URI configured in apt.conf"
+sed -i '/^Snapshots: / d' $(find rootdir/var/lib/apt/lists -name '*Release')
+releasechanger 'Label' 'Testcases'
+
+echo "Acquire::Snapshots::URI::Label::Testcases \"http://localhost:${APTHTTPPORT}/snapshot/@SNAPSHOTID@/\";" > rootdir/etc/apt/apt.conf.d/changelog.conf
+testsuccessequal "'http://localhost:${APTHTTPPORT}/dists/stable/InRelease' localhost:${APTHTTPPORT}_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/InRelease' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_InRelease 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_dists_stable_main_i18n_Translation-en 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/source/Sources.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_source_Sources 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/binary-amd64/Packages.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_binary-amd64_Packages 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/binary-all/Packages.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_binary-all_Packages 0
+'http://localhost:${APTHTTPPORT}/snapshot/BANANA/dists/stable/main/i18n/Translation-en.xz' localhost:${APTHTTPPORT}_snapshot_BANANA_dists_stable_main_i18n_Translation-en 0 " aptget update --print-uris -SBANANA
+
+rm rootdir/etc/apt/apt.conf.d/changelog.conf
+
+exit 0
+msgmsg "Failure cases"
+
+# no @CHANGEPATH@ in the URI
+testequal 'E: Failed to fetch changelog:/foo.changelog Changelog unavailable for foo=1.0' \
+ aptget update -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/snapshot" -SBANANA
+
+testequal "E: Failed to fetch http://localhost:${APTHTTPPORT}/does/not/exist/main/f/foo/foo_1.0/change.txt Changelog unavailable for foo=1.0 (404 Not Found)" \
+ aptget update -o Acquire::Snapshots::URI::Label::Testcases="http://localhost:${APTHTTPPORT}/does/not/exist/@SNAPSHOTID@" -SBANANA
+
+
+