Fix up for zip files and nesting logic.

* Don't include the archive in the archive if it falls within an archived path
* If remove=True and the archive would be in an archived path, fail.
* Fix single-file zip file compression
* Add more documentation about 'state' return
pull/18777/head
Ben Doherty 9 years ago committed by Matt Clay
parent 3be65b66d1
commit 2aa3f52bf3

@ -72,7 +72,12 @@ EXAMPLES = '''
RETURN = '''
state:
description: The current state of the archived file.
description:
The current state of the archived file.
If 'absent', then no source files were found and the archive does not exist.
If 'compress', then the file source file is in the compressed state.
If 'archive', then the source file or paths are currently archived.
If 'incomplete', then an archive was created, but not all source paths were found.
type: string
returned: always
missing:
@ -98,6 +103,7 @@ import glob
import shutil
import gzip
import bz2
import filecmp
import zipfile
import tarfile
@ -157,6 +163,7 @@ def main():
archive_paths = []
missing = []
exclude = []
arcroot = ''
for path in expanded_paths:
@ -172,9 +179,9 @@ def main():
if i < len(arcroot):
arcroot = os.path.dirname(arcroot[0:i+1])
if path == creates:
# Don't allow the archive to specify itself! this is an error.
module.fail_json(path=', '.join(paths), msg='Error, created archive would be included in archive')
# Don't allow archives to be created anywhere within paths to be removed
if remove and os.path.isdir(path) and creates.startswith(path):
module.fail_json(path=', '.join(paths), msg='Error, created archive can not be contained in source paths when remove=True')
if os.path.lexists(path):
archive_paths.append(path)
@ -208,18 +215,40 @@ def main():
if state != 'archive':
try:
# Easier compression using tarfile module
if compression == 'gz' or compression == 'bz2':
archive = tarfile.open(creates, 'w|' + compression)
for path in archive_paths:
archive.add(path, path[len(arcroot):])
basename = ''
# Prefix trees in the archive with their basename, unless specifically prevented with '.'
if os.path.isdir(path) and not path.endswith(os.sep + '.'):
basename = os.path.basename(path) + os.sep
archive.add(path, path[len(arcroot):], filter=lambda f: f if f.name != creates else None)
successes.append(path)
# Slightly more difficult (and less efficient!) compression using zipfile module
elif compression == 'zip':
archive = zipfile.ZipFile(creates, 'w')
archive = zipfile.ZipFile(creates, 'w', zipfile.ZIP_DEFLATED)
for path in archive_paths:
archive.write(path, path[len(arcroot):])
basename = ''
# Prefix trees in the archive with their basename, unless specifically prevented with '.'
if os.path.isdir(path) and not path.endswith(os.sep + '.'):
basename = os.path.basename(path) + os.sep
for dirpath, dirnames, filenames in os.walk(path, topdown=True):
for dirname in dirnames:
archive.write(dirpath + os.sep + dirname, basename + dirname)
for filename in filenames:
fullpath = dirpath + os.sep + filename
if not filecmp.cmp(fullpath, creates):
archive.write(fullpath, basename + filename)
successes.append(path)
except OSError:
@ -228,8 +257,10 @@ def main():
if archive:
archive.close()
state = 'archive'
if state != 'archive' and remove:
if state == 'archive' and remove:
for path in successes:
try:
if os.path.isdir(path):
@ -275,7 +306,7 @@ def main():
try:
if compression == 'zip':
archive = zipfile.ZipFile(creates, 'wb')
archive = zipfile.ZipFile(creates, 'w', zipfile.ZIP_DEFLATED)
archive.write(path, path[len(arcroot):])
archive.close()
state = 'archive' # because all zip files are archives

Loading…
Cancel
Save