From 4460af4594726ce5531224b1f9dc3826d634fd89 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 3 Apr 2017 14:28:51 +0100 Subject: [PATCH] wip source download --- hippotatlib/ownsource.py | 144 +++++++++++++++++++++++++++++++++++++++++++++++ t.py | 6 ++ 2 files changed, 150 insertions(+) create mode 100644 hippotatlib/ownsource.py create mode 100755 t.py diff --git a/hippotatlib/ownsource.py b/hippotatlib/ownsource.py new file mode 100644 index 0000000..be7bdcd --- /dev/null +++ b/hippotatlib/ownsource.py @@ -0,0 +1,144 @@ +# Automatic source code provision (AGPL compliance) + +import sys +import fnmatch + +class SourceShipmentPreparer(): + def __init__(s, destdir): + # caller may modify, and should read after calling generate() + s.output_name = 'srcbomb.tar.gz' + # defaults, caller can modify after creation + s.src_filter = s.src_filter_glob + s.src_filter_globs = ['/usr/local/*', '!/usr*', '!/etc/*'] + s.src_likeparent = s.src_likeparent_git + s.cwd = os.getcwd() + s.excludes = ['*~', '*.bak', '*.tmp', '#*#'] + s.rune_shell = ['/bin/bash', '-ec'] + s.rune_cpio = r'''' + set -o pipefail + ( + %s + # ^ by default, is find ... -print0 + ) | ( + cpio -Hustar -o --quiet -0 -R 1000:1000 || \ + cpio -Hustar -o --quiet -0 + ) + ''' + s.rune_portmanteau = r''' + outfile=$1; shift + rm -f "$outfile" + GZIP=-9 tar zcf "$outfile" "$@"' + ''' + s.manifest_name='0000-MANIFEST.txt' + # private + s._destdir = destdir + s._outcounter = 1 + s._manifest = [] + + def src_filter_glob(s, src): # default s.src_filter + for pat in s.src_filter_globs: + negate = pat.startswith('!') + if negate: pat = pat[1:] + if fnmatch.fnmatch(src, pat): + return not negate + return negate + + def src_likeparent_git(s, src): + try: + stat(os.path.join(d, '.git/.')) + except FileNotFoundError: + return False + else: + return True + + def src_parentfinder(s, src, infol): # callers may monkey-patch away + for deref in (False,True): + xinfo = [] + + search = src + if deref: + search = os.path.realpath(search) + + def ascend(): + xinfo.append(os.path.basename(search)) + search = os.path.dirname(search) + + try: + stab = lstat(search) + except FileNotFoundError: + return + if stat.S_ISREG(stab.st_mode): + ascend() + + while not os.path.ismount(search): + if s.src_likeparent(search): + xinfo.reverse() + infol.append(os.path.join(*xinfo)) + return search + + ascend() + + # no .git found anywhere + return d + + def src_prenormaliser(s, d): # callers may monkey-patch away + return os.path.join(s.cwd, os.path.abspath(d)) + + def src_find_rune(s, d): + script = 'find -type f -perm +004' + for excl in s.excludes: + assert("'" not in excl) + script += r" \! -name '%s'" % excl + script += ' -print0' + + def new_output_name(s, nametail, infol): + name = '%04d-%s' % (s._outcounter++, nametail) + s._manifest.append((name, infol.join(' ')) + return name + + def open_output_fh(s, name, mode): + return open(os.path.join(s._destdir, name), mode) + + def new_output_fh(s, nametail, infol): + name = new_output_name(s, nametail, infol) + return open_output_fh(name, 'wb') + + def mk_from_dir(s, d): + find_rune = s.src_find_rune(s, d) + total_rune = s.rune_cpio % find_rune + fh = new_output_fh('src.cpio') + subprocess.run(s.rune_shell + [total_rune], + cwd=s._destdir, + stdin=subprocess.DEVNULL, + stdout=fh, + restore_signals=True) + fh.close() + + def mk_from_src(s, d, infol): + d = s.src_prenormaliser(d, infol) + if not s.src_filter(d): return + d = s.src_parentfinder(d, infol) + s.mk_from_dir(d, infol) + + def mk_from_srcs(s, dirs=sys.path): + s.mk_from_src(sys.argv[0], ['argv[0]']) + for d in sys.path: + s.mk_from_src(d, ['sys.path']) + + def mk_portmanteau(s):] + cmdl = s.rune_shell + [ s.rune_portmanteau, 'x', + s.output_name, s.manifest_name ] + mfh = open_output_fh(s.manifest_name,'w') + for (name, info) in s._manifest: + cmdl.append(name) + print('%s\t%s\n' % (name,info), file=mfh) + mfh.close() + subprocess.run(s.rune_shell + cmdl, + cmd=s._destdir, + stdin=subprocess.DEVNULL, + stdout=sys.stderr, + restore_signals=True) + + def generate(s): + s.mk_from_srcdirs() + s.mk_portmanteau() diff --git a/t.py b/t.py new file mode 100755 index 0000000..8c6e152 --- /dev/null +++ b/t.py @@ -0,0 +1,6 @@ +#!/usr/bin/python3 + +from hippotatlib.ownsource import SourceShipmentPreparer + +p = SourceShipmentPreparer('tmp') +p.generate() -- 2.11.0