diff options
-rw-r--r-- | Doc/library/tarfile.rst | 27 | ||||
-rw-r--r-- | Lib/tarfile.py | 27 | ||||
-rw-r--r-- | Lib/test/test_tarfile.py | 28 | ||||
-rw-r--r-- | Misc/NEWS | 2 |
4 files changed, 76 insertions, 8 deletions
diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 2996839..fa6cca7 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -389,7 +389,7 @@ object, see :ref:`tarinfo-objects` for details. and :meth:`close`, and also supports iteration over its lines. -.. method:: TarFile.add(name, arcname=None, recursive=True, exclude=None) +.. method:: TarFile.add(name, arcname=None, recursive=True, exclude=None, filter=None) Add the file *name* to the archive. *name* may be any type of file (directory, fifo, symbolic link, etc.). If given, *arcname* specifies an alternative name @@ -397,11 +397,22 @@ object, see :ref:`tarinfo-objects` for details. can be avoided by setting *recursive* to :const:`False`. If *exclude* is given it must be a function that takes one filename argument and returns a boolean value. Depending on this value the respective file is either excluded - (:const:`True`) or added (:const:`False`). + (:const:`True`) or added (:const:`False`). If *filter* is specified it must + be a function that takes a :class:`TarInfo` object argument and returns the + changed TarInfo object. If it instead returns :const:`None` the TarInfo + object will be excluded from the archive. See :ref:`tar-examples` for an + example. .. versionchanged:: 2.6 Added the *exclude* parameter. + .. versionchanged:: 2.7 + Added the *filter* parameter. + + .. deprecated:: 2.7 + The *exclude* parameter is deprecated, please use the *filter* parameter + instead. + .. method:: TarFile.addfile(tarinfo, fileobj=None) @@ -653,6 +664,18 @@ How to read a gzip compressed tar archive and display some member information:: print "something else." tar.close() +How to create an archive and reset the user information using the *filter* +parameter in :meth:`TarFile.add`:: + + import tarfile + def reset(tarinfo): + tarinfo.uid = tarinfo.gid = 0 + tarinfo.uname = tarinfo.gname = "root" + return tarinfo + tar = tarfile.open("sample.tar.gz", "w:gz") + tar.add("foo", filter=reset) + tar.close() + .. _tar-formats: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 54a2606..a87fe22 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1918,13 +1918,16 @@ class TarFile(object): print "link to", tarinfo.linkname, print - def add(self, name, arcname=None, recursive=True, exclude=None): + def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): """Add the file `name' to the archive. `name' may be any type of file (directory, fifo, symbolic link, etc.). If given, `arcname' specifies an alternative name for the file in the archive. Directories are added recursively by default. This can be avoided by setting `recursive' to False. `exclude' is a function that should - return True for each filename to be excluded. + return True for each filename to be excluded. `filter' is a function + that expects a TarInfo object argument and returns the changed + TarInfo object, if it returns None the TarInfo object will be + excluded from the archive. """ self._check("aw") @@ -1932,9 +1935,13 @@ class TarFile(object): arcname = name # Exclude pathnames. - if exclude is not None and exclude(name): - self._dbg(2, "tarfile: Excluded %r" % name) - return + if exclude is not None: + import warnings + warnings.warn("use the filter argument instead", + DeprecationWarning, 2) + if exclude(name): + self._dbg(2, "tarfile: Excluded %r" % name) + return # Skip if somebody tries to archive the archive... if self.name is not None and os.path.abspath(name) == self.name: @@ -1950,6 +1957,13 @@ class TarFile(object): self._dbg(1, "tarfile: Unsupported type %r" % name) return + # Change or exclude the TarInfo object. + if filter is not None: + tarinfo = filter(tarinfo) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % name) + return + # Append the tar header and data to the archive. if tarinfo.isreg(): f = bltn_open(name, "rb") @@ -1960,7 +1974,8 @@ class TarFile(object): self.addfile(tarinfo) if recursive: for f in os.listdir(name): - self.add(os.path.join(name, f), os.path.join(arcname, f), recursive, exclude) + self.add(os.path.join(name, f), os.path.join(arcname, f), + recursive, exclude, filter) else: self.addfile(tarinfo) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 8c9b0ec..1240e1a 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -660,6 +660,34 @@ class WriteTest(WriteTestBase): finally: shutil.rmtree(tempdir) + def test_filter(self): + tempdir = os.path.join(TEMPDIR, "filter") + os.mkdir(tempdir) + try: + for name in ("foo", "bar", "baz"): + name = os.path.join(tempdir, name) + open(name, "wb").close() + + def filter(tarinfo): + if os.path.basename(tarinfo.name) == "bar": + return + tarinfo.uid = 123 + tarinfo.uname = "foo" + return tarinfo + + tar = tarfile.open(tmpname, self.mode, encoding="iso8859-1") + tar.add(tempdir, arcname="empty_dir", filter=filter) + tar.close() + + tar = tarfile.open(tmpname, "r") + for tarinfo in tar: + self.assertEqual(tarinfo.uid, 123) + self.assertEqual(tarinfo.uname, "foo") + self.assertEqual(len(tar.getmembers()), 3) + tar.close() + finally: + shutil.rmtree(tempdir) + # Guarantee that stored pathnames are not modified. Don't # remove ./ or ../ or double slashes. Still make absolute # pathnames relative. @@ -366,6 +366,8 @@ Core and Builtins Library ------- +- Issue #6856: Add a filter keyword argument to TarFile.add(). + - Issue #6163: Fixed HP-UX runtime library dir options in distutils.unixcompiler. Initial patch by Sridhar Ratnakumar and Michael Haubenwallner. |