mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-27 15:11:23 -07:00
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
This commit is contained in:
parent
3be65b66d1
commit
2aa3f52bf3
1 changed files with 40 additions and 9 deletions
|
@ -72,7 +72,12 @@ EXAMPLES = '''
|
||||||
|
|
||||||
RETURN = '''
|
RETURN = '''
|
||||||
state:
|
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
|
type: string
|
||||||
returned: always
|
returned: always
|
||||||
missing:
|
missing:
|
||||||
|
@ -98,6 +103,7 @@ import glob
|
||||||
import shutil
|
import shutil
|
||||||
import gzip
|
import gzip
|
||||||
import bz2
|
import bz2
|
||||||
|
import filecmp
|
||||||
import zipfile
|
import zipfile
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
|
@ -157,6 +163,7 @@ def main():
|
||||||
|
|
||||||
archive_paths = []
|
archive_paths = []
|
||||||
missing = []
|
missing = []
|
||||||
|
exclude = []
|
||||||
arcroot = ''
|
arcroot = ''
|
||||||
|
|
||||||
for path in expanded_paths:
|
for path in expanded_paths:
|
||||||
|
@ -172,9 +179,9 @@ def main():
|
||||||
if i < len(arcroot):
|
if i < len(arcroot):
|
||||||
arcroot = os.path.dirname(arcroot[0:i+1])
|
arcroot = os.path.dirname(arcroot[0:i+1])
|
||||||
|
|
||||||
if path == creates:
|
# Don't allow archives to be created anywhere within paths to be removed
|
||||||
# Don't allow the archive to specify itself! this is an error.
|
if remove and os.path.isdir(path) and creates.startswith(path):
|
||||||
module.fail_json(path=', '.join(paths), msg='Error, created archive would be included in archive')
|
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):
|
if os.path.lexists(path):
|
||||||
archive_paths.append(path)
|
archive_paths.append(path)
|
||||||
|
@ -208,18 +215,40 @@ def main():
|
||||||
|
|
||||||
if state != 'archive':
|
if state != 'archive':
|
||||||
try:
|
try:
|
||||||
|
# Easier compression using tarfile module
|
||||||
if compression == 'gz' or compression == 'bz2':
|
if compression == 'gz' or compression == 'bz2':
|
||||||
archive = tarfile.open(creates, 'w|' + compression)
|
archive = tarfile.open(creates, 'w|' + compression)
|
||||||
|
|
||||||
for path in archive_paths:
|
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)
|
successes.append(path)
|
||||||
|
|
||||||
|
# Slightly more difficult (and less efficient!) compression using zipfile module
|
||||||
elif compression == 'zip':
|
elif compression == 'zip':
|
||||||
archive = zipfile.ZipFile(creates, 'w')
|
archive = zipfile.ZipFile(creates, 'w', zipfile.ZIP_DEFLATED)
|
||||||
|
|
||||||
for path in archive_paths:
|
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)
|
successes.append(path)
|
||||||
|
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -228,8 +257,10 @@ def main():
|
||||||
|
|
||||||
if archive:
|
if archive:
|
||||||
archive.close()
|
archive.close()
|
||||||
|
state = 'archive'
|
||||||
|
|
||||||
if state != 'archive' and remove:
|
|
||||||
|
if state == 'archive' and remove:
|
||||||
for path in successes:
|
for path in successes:
|
||||||
try:
|
try:
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
|
@ -275,7 +306,7 @@ def main():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if compression == 'zip':
|
if compression == 'zip':
|
||||||
archive = zipfile.ZipFile(creates, 'wb')
|
archive = zipfile.ZipFile(creates, 'w', zipfile.ZIP_DEFLATED)
|
||||||
archive.write(path, path[len(arcroot):])
|
archive.write(path, path[len(arcroot):])
|
||||||
archive.close()
|
archive.close()
|
||||||
state = 'archive' # because all zip files are archives
|
state = 'archive' # because all zip files are archives
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue