mirror of https://github.com/python/cpython
Issue #6856: Add a filter keyword argument to TarFile.add().
The filter argument must be a function that takes a TarInfo object argument, changes it and returns it again. If the function returns None the TarInfo object will be excluded from the archive. The exclude argument is deprecated from now on, because it does something similar but is not as flexible.
This commit is contained in:
parent
d4c7eb1647
commit
21121e64b4
|
@ -389,7 +389,7 @@ object, see :ref:`tarinfo-objects` for details.
|
||||||
and :meth:`close`, and also supports iteration over its lines.
|
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,
|
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
|
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
|
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
|
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
|
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
|
.. versionchanged:: 2.6
|
||||||
Added the *exclude* parameter.
|
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)
|
.. 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."
|
print "something else."
|
||||||
tar.close()
|
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:
|
.. _tar-formats:
|
||||||
|
|
||||||
|
|
|
@ -1918,13 +1918,16 @@ class TarFile(object):
|
||||||
print "link to", tarinfo.linkname,
|
print "link to", tarinfo.linkname,
|
||||||
print
|
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
|
"""Add the file `name' to the archive. `name' may be any type of file
|
||||||
(directory, fifo, symbolic link, etc.). If given, `arcname'
|
(directory, fifo, symbolic link, etc.). If given, `arcname'
|
||||||
specifies an alternative name for the file in the archive.
|
specifies an alternative name for the file in the archive.
|
||||||
Directories are added recursively by default. This can be avoided by
|
Directories are added recursively by default. This can be avoided by
|
||||||
setting `recursive' to False. `exclude' is a function that should
|
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")
|
self._check("aw")
|
||||||
|
|
||||||
|
@ -1932,9 +1935,13 @@ class TarFile(object):
|
||||||
arcname = name
|
arcname = name
|
||||||
|
|
||||||
# Exclude pathnames.
|
# Exclude pathnames.
|
||||||
if exclude is not None and exclude(name):
|
if exclude is not None:
|
||||||
self._dbg(2, "tarfile: Excluded %r" % name)
|
import warnings
|
||||||
return
|
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...
|
# Skip if somebody tries to archive the archive...
|
||||||
if self.name is not None and os.path.abspath(name) == self.name:
|
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)
|
self._dbg(1, "tarfile: Unsupported type %r" % name)
|
||||||
return
|
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.
|
# Append the tar header and data to the archive.
|
||||||
if tarinfo.isreg():
|
if tarinfo.isreg():
|
||||||
f = bltn_open(name, "rb")
|
f = bltn_open(name, "rb")
|
||||||
|
@ -1960,7 +1974,8 @@ class TarFile(object):
|
||||||
self.addfile(tarinfo)
|
self.addfile(tarinfo)
|
||||||
if recursive:
|
if recursive:
|
||||||
for f in os.listdir(name):
|
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:
|
else:
|
||||||
self.addfile(tarinfo)
|
self.addfile(tarinfo)
|
||||||
|
|
|
@ -660,6 +660,34 @@ class WriteTest(WriteTestBase):
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(tempdir)
|
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
|
# Guarantee that stored pathnames are not modified. Don't
|
||||||
# remove ./ or ../ or double slashes. Still make absolute
|
# remove ./ or ../ or double slashes. Still make absolute
|
||||||
# pathnames relative.
|
# pathnames relative.
|
||||||
|
|
|
@ -366,6 +366,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6856: Add a filter keyword argument to TarFile.add().
|
||||||
|
|
||||||
- Issue #6163: Fixed HP-UX runtime library dir options in
|
- Issue #6163: Fixed HP-UX runtime library dir options in
|
||||||
distutils.unixcompiler. Initial patch by Sridhar Ratnakumar and
|
distutils.unixcompiler. Initial patch by Sridhar Ratnakumar and
|
||||||
Michael Haubenwallner.
|
Michael Haubenwallner.
|
||||||
|
|
Loading…
Reference in New Issue