-
-
Save snzip/f5a2bcb3ef1c0577ffe3ae9513c04022 to your computer and use it in GitHub Desktop.
Make a `patch.zip` file from `old.zip` file to `new.zip` file, including all changed and newly added files. Also generate a patch shell script `patch.sh` that removes all files unique to `old.zip`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import argparse | |
| import collections | |
| import tempfile | |
| import zipfile | |
| import filecmp | |
| import shutil | |
| import shlex | |
| ZipCmpResult = collections.namedtuple('ZipCmpResult', | |
| ['to_rm', 'to_cmp', 'to_add']) | |
| def make_parser(): | |
| parser = argparse.ArgumentParser( | |
| description='Make patch zip file from two similar zip files.') | |
| parser.add_argument( | |
| '--oldfile', | |
| default=os.path.join('share', 'old.zip'), | |
| help='default: %(default)s') | |
| parser.add_argument( | |
| '--newfile', | |
| default=os.path.join('share', 'new.zip'), | |
| help='default: %(default)s') | |
| parser.add_argument( | |
| '--toname', | |
| default=os.path.join('share', 'patch'), | |
| help='default: %(default)s') | |
| return parser | |
| def zipcmp(old, new): | |
| with zipfile.ZipFile(old) as zinfile: | |
| old_names = set(zinfile.namelist()) | |
| with zipfile.ZipFile(new) as zinfile: | |
| new_names = set(zinfile.namelist()) | |
| to_rm = old_names - new_names | |
| to_cmp = old_names & new_names | |
| to_add = new_names - old_names | |
| return ZipCmpResult(to_rm, to_cmp, to_add) | |
| def compare_files(old, new, cmpresult): | |
| with tempfile.TemporaryDirectory() as tmpdir, \ | |
| zipfile.ZipFile(old) as zinfile_old, \ | |
| zipfile.ZipFile(new) as zinfile_new: | |
| old_dest = os.path.join(tmpdir, 'old') | |
| new_dest = os.path.join(tmpdir, 'new') | |
| os.mkdir(old_dest) | |
| os.mkdir(new_dest) | |
| for filename in cmpresult.to_cmp: | |
| zinfile_old.extract(filename, path=old_dest) | |
| zinfile_new.extract(filename, path=new_dest) | |
| if not filecmp.cmp( | |
| os.path.join(old_dest, filename), | |
| os.path.join(new_dest, filename), | |
| shallow=False): | |
| cmpresult.to_add.add(filename) | |
| def mkpatch(new, cmpresult, to_name): | |
| with zipfile.ZipFile(new) as zinfile, \ | |
| zipfile.ZipFile(to_name + '.zip', 'w') as zoutfile: | |
| for filename in cmpresult.to_add: | |
| with zinfile.open(filename) as infile, \ | |
| zoutfile.open(filename, 'w') as outfile: | |
| shutil.copyfileobj(infile, outfile) | |
| with open(to_name + '.sh', 'w', encoding='utf-8') as outfile: | |
| outfile.write('#!/bin/sh\n') | |
| for filename in cmpresult.to_rm: | |
| outfile.write('rm {}\n'.format(shlex.quote(filename))) | |
| def main(): | |
| args = make_parser().parse_args() | |
| cmpresult = zipcmp(args.oldfile, args.newfile) | |
| compare_files(args.oldfile, args.newfile, cmpresult) | |
| mkpatch(args.newfile, cmpresult, args.toname) | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment