3 ### GNU Affero General Public License compliance
5 ### (c) 2013 Mark Wooding
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of Chopwood: a password-changing service.
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.
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.
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/>.
26 import contextlib
as CTX
32 import subprocess
as SUB
38 from cStringIO
import StringIO
40 from auto
import PACKAGE
, VERSION
47 finally: SH
.rmtree(d
, ignore_errors
= True)
51 for m
in SYS
.modules
.itervalues():
53 except AttributeError: continue
54 d
= OS
.path
.realpath(OS
.path
.dirname(f
))
55 if d
.startswith('/usr/') and not d
.startswith('/usr/local/'): continue
61 if d
.startswith(last
): continue
66 def exists_subdir(subdir
):
67 return lambda dir: OS
.path
.isdir(OS
.path
.join(dir, subdir
))
71 kid
= SUB
.Popen(SL
.split(cmd
), stdout
= SUB
.PIPE
, cwd
= dir)
74 buf
= kid
.stdout
.read(16384)
84 if f
.startswith('./'): f
= f
[2:]
88 raise U
.ExpectedError
, \
89 (500, "trailing junk from `%s' in `%s'" %
(cmd
, dir))
93 (exists_subdir('.git'), [filez('git ls-files -coz --exclude-standard'),
94 filez('find .git -print0')]),
95 (lambda d
: True, [filez('find . ( ! -perm +004 -prune ) -o -print0')])]
97 def dump_dir(name
, dir, dirmap
, tf
, root
):
98 for test
, listers
in DUMPERS
:
101 raise U
.ExpectedError
, (500, "no dumper for `%s'" % dir
)
102 tf
.add(dir, OS
.path
.join(root
, name
), recursive
= False)
103 for lister
in listers
:
104 for file in lister(dir):
105 full
= OS
.path
.join(dir, file)
106 tarname
= OS
.path
.join(root
, name
, file)
108 if OS
.path
.islink(full
):
109 dest
= OS
.path
.realpath(full
)
110 for d
, local
in dirmap
:
111 if dest
.startswith(d
):
112 fix
= OS
.path
.relpath(OS
.path
.join('/', local
, dest
[len(d
):]),
113 OS
.path
.join('/', name
,
114 OS
.path
.dirname(file)))
116 ti
= tf
.gettarinfo(full
, tarname
)
121 tf
.add(full
, tarname
, recursive
= False)
124 if SYS
.version_info
>= (2, 6):
125 tf
= TAR
.open(fileobj
= out
, mode
= 'w|gz', format
= TAR
.USTAR_FORMAT
)
127 tf
= TAR
.open(fileobj
= out
, mode
= 'w|gz')
129 root
= '%s-%s' %
(PACKAGE
, VERSION
)
133 for dir in dirs_to_dump():
134 dir = dir.rstrip('/')
135 base
= OS
.path
.basename(dir)
140 name
= '%s.%d' %
(base
, i
)
141 if name
not in seen
: break
142 dirmap
.append((dir + '/', name
))
143 festout
.write('%s = %s\n' %
(name
, dir))
144 fest
= festout
.getvalue()
145 ti
= TAR
.TarInfo(OS
.path
.join(root
, 'MANIFEST'))
149 ti
.type = TAR
.REGTYPE
150 uid
= OS
.getuid(); ti
.uid
, ti
.uname
= uid
, PW
.getpwuid(uid
).pw_name
151 gid
= OS
.getgid(); ti
.gid
, ti
.gname
= gid
, GR
.getgrgid(gid
).gr_name
152 tf
.addfile(ti
, fileobj
= StringIO(fest
))
153 for dir, name
in dirmap
:
154 dump_dir(name
, dir, dirmap
, tf
, root
)
157 ###----- That's all, folks --------------------------------------------------