Skip to content

Instantly share code, notes, and snippets.

@snzip
Forked from kkew3/mk_zip_patch.py
Created July 20, 2023 06:39
Show Gist options
  • Save snzip/f5a2bcb3ef1c0577ffe3ae9513c04022 to your computer and use it in GitHub Desktop.
Save snzip/f5a2bcb3ef1c0577ffe3ae9513c04022 to your computer and use it in GitHub Desktop.

Revisions

  1. @kkew3 kkew3 created this gist May 15, 2022.
    82 changes: 82 additions & 0 deletions mk_zip_patch.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    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()