aboutsummaryrefslogtreecommitdiff
path: root/pyzipper
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2019-03-10 13:46:08 -0400
committerRob Austein <sra@hactrn.net>2019-03-10 13:46:08 -0400
commitfa9a04b06a7c6f62979c506b9999abf6b2eb8208 (patch)
tree887062e0d0c0ff844eb5fd05d603aad897c77d7e /pyzipper
First public version.
Diffstat (limited to 'pyzipper')
-rwxr-xr-xpyzipper44
1 files changed, 44 insertions, 0 deletions
diff --git a/pyzipper b/pyzipper
new file mode 100755
index 0000000..9e50835
--- /dev/null
+++ b/pyzipper
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""
+Generate an executable Python zip package.
+"""
+
+import os, zipfile, argparse
+
+ap = argparse.ArgumentParser(description = __doc__,
+ formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+ap.add_argument("-o", "--output", required = True, type = argparse.FileType("wb+"))
+ap.add_argument("-m", "--module", default = "main", help = "module within package to run")
+ap.add_argument("-e", "--executable", default = "python", help = "python executable to run")
+ap.add_argument("source")
+args = ap.parse_args()
+
+# PyZipFile.writepy()'s behavior changes when it sees __init__.py
+if os.path.exists(os.path.join(args.source, "__init__.py")):
+ module = "{0.source}.{0.module}".format(args)
+else:
+ module = args.module
+
+# Write executable shim
+args.output.write('''\
+#/bin/sh -
+PYTHONPATH="$0"${{PYTHONPATH+":$PYTHONPATH"}} exec {e} -m {m} ${{1+"$@"}}
+'''.format(m = module, e = args.executable).encode("ascii"))
+
+# Make output executable
+os.fchmod(args.output.fileno(), 0o755)
+
+# Create the zip file and populate it with the code
+z = zipfile.PyZipFile(args.output, "a", zipfile.ZIP_DEFLATED)
+z.writepy(args.source)
+
+# Add data files, if any
+if os.path.isdir(args.source):
+ for root, dirs, files in os.walk(args.source):
+ for fn in files:
+ if not any(fn.endswith(fn2) for fn2 in (".py", ".pyc", ".pyo")):
+ z.write(os.path.join(root, fn))
+
+# Test the zip file we just generated out of paranoia
+z.testzip()