]> git.phdru.name Git - dotfiles.git/blob - bin/zip.py
Feat(zip): Save and restore symlinks
[dotfiles.git] / bin / zip.py
1 #! /usr/bin/env python3
2 """Zip (zip -r9) with encoded filenames
3
4    Written by Oleg Broytman. Copyright (C) 2009-2023 PhiloSoft Design.
5 """
6
7 import sys, os
8 from getopt import getopt, GetoptError
9 from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
10 from m_lib.defenc import default_encoding
11
12 def usage():
13     sys.exit('Usage: %s file.zip file1 dir2...' % sys.argv[0])
14
15 try:
16   options, arguments = getopt(sys.argv[1:], '')
17 except GetoptError:
18     usage()
19
20 if len(arguments) < 2:
21     usage()
22
23 def addToZip(zf, path):
24     if os.path.isfile(path) or os.path.islink(path):
25         print(path)
26         if isinstance(path, bytes):
27             recoded_path = path.decode(default_encoding).encode('cp866')
28         else:
29             recoded_path = path
30         if os.path.islink(path):
31             # http://www.mail-archive.com/python-list@python.org/msg34223.html
32             zipInfo = ZipInfo(recoded_path)
33             zipInfo.create_system = 3
34             # say, symlink attr magic...
35             zipInfo.external_attr = 0xA1ED0000
36             zf.writestr(zipInfo, os.readlink(path))
37         else:
38             zf.write(path, recoded_path, ZIP_DEFLATED)
39     elif os.path.isdir(path):
40         for nm in os.listdir(path):
41             addToZip(zf, os.path.join(path, nm))
42     # else: ignore
43
44 zname = arguments[0]
45 if os.path.splitext(zname)[1] not in ('.zip', '.ZIP'):
46     zname += '.zip'
47
48 zf = ZipFile(zname, 'w', allowZip64=True)
49
50 for path in arguments[1:]:
51     addToZip(zf, path)
52
53 zf.close()