1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#!/usr/bin/env python
# vim:fileencoding=utf-8
# Ultra-optimized Manifest writing.
# (c) 2017 Michał Górny
# Licensed under the terms of 2-clause BSD license
import errno
import glob
import gzip
import hashlib
import io
import os
import os.path
import sys
def get_manifest_entry(t, path, relpath):
sha512 = hashlib.sha512()
blake2 = hashlib.blake2b()
with io.open(path, 'rb') as f:
buf = f.read()
sha512.update(buf)
blake2.update(buf)
size = len(buf)
return ('{} {} {} BLAKE2B {} SHA512 {}'.format(t, relpath,
size, blake2.hexdigest(), sha512.hexdigest())).encode('utf8')
def generate_manifest_entries(out, topdir):
compat_mode = False
for dirpath, dirs, files in os.walk(topdir):
if dirpath != topdir:
for f in files:
if f in ('Manifest', 'Manifest.gz'):
fp = os.path.join(dirpath, f)
out.append(get_manifest_entry('MANIFEST',
fp, os.path.relpath(fp, topdir)))
# do not descend
del dirs[:]
skip = True
break
else:
skip = False
if skip:
continue
else:
# enable compat mode for ebuild directories
if any(f.endswith('.ebuild') and f != 'skel.ebuild' for f in files):
compat_mode = True
# skip dot-dirs
dotdirs = [d for d in dirs if d.startswith('.')]
for d in dotdirs:
dirs.remove(d)
for f in files:
if f.startswith('Manifest') or f.startswith('.'):
continue
fp = os.path.join(dirpath, f)
ep = os.path.relpath(fp, topdir)
ftype = 'DATA'
if compat_mode:
if f.endswith('.ebuild') and f != 'skel.ebuild':
ftype = 'EBUILD'
elif f == 'metadata.xml':
ftype = 'MISC'
elif ep.startswith('files/'):
ftype = 'AUX'
ep = ep[6:]
else:
if f in ('timestamp', 'timestamp.chk', 'timestamp.commit',
'timestamp.x'):
continue
out.append(get_manifest_entry(ftype, fp, ep))
return compat_mode
def gen_manifest(top_dir):
manifest_entries = []
# load DIST and IGNORE entries from existing Manifest
try:
with io.open(os.path.join(top_dir, 'Manifest'), 'rb') as f:
for l in f:
if l.startswith(b'DIST') or l.startswith(b'IGNORE'):
manifest_entries.append(l.rstrip())
had_manifest = True
except IOError as e:
if e.errno != errno.ENOENT:
raise
had_manifest = False
# generate local file entries
compat_mode = generate_manifest_entries(manifest_entries, top_dir)
manifest_entries.sort()
manifest_data = b'\n'.join(manifest_entries) + b'\n'
if not compat_mode:
with open(os.path.join(top_dir, 'Manifest.gz'), 'wb') as f:
with gzip.GzipFile(fileobj=f, mode='wb', filename='', mtime=0) as gzf:
gzf.write(manifest_data)
if had_manifest:
os.unlink(os.path.join(top_dir, 'Manifest'))
else:
with io.open(os.path.join(top_dir, 'Manifest'), 'wb') as f:
f.write(manifest_data)
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: {} <directory>...'.format(sys.argv[0]))
sys.exit(1)
for path in sys.argv[1:]:
gen_manifest(path)
|