The following example code is based off the tools.py script from the delocate project code I found. I set the variable for the src_dir to be a folder that should exist on all Windows systems, I just set it dst_dir to a temp folder.
For me I get mod_time mismatches of approx. 1 hour for C:\Users\Public , when I run the script on that folder, some files/folders (ex Desktop) may be missing due to permissions errors (I picked a folder I thought wouldn’t have any for the example), for this specific example, I am not concerned, from the files are that copied I can see mod_time mismatch and that is what I am concerned about.
import os, sys, zipfile, time, stat
from socket import gethostname
from datetime import datetime
hostname = gethostname()
date = datetime.now()
date = date.strftime('%Y-%m-%d--%H.%M.%S')
src_dir = r"C:\Users\Public"
dst_dir = r"C:\tmp"
outfile_path = os.path.join(dst_dir, f"{hostname}___{date}___Archive.zip")
def dir2zip(in_dir, zip_fname):
"""Make a zip file `zip_fname` with contents of directory `in_dir`
The recorded filenames are relative to `in_dir`, so doing a standard zip
unpack of the resulting `zip_fname` in an empty directory will result in
the original directory contents.
Parameters
----------
in_dir : str
Directory path containing files to go in the zip archive
zip_fname : str
Filename of zip archive to write
"""
print('runing dir2zip')
z = zipfile.ZipFile(zip_fname, "w", compression=zipfile.ZIP_DEFLATED)
for root, dirs, files in os.walk(in_dir):
for file in files:
in_fname = os.path.join(root, file)
in_stat = os.stat(in_fname)
# Preserve file permissions but allow copy
info = zipfile.ZipInfo(in_fname)
info.filename = os.path.relpath(in_fname, in_dir)
if os.path.sep == "\\":
# Make the paths unix friendly on windows.
info.filename = os.path.relpath(in_fname, in_dir).replace("\\", "/")
# Set time from modification time
info.date_time = time.localtime(in_stat.st_mtime)
# See https://stackoverflow.com/questions/434641/how-do-i-set-permissions-attributes-on-a-file-in-a-zip-file-using-pythons-zip/48435482#48435482 # noqa: E501
# Also set regular file permissions
perms = stat.S_IMODE(in_stat.st_mode) | stat.S_IFREG
info.external_attr = perms << 16
with open_readable(in_fname, "rb") as fobj:
contents = fobj.read()
z.writestr(info, contents, zipfile.ZIP_DEFLATED)
pass
z.close()
# https://github.com/matthew-brett/delocate/blob/master/delocate/tools.py
#def dir2zip(in_dir, zip_fname):
def chmod_perms(fname):
# Permissions relevant to chmod
return stat.S_IMODE(os.stat(fname).st_mode)
def ensure_permissions(mode_flags=stat.S_IWUSR):
"""decorator to ensure a filename has given permissions.
If changed, original permissions are restored after the decorated
modification.
"""
def decorator(f):
def modify(filename, *args, **kwargs):
m = 0
m = chmod_perms(filename) if os.path.exists(filename) else mode_flags
if not m & mode_flags:
os.chmod(filename, m | mode_flags)
try:
return f(filename, *args, **kwargs)
finally:
# restore original permissions
if not m & mode_flags:
os.chmod(filename, m)
return modify
return decorator
open_readable = ensure_permissions(stat.S_IRUSR)(open)
dir2zip(src_dir, outfile_path)
I don’t understand why on the line
open_readable = ensure_permissions(stat.S_IRUSR)(open)
There are two sets of parenthesis after the call to ensure_permissions and open inside parenthesis without any arguments.
I do not recall correctly what pipes (|) mean.