4f1db677aa16fcc6b9ac19c4f4f522f139e99ab0
1 # Automatic source code provision (AGPL compliance)
9 class SourceShipmentPreparer():
10 def __init__(s
, destdir
):
11 # caller may modify, and should read after calling generate()
12 s
.output_name
= 'srcbomb.tar.gz'
13 # defaults, caller can modify after creation
14 s
.src_filter
= s
.src_filter_glob
15 s
.src_filter_globs
= ['/usr/local/*', '!/usr*', '!/etc/*']
16 s
.src_likeparent
= s
.src_likeparent_git
18 s
.find_rune_base
= "find -type f -perm -004 \! -path '*/tmp/*'"
19 s
.excludes
= ['*~', '*.bak', '*.tmp', '#*#',
20 '[0-9][0-9][0-9][0-9]-src.cpio']
21 s
.rune_shell
= ['/bin/bash', '-ec']
22 s
.show_pathnames
= True
27 # ^ by default, is find ... -print0
29 cpio -Hustar -o --quiet -0 -R 1000:1000 || \
30 cpio -Hustar -o --quiet -0
33 s
.rune_portmanteau
= r
'''
36 GZIP=-1 tar zcf "$outfile" "$@"
38 s
.manifest_name
='0000-MANIFEST.txt'
45 def src_filter_glob(s
, src
): # default s.src_filter
46 for pat
in s
.src_filter_globs
:
47 negate
= pat
.startswith('!')
48 if negate
: pat
= pat
[1:]
49 if fnmatch
.fnmatch(src
, pat
):
53 def src_likeparent_git(s
, src
):
55 os
.stat(os
.path
.join(src
, '.git/.'))
56 except FileNotFoundError
:
61 def src_parentfinder(s
, src
, infol
): # callers may monkey-patch away
62 for deref
in (False,True):
67 search
= os
.path
.realpath(search
)
71 xinfo
.append(os
.path
.basename(search
))
72 search
= os
.path
.dirname(search
)
75 stab
= os
.lstat(search
)
76 except FileNotFoundError
:
78 if stat
.S_ISREG(stab
.st_mode
):
81 while not os
.path
.ismount(search
):
82 if s
.src_likeparent(search
):
84 if len(xinfo
): infol
.append('want=' + os
.path
.join(*xinfo
))
89 # no .git found anywhere
92 def src_prenormaliser(s
, d
, infol
): # callers may monkey-patch away
93 return os
.path
.join(s
.cwd
, os
.path
.abspath(d
))
95 def src_find_rune(s
, d
):
96 script
= s
.find_rune_base
97 for excl
in s
.excludes
+ [s
.output_name
, s
.manifest_name
]:
98 assert("'" not in excl
)
99 script
+= r
" \! -name '%s'" % excl
103 def manifest_append(s
, name
, infol
):
104 s
._manifest
.append((name
, ' '.join(infol
)))
106 def new_output_name(s
, nametail
, infol
):
108 name
= '%04d-%s' %
(s
._outcounter
, nametail
)
109 s
.manifest_append(name
, infol
)
112 def open_output_fh(s
, name
, mode
):
113 return open(os
.path
.join(s
._destdir
, name
), mode
)
115 def mk_from_dir(s
, d
, infol
):
116 try: name
= s
._dirmap
[d
]
117 except KeyError: pass
119 s
.manifest_append(name
, infol
)
122 if s
.show_pathnames
: infol
.append(d
)
123 find_rune
= s
.src_find_rune(d
)
124 total_rune
= s
.rune_cpio % find_rune
126 name
= s
.new_output_name('src.cpio', infol
)
128 fh
= s
.open_output_fh(name
, 'wb')
130 subprocess
.run(s
.rune_shell
+ [total_rune
],
132 stdin
=subprocess
.DEVNULL
,
134 restore_signals
=True,
138 def mk_from_src(s
, d
, infol
):
139 d
= s
.src_prenormaliser(d
, infol
)
140 if not s
.src_filter(d
): return
141 d
= s
.src_parentfinder(d
, infol
)
142 s
.mk_from_dir(d
, infol
)
144 def mk_from_module(s
, m
, infol
):
145 try: file = m
.__file__
146 except AttributeError: return
147 infol
.append(m
.__name__
)
148 s
.mk_from_src(file, infol
)
149 s
.manifest_append(None, ['spong',file])
150 #s.report_from_package(file, infol)
152 def mk_from_srcs(s
, dirs
=sys
.path
):
153 s
.mk_from_src(sys
.argv
[0], ['argv[0]'])
155 s
.mk_from_src(d
, ['sys.path'])
156 for m
in sys
.modules
.values():
157 s
.mk_from_module(m
, ['sys.modules'])
159 def mk_portmanteau(s
):
160 cmdl
= s
.rune_shell
+ [ s
.rune_portmanteau
, 'x',
161 s
.output_name
, s
.manifest_name
]
162 mfh
= s
.open_output_fh(s
.manifest_name
,'w')
163 for (name
, info
) in s
._manifest
:
164 if name
is not None: cmdl
.append(name
)
165 print('%s\t%s' %
(name
,info
), file=mfh
)
169 stdin
=subprocess
.DEVNULL
,
171 restore_signals
=True,