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
  • Select an option

  • Save snzip/f5a2bcb3ef1c0577ffe3ae9513c04022 to your computer and use it in GitHub Desktop.

Select an option

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`.
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