[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#854381: unblock: apt/1.4~rc1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package apt

(deity@l.d.o is in the X-Debbugs-CC, would be great to
 have that in replies.)

Apart from the changes below, it also includes translation
updates, a more up-to-date GPL (address, year, and formatting),
a whole lot of typo fixes, and a few adjustments to the test-
suite.

I attached two diffs: One full xz-compressed, and a cleaned
up one that does not contain typo fixes and translation
updates.

This was intended to go in before the freeze, but we had
to give the architecture wildcard fix some time alone so
it could figure out if its OK.

+apt (1.4~rc1) unstable; urgency=medium
+
+  [ David Kalnischkies ]
+  * don't show update stats if cache generation is disabled

   We'd end up generating a cache file to show the stats even
   if asked not to. That's not nice.

+  * don't lock dpkg in 'apt-get clean'
+  * don't lock dpkg in update commands

=> these fix locking races of update/clean with an apt-pkg process
   running dpkg (dpkg lock is released before running dpkg and locked
   again afterwards, so there is a short period where dpkg is unlocked
   and an update or clean in that period could cause such a process to
   break). 

   I'm working on a more complete solution called dpkg frontend locking,
   see https://lists.debian.org/debian-dpkg/2017/01/msg00044.html for
   more details if you are interested.

+  * avoid validate/delete/load race in cache generation

   Keeps the file descriptor of the cache around instead of re-opening
   it from the file, fixing some races with clean.

+  * fix 'install --no-download' mode

    As the name says, this did not work.

+  * remove 'old' FAILED files in the next acquire call (Closes: 846476)

    Makes your disk space great again.

+  * stop rred from leaking debug messages on recovered errors (Closes: #850759)

   Only print out some debugging messages if debugging is enabled. It's only
   wishlist, but then it's also only 3 lines added: one if for each output
   line.

+  * make the moo reproducible.
+    Thanks to Chris Lamb for initial patch and guru meditation (Closes: #848721)

   Makes moo great again.

+  * update release mappings in documentation

   Would be broken if we used the wrong distribution name in our
   examples.

+  * avoid malloc if option whitelist is disabled (default)

   Reduces changes that apt crashes when a terminal window is resized
   due to malloc in the SIGWNCH handler

+
+  [ Julian Andres Klode ]
+  * basehttp: Only read Content-Range on 416 and 206 responses (LP: #1657567)

   Addresses weird HTTP servers like Sourceforge that include a
   Content-Range on a 302 request, causing APT to fail because
   it did not understand the message.

+  * test suite: Do not exit 0 in trap for QUIT

   Makes the test suite fail again if stuff is broken! Actually kind of
   boring to include in debian/changelog...

+  * Only merge acquire items with the same meta key (Closes: #838441)

   Fixes a weird bunch of problems with the fetching of by-hash
   repositories where some files have the same hash. APT would
   previously only download them once (because it compares the
   actual by-hash URI), despite them being downloaded to two
   different locations on-disk. And of course, that thing broke
   when renaming stuff, causing failures in update.

   (This has even been tested for more than a week in Ubuntu,
    as we needed to unbreak KUbuntu's alpha2 release...)

unblock apt/1.4~rc1

-- System Information:
Debian Release: 9.0
  APT prefers unstable
  APT policy: (900, 'unstable'), (500, 'unstable-debug'), (500, 'buildd-unstable'), (500, 'testing'), (100, 'experimental'), (1, 'experimental-debug')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.9.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_IE.UTF-8, LC_CTYPE=en_IE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)

-- 
Debian Developer - deb.li/jak | jak-linux.org - free software dev
                  |  Ubuntu Core Developer |
When replying, only quote what is necessary, and write each reply
directly below the part(s) it pertains to ('inline').  Thank you.
diff --git a/.gitignore b/.gitignore
index ae327080a..9712a034d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,6 +73,7 @@ docbook-text-style.xsl
 **/test/interactive-helper/mthdcat
 **/test/interactive-helper/test_fileutl
 **/test/interactive-helper/test_udevcdrom
+**/test/interactive-helper/aptdropprivs
 **/test/libapt/libapt_test
 
 # Documentation
diff --git a/.travis.yml b/.travis.yml
index 192573e7d..023107a68 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,9 @@ language: cpp
 cache: ccache
 sudo: required
 dist: trusty
+env:
+ - TEST_SUITE=user CMAKE_FLAGS=
+ - TEST_SUITE=root CMAKE_FLAGS=-DWITH_DOC=OFF
 before_install:
  - sudo add-apt-repository 'deb http://archive.ubuntu.com/ubuntu/ wily main universe' -y
  - sudo add-apt-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial main' -y
@@ -14,16 +17,16 @@ install:
  - sudo apt-get -qq -y -t xenial install cmake ninja-build
  - sudo ./prepare-release travis-ci
 before_script:
- - ( mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Coverage -G Ninja .. )
+ - ( mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Coverage -G Ninja $CMAKE_FLAGS .. )
  - ninja -C build
 script:
  - CTEST_OUTPUT_ON_FAILURE=1 ninja -C build test
  - DESTDIR=$PWD/rootdir chronic ninja -C build install
- - ./test/integration/run-tests -qq
+ - test "$TEST_SUITE" != "user"  || ./test/integration/run-tests -qq
  - sudo adduser --force-badname --system --home /nonexistent --no-create-home --quiet _apt || true
  - sudo chmod  go+x /home/travis
  - sudo chmod -R go+rwX /home/travis/build
- - sudo ./test/integration/run-tests -qq
+ - test "$TEST_SUITE" != "root" || sudo ./test/integration/run-tests -qq
 after_script:
  - cd build
  - gcov -r $(find -name '*.gcno')
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6ef0fead..e9b5a0a19 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,7 +172,7 @@ endif()
 # Configure some variables like package, version and architecture.
 set(PACKAGE ${PROJECT_NAME})
 set(PACKAGE_MAIL "APT Development Team <deity@lists.debian.org>")
-set(PACKAGE_VERSION "1.4~beta4")
+set(PACKAGE_VERSION "1.4~rc1")
 
 if (NOT DEFINED DPKG_DATADIR)
   execute_process(COMMAND ${PERL_EXECUTABLE} -MDpkg -e "print $Dpkg::DATADIR;"
diff --git a/COPYING.GPL b/COPYING.GPL
index 60549be51..d159169d1 100644
--- a/COPYING.GPL
+++ b/COPYING.GPL
@@ -1,12 +1,12 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
-			    Preamble
+                            Preamble
 
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users.  This
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-
-		    GNU GENERAL PUBLIC LICENSE
+
+                    GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
   0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this.  Our decision will be guided by the two goals
 of preserving the free status of all derivatives of our free software and
 of promoting the sharing and reuse of software generally.
 
-			    NO WARRANTY
+                            NO WARRANTY
 
   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.
 
-		     END OF TERMS AND CONDITIONS
-
-	    How to Apply These Terms to Your New Programs
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
 possible use to the public, the best way to achieve this is to make it
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
+    Copyright (C) <year>  <name of author>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -336,5 +335,5 @@ necessary.  Here is a sample; alter the names:
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc
index ac925e72e..b62c50c00 100644
--- a/apt-pkg/acquire.cc
+++ b/apt-pkg/acquire.cc
@@ -117,6 +117,12 @@ static bool SetupAPTPartialDirectory(std::string const &grand, std::string const
    if (chmod(partial.c_str(), 0700) != 0)
       _error->WarningE("SetupAPTPartialDirectory", "chmod 0700 of directory %s failed", partial.c_str());
 
+   _error->PushToStack();
+   // remove 'old' FAILED files to stop us from collecting them for no reason
+   for (auto const &Failed: GetListOfFilesInDir(partial, "FAILED", false, false))
+      RemoveFile("SetupAPTPartialDirectory", Failed);
+   _error->RevertToStack();
+
    return true;
 }
 bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock)
@@ -894,11 +900,27 @@ pkgAcquire::Queue::~Queue()
 /* */
 bool pkgAcquire::Queue::Enqueue(ItemDesc &Item)
 {
+   // MetaKeysMatch checks whether the two items have no non-matching
+   // meta-keys. If the items are not transaction items, it returns
+   // true, so other items can still be merged.
+   auto MetaKeysMatch = [](pkgAcquire::ItemDesc const &A, pkgAcquire::Queue::QItem const *B) {
+      auto OwnerA = dynamic_cast<pkgAcqTransactionItem*>(A.Owner);
+      if (OwnerA == nullptr)
+	 return true;
+
+      for (auto const & OwnerBUncast : B->Owners) {
+	 auto OwnerB = dynamic_cast<pkgAcqTransactionItem*>(OwnerBUncast);
+
+	 if (OwnerB != nullptr && OwnerA->GetMetaKey() != OwnerB->GetMetaKey())
+	    return false;
+      }
+      return true;
+   };
    QItem **OptimalI = &Items;
    QItem **I = &Items;
    // move to the end of the queue and check for duplicates here
    for (; *I != 0; ) {
-      if (Item.URI == (*I)->URI)
+      if (Item.URI == (*I)->URI && MetaKeysMatch(Item, *I))
       {
 	 if (_config->FindB("Debug::pkgAcquire::Worker",false) == true)
 	    std::cerr << " @ Queue: Action combined for " << Item.URI << " and " << (*I)->URI << std::endl;
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
index 13d678539..64062f7a4 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -92,10 +92,9 @@ static ConfigType getConfigType(std::string const &type)		/*{{{*/
    return ConfigType::UNDEFINED;
 }
 									/*}}}*/
-static void checkFindConfigOptionType(std::string name, ConfigType const type)/*{{{*/
+// checkFindConfigOptionType - workhorse of option checking		/*{{{*/
+static void checkFindConfigOptionTypeInternal(std::string name, ConfigType const type)
 {
-   if (apt_known_config.empty())
-      return;
    std::transform(name.begin(), name.end(), name.begin(), ::tolower);
    auto known = apt_known_config.find(name);
    if (known == apt_known_config.cend())
@@ -152,6 +151,12 @@ static void checkFindConfigOptionType(std::string name, ConfigType const type)/*
 	       name.c_str(), getConfigTypeString(known->second).c_str(), getConfigTypeString(type).c_str());
    }
 }
+static void checkFindConfigOptionType(char const * const name, ConfigType const type)
+{
+   if (apt_known_config.empty())
+      return;
+   checkFindConfigOptionTypeInternal(name, type);
+}
 									/*}}}*/
 static bool LoadConfigurationIndex(std::string const &filename)		/*{{{*/
 {
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index 107f1f141..e52667fbc 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -1363,24 +1363,27 @@ public:
    ScopedErrorRevert() { _error->PushToStack(); }
    ~ScopedErrorRevert() { _error->RevertToStack(); }
 };
-static bool CheckValidity(const string &CacheFile,
+static bool CheckValidity(FileFd &CacheFile, std::string const &CacheFileName,
                           pkgSourceList &List,
                           FileIterator const Start,
                           FileIterator const End,
                           MMap **OutMap = 0,
 			  pkgCache **OutCache = 0)
 {
+   if (CacheFileName.empty())
+      return false;
    ScopedErrorRevert ser;
+
    bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
    // No file, certainly invalid
-   if (CacheFile.empty() == true || FileExists(CacheFile) == false)
+   if (CacheFile.Open(CacheFileName, FileFd::ReadOnly, FileFd::None) == false)
    {
       if (Debug == true)
-	 std::clog << "CacheFile " << CacheFile << " doesn't exist" << std::endl;
+	 std::clog << "CacheFile " << CacheFileName << " doesn't exist" << std::endl;
       return false;
    }
 
-   if (List.GetLastModifiedTime() > GetModificationTime(CacheFile))
+   if (List.GetLastModifiedTime() > CacheFile.ModificationTime())
    {
       if (Debug == true)
 	 std::clog << "sources.list is newer than the cache" << std::endl;
@@ -1388,8 +1391,7 @@ static bool CheckValidity(const string &CacheFile,
    }
 
    // Map it
-   FileFd CacheF(CacheFile,FileFd::ReadOnly);
-   std::unique_ptr<MMap> Map(new MMap(CacheF,0));
+   std::unique_ptr<MMap> Map(new MMap(CacheFile,0));
    if (unlikely(Map->validData()) == false)
       return false;
    std::unique_ptr<pkgCache> CacheP(new pkgCache(Map.get()));
@@ -1397,7 +1399,7 @@ static bool CheckValidity(const string &CacheFile,
    if (_error->PendingError() || Map->Size() == 0)
    {
       if (Debug == true)
-	 std::clog << "Errors are pending or Map is empty() for " << CacheFile << std::endl;
+	 std::clog << "Errors are pending or Map is empty() for " << CacheFileName << std::endl;
       return false;
    }
 
@@ -1623,13 +1625,12 @@ static bool writeBackMMapToFile(pkgCacheGenerator * const Gen, DynamicMMap * con
    return true;
 }
 static bool loadBackMMapFromFile(std::unique_ptr<pkgCacheGenerator> &Gen,
-      std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, std::string const &FileName)
+      std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, FileFd &CacheF)
 {
    Map.reset(CreateDynamicMMap(NULL, 0));
    if (unlikely(Map->validData()) == false)
       return false;
-   FileFd CacheF(FileName, FileFd::ReadOnly);
-   if (CacheF.IsOpen() == false || CacheF.Failed())
+   if (CacheF.IsOpen() == false || CacheF.Seek(0) == false || CacheF.Failed())
       return false;
    _error->PushToStack();
    map_pointer_t const alloc = Map->RawAllocate(CacheF.Size());
@@ -1661,20 +1662,20 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
       return false;
 
    // Decide if we can write to the files..
-   string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
-   string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
+   string const CacheFileName = _config->FindFile("Dir::Cache::pkgcache");
+   string const SrcCacheFileName = _config->FindFile("Dir::Cache::srcpkgcache");
 
    // ensure the cache directory exists
-   if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
+   if (CacheFileName.empty() == false || SrcCacheFileName.empty() == false)
    {
       string dir = _config->FindDir("Dir::Cache");
       size_t const len = dir.size();
       if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
 	 dir = dir.substr(0, len - 5);
-      if (CacheFile.empty() == false)
-	 CreateDirectory(dir, flNotFile(CacheFile));
-      if (SrcCacheFile.empty() == false)
-	 CreateDirectory(dir, flNotFile(SrcCacheFile));
+      if (CacheFileName.empty() == false)
+	 CreateDirectory(dir, flNotFile(CacheFileName));
+      if (SrcCacheFileName.empty() == false)
+	 CreateDirectory(dir, flNotFile(SrcCacheFileName));
    }
 
    if (Progress != NULL)
@@ -1683,8 +1684,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
    bool pkgcache_fine = false;
    bool srcpkgcache_fine = false;
    bool volatile_fine = List.GetVolatileFiles().empty();
-
-   if (CheckValidity(CacheFile, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL,
+   FileFd CacheFile;
+   if (CheckValidity(CacheFile, CacheFileName, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL,
 		     volatile_fine ? OutCache : NULL) == true)
    {
       if (Debug == true)
@@ -1692,9 +1693,11 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
       pkgcache_fine = true;
       srcpkgcache_fine = true;
    }
+
+   FileFd SrcCacheFile;
    if (pkgcache_fine == false)
    {
-      if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true)
+      if (CheckValidity(SrcCacheFile, SrcCacheFileName, List, Files.end(), Files.end()) == true)
       {
 	 if (Debug == true)
 	    std::clog << "srcpkgcache.bin is valid - it can be reused" << std::endl;
@@ -1712,10 +1715,10 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
    bool Writeable = false;
    if (srcpkgcache_fine == false || pkgcache_fine == false)
    {
-      if (CacheFile.empty() == false)
-	 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
-      else if (SrcCacheFile.empty() == false)
-	 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
+      if (CacheFileName.empty() == false)
+	 Writeable = access(flNotFile(CacheFileName).c_str(),W_OK) == 0;
+      else if (SrcCacheFileName.empty() == false)
+	 Writeable = access(flNotFile(SrcCacheFileName).c_str(),W_OK) == 0;
 
       if (Debug == true)
 	 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
@@ -1754,8 +1757,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
 	       Files.end(),Files.end()) == false)
 	 return false;
 
-      if (Writeable == true && SrcCacheFile.empty() == false)
-	 if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFile) == false)
+      if (Writeable == true && SrcCacheFileName.empty() == false)
+	 if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFileName) == false)
 	    return false;
    }
 
@@ -1767,8 +1770,8 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress
 	       Files.begin(), Files.end()) == false)
 	 return false;
 
-      if (Writeable == true && CacheFile.empty() == false)
-	 if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFile) == false)
+      if (Writeable == true && CacheFileName.empty() == false)
+	 if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFileName) == false)
 	    return false;
    }
 
diff --git a/apt-private/private-download.cc b/apt-private/private-download.cc
index d0cbbcf50..ee477f4cb 100644
--- a/apt-private/private-download.cc
+++ b/apt-private/private-download.cc
@@ -367,7 +367,7 @@ bool DoAutoClean(CommandLine &)
    }
 
    CacheFile Cache;
-   if (Cache.Open() == false)
+   if (Cache.Open(false) == false)
       return false;
 
    LogCleaner Cleaner;
diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc
index b49c7f2ef..73a03a828 100644
--- a/apt-private/private-install.cc
+++ b/apt-private/private-install.cc
@@ -136,16 +136,19 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
        _error->PendingError() == true)
       return false;
 
-   if (_config->FindB("APT::Get::Fix-Missing",false) == true &&
-	 _config->FindB("APT::Get::Download",true) == false)
+   if (_config->FindB("APT::Get::Download",true) == false)
    {
       bool Missing = false;
       RemoveDownloadNeedingItemsFromFetcher(Fetcher, Missing);
       if (Missing)
-	 PM->FixMissing();
+      {
+	 if (_config->FindB("APT::Get::Fix-Missing",false))
+	    PM->FixMissing();
+	 else
+	    return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?"));
+      }
       Fetcher.Shutdown();
-      if (PM->GetArchives(&Fetcher,List,&Recs) == false ||
-	    _error->PendingError() == true)
+      if (_error->PendingError() == true)
 	 return false;
    }
 
diff --git a/apt-private/private-moo.cc b/apt-private/private-moo.cc
index a87999150..b8ed6efbd 100644
--- a/apt-private/private-moo.cc
+++ b/apt-private/private-moo.cc
@@ -15,6 +15,7 @@
 
 #include <apt-private/private-moo.h>
 #include <apt-private/private-output.h>
+#include <apt-private/private-utils.h>
 
 #include <stddef.h>
 #include <string.h>
@@ -26,8 +27,8 @@
 #include <apti18n.h>
 									/*}}}*/
 
-static std::string getMooLine() {					/*{{{*/
-   time_t const timenow = time(NULL);
+static std::string getMooLine(time_t const timenow)			/*{{{*/
+{
    struct tm special;
    localtime_r(&timenow, &special);
    enum { NORMAL, PACKAGEMANAGER, APPRECIATION, AGITATION, AIRBORN } line;
@@ -64,17 +65,18 @@ static std::string getMooLine() {					/*{{{*/
    return out.str();
 }
 									/*}}}*/
-static bool printMooLine() {						/*{{{*/
-   std::cerr << getMooLine() << std::endl;
+static bool printMooLine(time_t const timenow)				/*{{{*/
+{
+   std::cerr << getMooLine(timenow);
    return true;
 }
 									/*}}}*/
-bool DoMoo1(CommandLine &)						/*{{{*/
+static bool DoMoo1(time_t const timenow)				/*{{{*/
 {
    // our trustworthy super cow since 2001
    if (_config->FindI("quiet") >= 2)
-      return printMooLine();
-   std::string const moo = getMooLine();
+      return printMooLine(timenow);
+   std::string const moo = getMooLine(timenow);
    size_t const depth = moo.length()/4;
    c1out <<
       OutputInDepth(depth, " ") << "         (__) \n" <<
@@ -87,12 +89,12 @@ bool DoMoo1(CommandLine &)						/*{{{*/
    return true;
 }
 									/*}}}*/
-bool DoMoo2(CommandLine &)						/*{{{*/
+static bool DoMoo2(time_t const timenow)				/*{{{*/
 {
    // by Fernando Ribeiro in lp:56125
    if (_config->FindI("quiet") >= 2)
-      return printMooLine();
-   std::string const moo = getMooLine();
+      return printMooLine(timenow);
+   std::string const moo = getMooLine(timenow);
    size_t const depth = moo.length()/4;
    if (_config->FindB("APT::Moo::Color", false) == false)
       c1out <<
@@ -121,12 +123,12 @@ bool DoMoo2(CommandLine &)						/*{{{*/
    return true;
 }
 									/*}}}*/
-bool DoMoo3(CommandLine &)						/*{{{*/
+static bool DoMoo3(time_t const timenow)				/*{{{*/
 {
    // by Robert Millan in deb:134156
    if (_config->FindI("quiet") >= 2)
-      return printMooLine();
-   std::string const moo = getMooLine();
+      return printMooLine(timenow);
+   std::string const moo = getMooLine(timenow);
    size_t const depth = moo.length()/16;
    c1out <<
       OutputInDepth(depth, " ") << "                   \\_/ \n" <<
@@ -138,7 +140,7 @@ bool DoMoo3(CommandLine &)						/*{{{*/
    return true;
 }
 									/*}}}*/
-bool DoMooApril(CommandLine &)						/*{{{*/
+static bool DoMooApril()						/*{{{*/
 {
    // by Christopher Allan Webber and proposed by Paul Tagliamonte
    // in a "Community outreach": https://lists.debian.org/debian-devel/2013/04/msg00045.html
@@ -163,11 +165,12 @@ bool DoMooApril(CommandLine &)						/*{{{*/
 									/*}}}*/
 bool DoMoo(CommandLine &CmdL)						/*{{{*/
 {
-   time_t const timenow = time(NULL);
+   time_t const timenow = GetSecondsSinceEpoch();
+
    struct tm april;
    localtime_r(&timenow, &april);
    if (april.tm_mday == 1 && april.tm_mon == 3)
-      return DoMooApril(CmdL);
+      return DoMooApril();
 
    signed short SuperCow = 1;
    if (CmdL.FileSize() != 0)
@@ -185,11 +188,11 @@ bool DoMoo(CommandLine &CmdL)						/*{{{*/
    }
 
    switch(SuperCow) {
-      case 1: return DoMoo1(CmdL);
-      case 2: return DoMoo2(CmdL);
-      case 3: return DoMoo3(CmdL);
-      case 4: return DoMooApril(CmdL);
-      default: return DoMoo1(CmdL);
+      case 1: return DoMoo1(timenow);
+      case 2: return DoMoo2(timenow);
+      case 3: return DoMoo3(timenow);
+      case 4: return DoMooApril();
+      default: return DoMoo1(timenow);
    }
 
    return true;
diff --git a/apt-private/private-moo.h b/apt-private/private-moo.h
index bc8b3e7dd..c230ce2e1 100644
--- a/apt-private/private-moo.h
+++ b/apt-private/private-moo.h
@@ -6,9 +6,5 @@
 class CommandLine;
 
 APT_PUBLIC bool DoMoo(CommandLine &CmdL);
-bool DoMoo1(CommandLine &CmdL);
-bool DoMoo2(CommandLine &CmdL);
-bool DoMoo3(CommandLine &CmdL);
-bool DoMooApril(CommandLine &CmdL);
 
 #endif
diff --git a/apt-private/private-update.cc b/apt-private/private-update.cc
index ba953a088..a886c830f 100644
--- a/apt-private/private-update.cc
+++ b/apt-private/private-update.cc
@@ -71,19 +71,19 @@ bool DoUpdate(CommandLine &CmdL)
       ListUpdate(Stat, *List);
    }
 
+   if (_config->FindB("pkgCacheFile::Generate", true) == false)
+      return true;
+
    // Rebuild the cache.
-   if (_config->FindB("pkgCacheFile::Generate", true) == true)
-   {
-      pkgCacheFile::RemoveCaches();
-      if (Cache.BuildCaches() == false)
-	 return false;
-   }
+   pkgCacheFile::RemoveCaches();
+   if (Cache.BuildCaches(false) == false)
+      return false;
 
    // show basic stats (if the user whishes)
    if (_config->FindB("APT::Cmd::Show-Update-Stats", false) == true)
    {
       int upgradable = 0;
-      if (Cache.Open() == false)
+      if (Cache.Open(false) == false)
          return false;
       for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() != true; ++I)
       {
diff --git a/apt-private/private-utils.cc b/apt-private/private-utils.cc
index 775bf7e79..5863925b9 100644
--- a/apt-private/private-utils.cc
+++ b/apt-private/private-utils.cc
@@ -1,11 +1,13 @@
 #include <config.h>
 
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 
 #include <apt-private/private-utils.h>
 
 #include <cstdlib>
+#include <sstream>
 #include <unistd.h>
 
 // DisplayFileInPager - Display File with pager				/*{{{*/
@@ -74,3 +76,23 @@ bool EditFileInSensibleEditor(std::string const &filename)
    return ExecWait(Process, "editor", false);
 }
 									/*}}}*/
+time_t GetSecondsSinceEpoch()						/*{{{*/
+{
+   auto const source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+   if (source_date_epoch == nullptr)
+      return time(nullptr);
+
+   time_t epoch;
+   std::stringstream ss(source_date_epoch);
+   ss >> epoch;
+
+   if (ss.fail() || !ss.eof())
+   {
+      _error->Warning("Environment variable SOURCE_DATE_EPOCH was ignored as it has an invalid value: \"%s\"",
+            source_date_epoch);
+      return time(nullptr);
+   }
+
+   return epoch;
+}
+									/*}}}*/
diff --git a/apt-private/private-utils.h b/apt-private/private-utils.h
index b3b249689..4d48bd1ba 100644
--- a/apt-private/private-utils.h
+++ b/apt-private/private-utils.h
@@ -5,5 +5,6 @@
 
 bool DisplayFileInPager(std::string const &filename);
 bool EditFileInSensibleEditor(std::string const &filename);
+time_t GetSecondsSinceEpoch();
 
 #endif
diff --git a/debian/changelog b/debian/changelog
index 7cb7566cf..ffcde2e74 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,38 @@
+apt (1.4~rc1) unstable; urgency=medium
+
+  [ David Kalnischkies ]
+  * don't show update stats if cache generation is disabled
+  * don't lock dpkg in 'apt-get clean'
+  * don't lock dpkg in update commands
+  * avoid validate/delete/load race in cache generation
+  * fix 'install --no-download' mode
+  * remove 'old' FAILED files in the next acquire call (Closes: 846476)
+  * stop rred from leaking debug messages on recovered errors (Closes: #850759)
+  * make the moo reproducible.
+    Thanks to Chris Lamb for initial patch and guru meditation (Closes: #848721)
+  * update release mappings in documentation
+  * avoid malloc if option whitelist is disabled (default)
+
+  [ Julian Andres Klode ]
+  * basehttp: Only read Content-Range on 416 and 206 responses (LP: #1657567)
+  * test suite: Do not exit 0 in trap for QUIT
+  * Only merge acquire items with the same meta key (Closes: #838441)
+
+  [ Zhou Mo ]
+  * po: update Simplified Chinese program translation
+
+  [ Jean-Pierre Giraud ]
+  * French manpages translation update (Closes: 852460)
+
+  [ victory ]
+  * Japanese manpages & program translation update
+
+  [ Frans Spiesschaert ]
+  * Dutch program translation update (Closes: #853761)
+  * Dutch manpage translation update (Closes: #853762)
+
+ -- Julian Andres Klode <jak@debian.org>  Mon, 06 Feb 2017 14:41:23 +0100
+
 apt (1.4~beta4) unstable; urgency=medium
 
   * Read dpkg tables to handle architecture wildcards.
diff --git a/doc/apt-get.8.xml b/doc/apt-get.8.xml
index 1867b643d..f53bfa19b 100644
--- a/doc/apt-get.8.xml
+++ b/doc/apt-get.8.xml
@@ -14,7 +14,7 @@
    &apt-email;
    &apt-product;
    <!-- The last update date -->
-   <date>2017-01-05T00:00:00Z</date>
+   <date>2017-01-17T00:00:00Z</date>
  </refentryinfo>
  
  <refmeta>
diff --git a/doc/apt-verbatim.ent b/doc/apt-verbatim.ent
index d2a6d90f2..71d7d8453 100644
--- a/doc/apt-verbatim.ent
+++ b/doc/apt-verbatim.ent
@@ -239,20 +239,20 @@
 ">
 
 <!-- this will be updated by 'prepare-release' -->
-<!ENTITY apt-product-version "1.4~beta4">
+<!ENTITY apt-product-version "1.4~rc1">
 
 <!-- (Code)names for various things used all over the place -->
-<!ENTITY debian-oldstable-codename "wheezy">
-<!ENTITY debian-stable-codename "jessie">
-<!ENTITY debian-testing-codename "stretch">
-<!ENTITY debian-stable-version "8">
-<!ENTITY ubuntu-codename "trusty">
+<!ENTITY debian-oldstable-codename "jessie">
+<!ENTITY debian-stable-codename "stretch">
+<!ENTITY debian-testing-codename "buster">
+<!ENTITY debian-stable-version "9">
+<!ENTITY ubuntu-codename "xenial">
 
 <!-- good and bad just refers to matching and not matching a pattern…
      It is not a remark about the specific perl version.
      There is no way perl could be clasified "good" (or "bad") in any version… -->
-<!ENTITY good-perl "5.10">
-<!ENTITY bad-perl "5.14">
+<!ENTITY good-perl "5.20">
+<!ENTITY bad-perl "5.24">
 
 <!-- Arguments -->
 <!ENTITY synopsis-arg-option "<arg><option>-o=<replaceable>&synopsis-config-string;</replaceable></option></arg>">
diff --git a/methods/basehttp.cc b/methods/basehttp.cc
index 74d641ef2..2e4f37e26 100644
--- a/methods/basehttp.cc
+++ b/methods/basehttp.cc
@@ -175,7 +175,11 @@ bool RequestState::HeaderLine(string const &Line)			/*{{{*/
       return true;
    }
 
-   if (stringcasecmp(Tag,"Content-Range:") == 0)
+   // The Content-Range field only has a meaning in HTTP/1.1 for the
+   // 206 (Partial Content) and 416 (Range Not Satisfiable) responses
+   // according to RFC7233 "Range Requests", §4.2, so only consider it
+   // for such responses.
+   if ((Result == 416 || Result == 206) && stringcasecmp(Tag,"Content-Range:") == 0)
    {
       HaveContent = true;
 
diff --git a/methods/rred.cc b/methods/rred.cc
index 958933a07..2e5008d46 100644
--- a/methods/rred.cc
+++ b/methods/rred.cc
@@ -662,12 +662,14 @@ class RredMethod : public aptMethod {
 	 FileFd inp, out;
 	 if (inp.Open(Path, FileFd::ReadOnly, FileFd::Extension) == false)
 	 {
-	    std::cerr << "FAILED to open inp " << Path << std::endl;
+	    if (Debug == true)
+	       std::clog << "FAILED to open inp " << Path << std::endl;
 	    return _error->Error("Failed to open inp %s", Path.c_str());
 	 }
 	 if (out.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension) == false)
 	 {
-	    std::cerr << "FAILED to open out " << Itm->DestFile << std::endl;
+	    if (Debug == true)
+	       std::clog << "FAILED to open out " << Itm->DestFile << std::endl;
 	    return _error->Error("Failed to open out %s", Itm->DestFile.c_str());
 	 }
 
@@ -686,7 +688,8 @@ class RredMethod : public aptMethod {
 	 inp.Close();
 
 	 if (_error->PendingError() == true) {
-	    std::cerr << "FAILED to read or write files" << std::endl;
+	    if (Debug == true)
+	       std::clog << "FAILED to read or write files" << std::endl;
 	    return false;
 	 }
 
diff --git a/prepare-release b/prepare-release
index 0004de310..8c4e0978b 100755
--- a/prepare-release
+++ b/prepare-release
@@ -215,6 +215,69 @@ elif [ "$1" = 'coverage' ]; then
 		   'apt-inst' 'apt-inst/deb' 'apt-inst/contrib' 'apt-private'
 	done
 	genhtml --output-directory "${DIR}" "${DIR}/apt.coverage.fixed" ${LCOVRC}
+elif [ "$1" = 'spellcheckers' ]; then
+	echo '### codespell in source directories:'
+	codespell --enable-colors $(find . -mindepth 1 -maxdepth 1 -type d \! -name '.git' \! -name 'doc' \! -name 'po' \! -name 'build' \! -name 'test') | \
+		grep -v '^.*debian/changelog.*Troup.*==>.*Troupe.*$' || true
+	echo '### codespell in testcases:'
+	codespell $(find test -type f \! -name 'status-*' \! -name 'Packages-*' \! -name '*.deb' \! -name '*.sec' \! -name '*.pub' \! -name '*.db')
+	echo '### codespell in documentation:'
+	codespell doc/*.xml doc/*.txt doc/*.dbk doc/*.ent doc/*.cmake.in doc/xml.add doc/po4a.conf doc/examples doc/po/apt-doc.pot po/apt-all.pot README.* COPYING
+
+	echo '### spellintian in source directories:'
+	{
+		for DIR in $(find . -mindepth 1 -maxdepth 1 -type d \! -name '.git' \! -name 'doc' \! -name 'po' \! -name 'build' \! -name 'test'); do
+			spellintian $(find "$DIR" -type f)
+		done
+	} | grep -v \
+		-e '^.*: long long (duplicate word) -> long$' \
+		-e '^./apt-pkg/pkgcache.h: ID ID (duplicate word) -> ID$' \
+		-e '^./apt-pkg/contrib/mmap.cc: WorkSpace WorkSpace (duplicate word) -> WorkSpace$' \
+		-e '^./apt-pkg/contrib/md5.cc: z z (duplicate word) -> z$' \
+		-e '^./apt-pkg/metaindex.cc: const const (duplicate word) -> const$' \
+		-e '^./apt-pkg/acquire-method.cc: QueueBack QueueBack (duplicate word) -> QueueBack$' \
+		-e '^./CMake/Translations.cmake: domain domain (duplicate word) -> domain$' \
+		-e '^./CMake/apti18n.h.in: m m (duplicate word) -> m$' \
+		-e '^./CMake/run_if_exists.sh: fi fi (duplicate word) -> fi$' \
+		-e '^./ftparchive/byhash.cc: ByHash ByHash (duplicate word) -> ByHash$' \
+		-e '^./ftparchive/writer.cc: this Packages -> these packages$' \
+		-e '^./ftparchive/byhash.h: ByHash ByHash (duplicate word) -> ByHash$' \
+		-e '^./cmdline/apt-key.in: done done (duplicate word) -> done$' \
+		-e '^./cmdline/apt-key.in: fi fi (duplicate word) -> fi$' \
+		-e '^./cmdline/apt-key.in: echo echo (duplicate word) -> echo$' \
+		-e '^./triehash/.travis.yml: perl perl (duplicate word) -> perl$' \
+		-e '^./triehash/README.md: Performance Performance (duplicate word) -> Performance$' \
+		-e '^./debian/apt.apt-compat.cron.daily: fi fi (duplicate word) -> fi$' \
+		-e '^./debian/apt.auto-removal.sh: done done (duplicate word) -> done$' \
+		-e '^./debian/apt.systemd.daily: fi fi (duplicate word) -> fi$' \
+		-e '^./debian/apt.postinst: fi fi (duplicate word) -> fi$' \
+		-e '^./methods/http.cc: Sz Sz (duplicate word) -> Sz$' \
+		-e '^./methods/ftp.cc: AFMap AFMap (duplicate word) -> AFMap$' \
+		-e '^./dselect/install: fi fi (duplicate word) -> fi$' \
+		|| true
+	echo '### spellintian in testcases:'
+	spellintian $(find test -type f \! -name 'status-*' \! -name 'Packages-*' \! -name '*.deb' \! -name '*.sec' \! -name '*.pub' \! -name '*.db') \
+	| grep -v \
+		-e '^.*: long long (duplicate word) -> long$' \
+		-e '^test/integration/.*: fi fi (duplicate word) -> fi$' \
+		-e '^test/integration/.*: done done (duplicate word) -> done$' \
+		-e '^test/integration/.*: echo echo (duplicate word) -> echo$' \
+		-e '^test/integration/test-00-commands-have-help: moo moo (duplicate word) -> moo$' \
+		-e '^test/integration/test-apt-cache: bar bar (duplicate word) -> bar$' \
+		-e '^test/integration/test-sourceslist-trusted-options: everythingsucceeds everythingsucceeds (duplicate word) -> everythingsucceeds$' \
+		-e '^test/integration/test-sourceslist-trusted-options: everythingfails everythingfails (duplicate word) -> everythingfails$' \
+		-e '^test/integration/test-apt-get-changelog: foo foo (duplicate word) -> foo$' \
+		-e '^test/integration/test-ubuntu-bug-761175-remove-purge: testround testround (duplicate word) -> testround$' \
+		-e '^test/integration/test-apt-get-download: apt apt (duplicate word) -> apt$' \
+		-e '^test/integration/test-apt-showlist-orgroup-in-recommends: zzz zzz (duplicate word) -> zzz$' \
+		-e '^test/integration/test-bug-691453-apt-cache-search-multi-pattern: bar bar (duplicate word) -> bar$' \
+		-e '^test/integration/test-allow: hold hold (duplicate word) -> hold$' \
+		-e '^test/integration/test-apt-by-hash-update: ensureitsbroken ensureitsbroken (duplicate word) -> ensureitsbroken$' \
+		-e '^test/integration/test-apt-source-and-build-dep: foo foo (duplicate word) -> foo$' \
+		|| true
+	echo '### spellintian in documentation:'
+	spellintian doc/*.xml doc/*.txt doc/*.dbk doc/*.ent doc/*.cmake.in doc/xml.add doc/po4a.conf doc/examples/* doc/po/apt-doc.pot po/apt-all.pot README.* COPYING
+
 else
 	echo >&1 "Usage:\t$0 pre-export
 \t$0 pre-build
@@ -242,6 +305,11 @@ Both will format the diff properly.
 used by .travis.yml.
 »coverage« does a clean build with the right flags for coverage reporting,
 runs all tests and generates a html report in the end.
+
+\t$0 spellcheckers
+
+»spellcheckers« runs »codespell« and »spellintian« on the appropiate files and
+filters out obvious false positives.
 "
 
 fi
diff --git a/test/integration/run-tests b/test/integration/run-tests
index 3dcacc7bd..80f1fc61d 100755
--- a/test/integration/run-tests
+++ b/test/integration/run-tests
@@ -114,7 +114,8 @@ removesigninghome() {
 	GNUPGHOME="${APT_TEST_SIGNINGHOME}" gpgconf --kill gpg-agent >/dev/null 2>&1 || true
 	rm -rf -- "$APT_TEST_SIGNINGHOME"
 }
-trap "removesigninghome; exit 0" 0 HUP INT QUIT ILL ABRT FPE SEGV PIPE TERM
+trap "exit 1" 0 HUP INT ILL ABRT FPE SEGV PIPE TERM
+trap "removesigninghome" 0 QUIT
 export APT_TEST_SIGNINGHOME
 
 TOTAL="$(echo "$TESTLIST" | wc -l)"
diff --git a/test/integration/test-00-commands-have-help b/test/integration/test-00-commands-have-help
index 699cdef15..87c3be6b4 100755
--- a/test/integration/test-00-commands-have-help
+++ b/test/integration/test-00-commands-have-help
@@ -63,3 +63,25 @@ testsuccess aptget moo moo moo
 testsuccess aptget moo moo moo -q=2
 testsuccess aptget moo moo moo moo
 testsuccess aptget moo moo moo moo -q=2
+
+export SOURCE_DATE_EPOCH=moo
+testwarningmsg 'W: Environment variable SOURCE_DATE_EPOCH was ignored as it has an invalid value: "moo"' apt moo
+testmoo() {
+	export SOURCE_DATE_EPOCH="$(date -d "$1" +'%s')"
+	testsuccess aptget moo
+	cp rootdir/tmp/testsuccess.output moo.output
+	testsuccess grep "$2" moo.output
+	testsuccessequal "$2" apt moo -qqq
+	unset SOURCE_DATE_EPOCH
+}
+testmoo '@0' 'Have you mooed today?'
+testmoo '0-12-25' 'Happy package management day!'
+testmoo '1930-02-18' "It's a Bird ... It's a Plane ... It's Super Cow!"
+testmoo '1966-11-07' 'Whoever needs milk, bows to the animal.'
+testmoo '1988-03-29' 'Have you mooed today?'
+testmoo '1993-08-16' 'Three moos for Debian!'
+testmoo '1998-04-01' 'Have you smashed some milk today?'
+testmoo '@1484822790' 'Have you mooed today?'
+testmoo '@1484822791' 'Have you mooed today?'
+testmoo '@1484822792' 'Have you mooed today?'
+testmoo '@1484822793' 'Have you mooed today?'
diff --git a/test/integration/test-apt-cli-update b/test/integration/test-apt-cli-update
index b423072c3..cc8d051d2 100755
--- a/test/integration/test-apt-cli-update
+++ b/test/integration/test-apt-cli-update
@@ -15,6 +15,7 @@ setupaptarchive --no-update
 
 testfailuremsg 'E: The update command takes no arguments' apt update arguments
 
+testempty apt update -qq -o pkgCacheFile::Generate=false
 testsuccessequal "1 package can be upgraded. Run 'apt list --upgradable' to see it." apt update -qq
 
 cp dpkg.status rootdir/var/lib/dpkg/status
diff --git a/test/integration/test-apt-keep-downloaded-pkgs b/test/integration/test-apt-keep-downloaded-pkgs
index 4cc7fbb04..c5f62954c 100755
--- a/test/integration/test-apt-keep-downloaded-pkgs
+++ b/test/integration/test-apt-keep-downloaded-pkgs
@@ -15,14 +15,25 @@ buildsimplenativepackage 'pkg4' 'all' '1.0' 'stable'
 # local (file) installs
 setupaptarchive
 
+# a file:// "download" is not a real download and hence passes
+testsuccess aptget install pkg1 --no-download --download-only -y
+testfailure test -f rootdir/var/cache/apt/archives/pkg1_1.0_all.deb
+testsuccess test -f aptarchive/pool/pkg1_1.0_all.deb
+
 # ensure that install from local sources does not remove debs
 testsuccess aptget install pkg1 -o APT::Keep-Downloaded-Packages=false
 testsuccess test -f aptarchive/pool/pkg1_1.0_all.deb
+testfailure test -f rootdir/var/cache/apt/archives/pkg1_1.0_all.deb
 
 # now switch to http and downloading debs
 changetowebserver
 testsuccess aptget update
 
+# see if no-download really doesn't download the package
+testfailuremsg 'E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?' aptget install pkg2 --no-download -y
+testsuccess test -f aptarchive/pool/pkg2_1.0_all.deb
+testfailure test -f rootdir/var/cache/apt/archives/pkg2_1.0_all.deb
+
 # ensure that the downloaded pkg is kept with "keep=true"
 testsuccess aptget install pkg2 -o APT::Keep-Downloaded-Packages=true
 testsuccess test -f aptarchive/pool/pkg2_1.0_all.deb
@@ -40,4 +51,4 @@ testfailure test -f rootdir/var/cache/apt/archives/pkg3_1.0_all.deb
 # ensure that install from the download dir does not delete packages
 mv aptarchive/pool/pkg4_1.0_all.deb rootdir/var/cache/apt/archives
 testsuccess aptget install $(pwd)/rootdir/var/cache/apt/archives/pkg4_1.0_all.deb -o APT::Keep-Downloaded-Packages=false
-testsuccess test -f $(pwd)/rootdir/var/cache/apt/archives/pkg4_1.0_all.deb
\ No newline at end of file
+testsuccess test -f $(pwd)/rootdir/var/cache/apt/archives/pkg4_1.0_all.deb
diff --git a/test/integration/test-apt-update-expected-size b/test/integration/test-apt-update-expected-size
index f7b825d98..710d05d18 100755
--- a/test/integration/test-apt-update-expected-size
+++ b/test/integration/test-apt-update-expected-size
@@ -25,6 +25,7 @@ test_inreleasetoobig() {
 	rm -f update.output
 	# ensure the failed InRelease file got renamed
 	testsuccess ls rootdir/var/lib/apt/lists/partial/*InRelease.FAILED
+	testfailure test -e rootdir/var/lib/apt/lists/partial/Old.FAILED
 }
 
 test_packagestoobig() {
@@ -40,6 +41,8 @@ test_packagestoobig() {
 	NEW_SIZE="$(stat --printf=%s aptarchive/dists/unstable/main/binary-i386/Packages.gz)"
 	testfailuremsg "E: Failed to fetch ${1}/dists/unstable/main/binary-i386/Packages.gz  Writing more data than expected ($NEW_SIZE > $SIZE)
 E: Some index files failed to download. They have been ignored, or old ones used instead." aptget update -o Debug::pkgAcquire::Worker=1 -o Debug::Acquire::Transaction=0
+	testsuccess ls rootdir/var/lib/apt/lists/partial/*Packages*.FAILED
+	testfailure test -e rootdir/var/lib/apt/lists/partial/Old.FAILED
 }
 
 methodtest() {
@@ -51,6 +54,7 @@ methodtest() {
 	rm -rf rootdir/var/lib/apt/lists rootdir/var/lib/apt/lists.good
 	# normal update works fine
 	testsuccess aptget update
+	touch rootdir/var/lib/apt/lists/partial/Old.FAILED
 	mv rootdir/var/lib/apt/lists rootdir/var/lib/apt/lists.good
 
 	# starting fresh works
diff --git a/test/integration/test-ubuntu-bug-1651923-requote-https-uri b/test/integration/test-ubuntu-bug-1651923-requote-https-uri
index bedd972b4..cf56a6af4 100755
--- a/test/integration/test-ubuntu-bug-1651923-requote-https-uri
+++ b/test/integration/test-ubuntu-bug-1651923-requote-https-uri
@@ -13,7 +13,7 @@ changetohttpswebserver
 webserverconfig 'aptwebserver::redirect::replace::/targetwithoutspace/' '/target%20with%20space/'
 webserverconfig 'aptwebserver::redirect::replace::/targetwithoutspace2/' '/target with space/'
 
-testsuccess apthelper download-file -o debug::acquire::http=1 "http://localhost:${APTHTTPPORT}/targetwithoutspace/working"; httpfile1
-testsuccess apthelper download-file -o debug::acquire::http=1 "http://localhost:${APTHTTPPORT}/targetwithoutspace2/working"; httpfile2
-testsuccess apthelper download-file -o debug::acquire::https=1 "https://localhost:${APTHTTPSPORT}/targetwithoutspace/working"; httpsfile1
-testsuccess apthelper download-file -o debug::acquire::https=1 "https://localhost:${APTHTTPSPORT}/targetwithoutspace2/working"; httpsfile2
+testsuccess downloadfile "http://localhost:${APTHTTPPORT}/targetwithoutspace/working"; httpfile1
+testsuccess downloadfile "http://localhost:${APTHTTPPORT}/targetwithoutspace2/working"; httpfile2
+testsuccess downloadfile "https://localhost:${APTHTTPSPORT}/targetwithoutspace/working"; httpsfile1
+testsuccess downloadfile "https://localhost:${APTHTTPSPORT}/targetwithoutspace2/working"; httpsfile2

Attachment: apt_1.4~rc1.diff.xz
Description: application/xz


Reply to: