chiark / gitweb /
cgi.py: Implement a wrapping operation.
[chopwood] / agpl.py
CommitLineData
a2916c06
MW
1### -*-python-*-
2###
3### GNU Affero General Public License compliance
4###
5### (c) 2013 Mark Wooding
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This file is part of Chopwood: a password-changing service.
11###
12### Chopwood is free software; you can redistribute it and/or modify
13### it under the terms of the GNU Affero General Public License as
14### published by the Free Software Foundation; either version 3 of the
15### License, or (at your option) any later version.
16###
17### Chopwood is distributed in the hope that it will be useful,
18### but WITHOUT ANY WARRANTY; without even the implied warranty of
19### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20### GNU Affero General Public License for more details.
21###
22### You should have received a copy of the GNU Affero General Public
23### License along with Chopwood; if not, see
24### <http://www.gnu.org/licenses/>.
25
26import contextlib as CTX
27import os as OS
28import shlex as SL
29import shutil as SH
30import subprocess as SUB
31import sys as SYS
32import tarfile as TAR
33import tempfile as TF
34
35from auto import PACKAGE, VERSION
36import util as U
37
38@CTX.contextmanager
39def tempdir():
40 d = TF.mkdtemp()
41 try: yield d
42 finally: SH.rmtree(d, ignore_errors = True)
43
44def dirs_to_dump():
45 dirs = set()
46 for m in SYS.modules.itervalues():
47 try: f = m.__file__
48 except AttributeError: continue
49 d = OS.path.realpath(OS.path.dirname(f))
50 if d.startswith('/usr/') and not d.startswith('/usr/local/'): continue
51 dirs.add(d)
52 dirs = sorted(dirs)
53 last = '!'
54 dump = []
55 for d in dirs:
56 if d.startswith(last): continue
57 dump.append(d)
58 last = d
59 return dump
60
61def exists_subdir(subdir):
62 return lambda dir: OS.path.isdir(OS.path.join(dir, subdir))
63
64def filez(cmd):
65 def _(dir):
66 kid = SUB.Popen(SL.split(cmd), stdout = SUB.PIPE, cwd = dir)
67 left = ''
68 while True:
69 buf = kid.stdout.read(16384)
70 if not buf: break
71 buf = left + buf
72 i = 0
73 while True:
74 z = buf.find('\0', i)
75 if z < 0: break
76 f = buf[i:z]
77 if f.startswith('./'): f = f[2:]
78 yield f
79 i = z + 1
80 left = buf[i:]
81 if left:
82 raise U.ExpectedError, \
83 (500, "trailing junk from `%s' in `%s'" % (cmd, dir))
84 return _
85
86DUMPERS = [
87 (exists_subdir('.git'), [filez('git ls-files -coz --exclude-standard'),
88 filez('find .git -print0')]),
89 (lambda d: True, [filez('find . ( ! -perm +004 -prune ) -o -print0')])]
90
91def dump_dir(dir, tf, root):
92 for test, listers in DUMPERS:
93 if test(dir): break
94 else:
95 raise U.ExpectedError, (500, "no dumper for `%s'" % dir)
96 for lister in listers:
97 base = OS.path.basename(dir)
98 for file in lister(dir):
99 tf.add(OS.path.join(dir, file), OS.path.join(root, base, file),
100 recursive = False)
101
102def source(out):
103 if SYS.version_info >= (2, 6):
104 tf = TAR.open(fileobj = out, mode = 'w|gz', format = TAR.USTAR_FORMAT)
105 else:
106 tf = TAR.open(fileobj = out, mode = 'w|gz')
107 tf.posix = True
108 for d in dirs_to_dump():
109 dump_dir(d, tf, '%s-%s' % (PACKAGE, VERSION))
110 tf.close()
111
112###----- That's all, folks --------------------------------------------------