Blame SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch

ae2451
diff --git a/Lib/shutil.py b/Lib/shutil.py
ae2451
index 420802f..d0ff2ef 100644
ae2451
--- a/Lib/shutil.py
ae2451
+++ b/Lib/shutil.py
ae2451
@@ -446,17 +446,24 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
ae2451
                         zip_filename, base_dir)
ae2451
 
ae2451
         if not dry_run:
ae2451
-            zip = zipfile.ZipFile(zip_filename, "w",
ae2451
-                                  compression=zipfile.ZIP_DEFLATED)
ae2451
-
ae2451
-            for dirpath, dirnames, filenames in os.walk(base_dir):
ae2451
-                for name in filenames:
ae2451
-                    path = os.path.normpath(os.path.join(dirpath, name))
ae2451
-                    if os.path.isfile(path):
ae2451
-                        zip.write(path, path)
ae2451
+            with zipfile.ZipFile(zip_filename, "w",
ae2451
+                                 compression=zipfile.ZIP_DEFLATED) as zf:
ae2451
+                path = os.path.normpath(base_dir)
ae2451
+                zf.write(path, path)
ae2451
+                if logger is not None:
ae2451
+                    logger.info("adding '%s'", path)
ae2451
+                for dirpath, dirnames, filenames in os.walk(base_dir):
ae2451
+                    for name in sorted(dirnames):
ae2451
+                        path = os.path.normpath(os.path.join(dirpath, name))
ae2451
+                        zf.write(path, path)
ae2451
                         if logger is not None:
ae2451
                             logger.info("adding '%s'", path)
ae2451
-            zip.close()
ae2451
+                    for name in filenames:
ae2451
+                        path = os.path.normpath(os.path.join(dirpath, name))
ae2451
+                        if os.path.isfile(path):
ae2451
+                            zf.write(path, path)
ae2451
+                            if logger is not None:
ae2451
+                                logger.info("adding '%s'", path)
ae2451
 
ae2451
     return zip_filename
ae2451
 
ae2451
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
ae2451
index 9bdb724..9238489 100644
ae2451
--- a/Lib/test/test_shutil.py
ae2451
+++ b/Lib/test/test_shutil.py
ae2451
@@ -10,13 +10,13 @@ import os.path
ae2451
 import errno
ae2451
 from os.path import splitdrive
ae2451
 from distutils.spawn import find_executable, spawn
ae2451
-from shutil import (_make_tarball, _make_zipfile, make_archive,
ae2451
+from shutil import (make_archive,
ae2451
                     register_archive_format, unregister_archive_format,
ae2451
                     get_archive_formats)
ae2451
 import tarfile
ae2451
 import warnings
ae2451
 
ae2451
-from test import test_support
ae2451
+from test import test_support as support
ae2451
 from test.test_support import TESTFN, check_warnings, captured_stdout
ae2451
 
ae2451
 TESTFN2 = TESTFN + "2"
ae2451
@@ -372,139 +372,135 @@ class TestShutil(unittest.TestCase):
ae2451
     @unittest.skipUnless(zlib, "requires zlib")
ae2451
     def test_make_tarball(self):
ae2451
         # creating something to tar
ae2451
-        tmpdir = self.mkdtemp()
ae2451
-        self.write_file([tmpdir, 'file1'], 'xxx')
ae2451
-        self.write_file([tmpdir, 'file2'], 'xxx')
ae2451
-        os.mkdir(os.path.join(tmpdir, 'sub'))
ae2451
-        self.write_file([tmpdir, 'sub', 'file3'], 'xxx')
ae2451
+        root_dir, base_dir = self._create_files('')
ae2451
 
ae2451
         tmpdir2 = self.mkdtemp()
ae2451
         # force shutil to create the directory
ae2451
         os.rmdir(tmpdir2)
ae2451
-        unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
ae2451
+        unittest.skipUnless(splitdrive(root_dir)[0] == splitdrive(tmpdir2)[0],
ae2451
                             "source and target should be on same drive")
ae2451
 
ae2451
         base_name = os.path.join(tmpdir2, 'archive')
ae2451
 
ae2451
         # working with relative paths to avoid tar warnings
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            _make_tarball(splitdrive(base_name)[1], '.')
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        make_archive(splitdrive(base_name)[1], 'gztar', root_dir, '.')
ae2451
 
ae2451
         # check if the compressed tarball was created
ae2451
         tarball = base_name + '.tar.gz'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertTrue(os.path.isfile(tarball))
ae2451
+        self.assertTrue(tarfile.is_tarfile(tarball))
ae2451
+        with tarfile.open(tarball, 'r:gz') as tf:
ae2451
+            self.assertEqual(sorted(tf.getnames()),
ae2451
+                             ['.', './file1', './file2',
ae2451
+                              './sub', './sub/file3', './sub2'])
ae2451
 
ae2451
         # trying an uncompressed one
ae2451
         base_name = os.path.join(tmpdir2, 'archive')
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            _make_tarball(splitdrive(base_name)[1], '.', compress=None)
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        make_archive(splitdrive(base_name)[1], 'tar', root_dir, '.')
ae2451
         tarball = base_name + '.tar'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertTrue(os.path.isfile(tarball))
ae2451
+        self.assertTrue(tarfile.is_tarfile(tarball))
ae2451
+        with tarfile.open(tarball, 'r') as tf:
ae2451
+            self.assertEqual(sorted(tf.getnames()),
ae2451
+                             ['.', './file1', './file2',
ae2451
+                              './sub', './sub/file3', './sub2'])
ae2451
 
ae2451
     def _tarinfo(self, path):
ae2451
-        tar = tarfile.open(path)
ae2451
-        try:
ae2451
+        with tarfile.open(path) as tar:
ae2451
             names = tar.getnames()
ae2451
             names.sort()
ae2451
             return tuple(names)
ae2451
-        finally:
ae2451
-            tar.close()
ae2451
 
ae2451
-    def _create_files(self):
ae2451
+    def _create_files(self, base_dir='dist'):
ae2451
         # creating something to tar
ae2451
-        tmpdir = self.mkdtemp()
ae2451
-        dist = os.path.join(tmpdir, 'dist')
ae2451
-        os.mkdir(dist)
ae2451
-        self.write_file([dist, 'file1'], 'xxx')
ae2451
-        self.write_file([dist, 'file2'], 'xxx')
ae2451
+        root_dir = self.mkdtemp()
ae2451
+        dist = os.path.join(root_dir, base_dir)
ae2451
+        if not os.path.isdir(dist):
ae2451
+            os.makedirs(dist)
ae2451
+        self.write_file((dist, 'file1'), 'xxx')
ae2451
+        self.write_file((dist, 'file2'), 'xxx')
ae2451
         os.mkdir(os.path.join(dist, 'sub'))
ae2451
-        self.write_file([dist, 'sub', 'file3'], 'xxx')
ae2451
+        self.write_file((dist, 'sub', 'file3'), 'xxx')
ae2451
         os.mkdir(os.path.join(dist, 'sub2'))
ae2451
-        tmpdir2 = self.mkdtemp()
ae2451
-        base_name = os.path.join(tmpdir2, 'archive')
ae2451
-        return tmpdir, tmpdir2, base_name
ae2451
+        if base_dir:
ae2451
+            self.write_file((root_dir, 'outer'), 'xxx')
ae2451
+        return root_dir, base_dir
ae2451
 
ae2451
     @unittest.skipUnless(zlib, "Requires zlib")
ae2451
-    @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
ae2451
+    @unittest.skipUnless(find_executable('tar'),
ae2451
                          'Need the tar command to run')
ae2451
     def test_tarfile_vs_tar(self):
ae2451
-        tmpdir, tmpdir2, base_name =  self._create_files()
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            _make_tarball(base_name, 'dist')
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        root_dir, base_dir = self._create_files()
ae2451
+        base_name = os.path.join(self.mkdtemp(), 'archive')
ae2451
+        make_archive(base_name, 'gztar', root_dir, base_dir)
ae2451
 
ae2451
         # check if the compressed tarball was created
ae2451
         tarball = base_name + '.tar.gz'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertTrue(os.path.isfile(tarball))
ae2451
 
ae2451
         # now create another tarball using `tar`
ae2451
-        tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
ae2451
-        tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
ae2451
-        gzip_cmd = ['gzip', '-f9', 'archive2.tar']
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            with captured_stdout() as s:
ae2451
-                spawn(tar_cmd)
ae2451
-                spawn(gzip_cmd)
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        tarball2 = os.path.join(root_dir, 'archive2.tar')
ae2451
+        tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
ae2451
+        with support.change_cwd(root_dir), captured_stdout():
ae2451
+            spawn(tar_cmd)
ae2451
 
ae2451
-        self.assertTrue(os.path.exists(tarball2))
ae2451
+        self.assertTrue(os.path.isfile(tarball2))
ae2451
         # let's compare both tarballs
ae2451
         self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
ae2451
 
ae2451
         # trying an uncompressed one
ae2451
-        base_name = os.path.join(tmpdir2, 'archive')
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            _make_tarball(base_name, 'dist', compress=None)
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        make_archive(base_name, 'tar', root_dir, base_dir)
ae2451
         tarball = base_name + '.tar'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertTrue(os.path.isfile(tarball))
ae2451
 
ae2451
         # now for a dry_run
ae2451
-        base_name = os.path.join(tmpdir2, 'archive')
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
-        try:
ae2451
-            _make_tarball(base_name, 'dist', compress=None, dry_run=True)
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        make_archive(base_name, 'tar', root_dir, base_dir, dry_run=True)
ae2451
         tarball = base_name + '.tar'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertTrue(os.path.isfile(tarball))
ae2451
 
ae2451
     @unittest.skipUnless(zlib, "Requires zlib")
ae2451
     @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
ae2451
     def test_make_zipfile(self):
ae2451
-        # creating something to tar
ae2451
-        tmpdir = self.mkdtemp()
ae2451
-        self.write_file([tmpdir, 'file1'], 'xxx')
ae2451
-        self.write_file([tmpdir, 'file2'], 'xxx')
ae2451
+        # creating something to zip
ae2451
+        root_dir, base_dir = self._create_files()
ae2451
+        base_name = os.path.join(self.mkdtemp(), 'archive')
ae2451
 
ae2451
-        tmpdir2 = self.mkdtemp()
ae2451
-        # force shutil to create the directory
ae2451
-        os.rmdir(tmpdir2)
ae2451
-        base_name = os.path.join(tmpdir2, 'archive')
ae2451
-        _make_zipfile(base_name, tmpdir)
ae2451
+        res = make_archive(base_name, 'zip', root_dir, base_dir)
ae2451
 
ae2451
-        # check if the compressed tarball was created
ae2451
-        tarball = base_name + '.zip'
ae2451
-        self.assertTrue(os.path.exists(tarball))
ae2451
+        self.assertEqual(res, base_name + '.zip')
ae2451
+        self.assertTrue(os.path.isfile(res))
ae2451
+        self.assertTrue(zipfile.is_zipfile(res))
ae2451
+        with zipfile.ZipFile(res) as zf:
ae2451
+            self.assertEqual(sorted(zf.namelist()),
ae2451
+                             ['dist/', 'dist/file1', 'dist/file2',
ae2451
+                             'dist/sub/', 'dist/sub/file3', 'dist/sub2/'])
ae2451
 
ae2451
+    @unittest.skipUnless(zlib, "Requires zlib")
ae2451
+    @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
ae2451
+    @unittest.skipUnless(find_executable('zip'),
ae2451
+                         'Need the zip command to run')
ae2451
+    def test_zipfile_vs_zip(self):
ae2451
+        root_dir, base_dir = self._create_files()
ae2451
+        base_name = os.path.join(self.mkdtemp(), 'archive')
ae2451
+        archive = make_archive(base_name, 'zip', root_dir, base_dir)
ae2451
+
ae2451
+        # check if ZIP file  was created
ae2451
+        self.assertEqual(archive, base_name + '.zip')
ae2451
+        self.assertTrue(os.path.isfile(archive))
ae2451
+
ae2451
+        # now create another ZIP file using `zip`
ae2451
+        archive2 = os.path.join(root_dir, 'archive2.zip')
ae2451
+        zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
ae2451
+        with support.change_cwd(root_dir):
ae2451
+            spawn(zip_cmd)
ae2451
+
ae2451
+        self.assertTrue(os.path.isfile(archive2))
ae2451
+        # let's compare both ZIP files
ae2451
+        with zipfile.ZipFile(archive) as zf:
ae2451
+            names = zf.namelist()
ae2451
+        with zipfile.ZipFile(archive2) as zf:
ae2451
+            names2 = zf.namelist()
ae2451
+        self.assertEqual(sorted(names), sorted(names2))
ae2451
 
ae2451
     def test_make_archive(self):
ae2451
         tmpdir = self.mkdtemp()
ae2451
@@ -521,39 +517,36 @@ class TestShutil(unittest.TestCase):
ae2451
         else:
ae2451
             group = owner = 'root'
ae2451
 
ae2451
-        base_dir, root_dir, base_name =  self._create_files()
ae2451
-        base_name = os.path.join(self.mkdtemp() , 'archive')
ae2451
+        root_dir, base_dir = self._create_files()
ae2451
+        base_name = os.path.join(self.mkdtemp(), 'archive')
ae2451
         res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
ae2451
                            group=group)
ae2451
-        self.assertTrue(os.path.exists(res))
ae2451
+        self.assertTrue(os.path.isfile(res))
ae2451
 
ae2451
         res = make_archive(base_name, 'zip', root_dir, base_dir)
ae2451
-        self.assertTrue(os.path.exists(res))
ae2451
+        self.assertTrue(os.path.isfile(res))
ae2451
 
ae2451
         res = make_archive(base_name, 'tar', root_dir, base_dir,
ae2451
                            owner=owner, group=group)
ae2451
-        self.assertTrue(os.path.exists(res))
ae2451
+        self.assertTrue(os.path.isfile(res))
ae2451
 
ae2451
         res = make_archive(base_name, 'tar', root_dir, base_dir,
ae2451
                            owner='kjhkjhkjg', group='oihohoh')
ae2451
-        self.assertTrue(os.path.exists(res))
ae2451
+        self.assertTrue(os.path.isfile(res))
ae2451
 
ae2451
     @unittest.skipUnless(zlib, "Requires zlib")
ae2451
     @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
ae2451
     def test_tarfile_root_owner(self):
ae2451
-        tmpdir, tmpdir2, base_name =  self._create_files()
ae2451
-        old_dir = os.getcwd()
ae2451
-        os.chdir(tmpdir)
ae2451
+        root_dir, base_dir = self._create_files()
ae2451
+        base_name = os.path.join(self.mkdtemp(), 'archive')
ae2451
         group = grp.getgrgid(0)[0]
ae2451
         owner = pwd.getpwuid(0)[0]
ae2451
-        try:
ae2451
-            archive_name = _make_tarball(base_name, 'dist', compress=None,
ae2451
-                                         owner=owner, group=group)
ae2451
-        finally:
ae2451
-            os.chdir(old_dir)
ae2451
+        with support.change_cwd(root_dir):
ae2451
+            archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
ae2451
+                                        owner=owner, group=group)
ae2451
 
ae2451
         # check if the compressed tarball was created
ae2451
-        self.assertTrue(os.path.exists(archive_name))
ae2451
+        self.assertTrue(os.path.isfile(archive_name))
ae2451
 
ae2451
         # now checks the rights
ae2451
         archive = tarfile.open(archive_name)
ae2451
@@ -859,7 +852,7 @@ class TestCopyFile(unittest.TestCase):
ae2451
 
ae2451
 
ae2451
 def test_main():
ae2451
-    test_support.run_unittest(TestShutil, TestMove, TestCopyFile)
ae2451
+    support.run_unittest(TestShutil, TestMove, TestCopyFile)
ae2451
 
ae2451
 if __name__ == '__main__':
ae2451
     test_main()
ae2451
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
ae2451
index 42c1b4d..98a9275 100644
ae2451
--- a/Lib/test/test_support.py
ae2451
+++ b/Lib/test/test_support.py
ae2451
@@ -491,6 +491,33 @@ TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid())
ae2451
 SAVEDCWD = os.getcwd()
ae2451
 
ae2451
 @contextlib.contextmanager
ae2451
+def change_cwd(path, quiet=False):
ae2451
+    """Return a context manager that changes the current working directory.
ae2451
+
ae2451
+    Arguments:
ae2451
+
ae2451
+      path: the directory to use as the temporary current working directory.
ae2451
+
ae2451
+      quiet: if False (the default), the context manager raises an exception
ae2451
+        on error.  Otherwise, it issues only a warning and keeps the current
ae2451
+        working directory the same.
ae2451
+
ae2451
+    """
ae2451
+    saved_dir = os.getcwd()
ae2451
+    try:
ae2451
+        os.chdir(path)
ae2451
+    except OSError:
ae2451
+        if not quiet:
ae2451
+            raise
ae2451
+        warnings.warn('tests may fail, unable to change CWD to: ' + path,
ae2451
+                      RuntimeWarning, stacklevel=3)
ae2451
+    try:
ae2451
+        yield os.getcwd()
ae2451
+    finally:
ae2451
+        os.chdir(saved_dir)
ae2451
+
ae2451
+
ae2451
+@contextlib.contextmanager
ae2451
 def temp_cwd(name='tempcwd', quiet=False):
ae2451
     """
ae2451
     Context manager that creates a temporary directory and set it as CWD.