Lines 7-12
from __future__ import print_function
Link Here
|
7 |
import errno |
7 |
import errno |
8 |
import signal |
8 |
import signal |
9 |
import sys |
9 |
import sys |
|
|
10 |
import tarfile |
10 |
|
11 |
|
11 |
try: |
12 |
try: |
12 |
import portage |
13 |
import portage |
Lines 16-37
except ImportError:
Link Here
|
16 |
import portage |
17 |
import portage |
17 |
|
18 |
|
18 |
from portage import os |
19 |
from portage import os |
|
|
20 |
from portage import catsplit, flatten, isvalidatom, xpak |
21 |
from portage.dbapi.dep_expand import dep_expand |
22 |
from portage.dep import use_reduce, paren_reduce |
23 |
from portage.exception import InvalidAtom, InvalidData, InvalidDependString, PackageSetNotFound |
24 |
from portage.util import ConfigProtect, ensure_dirs |
25 |
from portage.dbapi.vartree import dblink, tar_contents |
26 |
from portage.checksum import perform_md5 |
27 |
from portage.sets import load_default_config, SETPREFIX |
28 |
|
29 |
def quickpkg_atom(options, infos, arg, eout): |
30 |
root = portage.settings["ROOT"] |
31 |
trees = portage.db[root] |
32 |
vartree = trees["vartree"] |
33 |
vardb = vartree.dbapi |
34 |
bintree = trees["bintree"] |
35 |
|
36 |
include_config = options.include_config == "y" |
37 |
include_unmodified_config = options.include_unmodified_config == "y" |
38 |
fix_metadata_keys = ["PF", "CATEGORY"] |
39 |
|
40 |
try: |
41 |
atom = dep_expand(arg, mydb=vardb, settings=vartree.settings) |
42 |
except ValueError as e: |
43 |
# Multiple matches thrown from cpv_expand |
44 |
eout.eerror("Please use a more specific atom: %s" % \ |
45 |
" ".join(e.args[0])) |
46 |
del e |
47 |
infos["missing"].append(arg) |
48 |
return |
49 |
except (InvalidAtom, InvalidData): |
50 |
eout.eerror("Invalid atom: %s" % (arg,)) |
51 |
infos["missing"].append(arg) |
52 |
return |
53 |
if atom[:1] == '=' and arg[:1] != '=': |
54 |
# dep_expand() allows missing '=' but it's really invalid |
55 |
eout.eerror("Invalid atom: %s" % (arg,)) |
56 |
infos["missing"].append(arg) |
57 |
return |
58 |
|
59 |
matches = vardb.match(atom) |
60 |
pkgs_for_arg = 0 |
61 |
for cpv in matches: |
62 |
excluded_config_files = [] |
63 |
bintree.prevent_collision(cpv) |
64 |
cat, pkg = catsplit(cpv) |
65 |
dblnk = dblink(cat, pkg, root, |
66 |
vartree.settings, treetype="vartree", |
67 |
vartree=vartree) |
68 |
dblnk.lockdb() |
69 |
try: |
70 |
if not dblnk.exists(): |
71 |
# unmerged by a concurrent process |
72 |
continue |
73 |
iuse, use, restrict = vardb.aux_get(cpv, |
74 |
["IUSE","USE","RESTRICT"]) |
75 |
iuse = [ x.lstrip("+-") for x in iuse.split() ] |
76 |
use = use.split() |
77 |
try: |
78 |
restrict = flatten(use_reduce( |
79 |
paren_reduce(restrict), uselist=use)) |
80 |
except InvalidDependString as e: |
81 |
eout.eerror("Invalid RESTRICT metadata " + \ |
82 |
"for '%s': %s; skipping" % (cpv, str(e))) |
83 |
del e |
84 |
continue |
85 |
if "bindist" in iuse and "bindist" not in use: |
86 |
eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv) |
87 |
eout.ewarn("%s: it may not be legal to redistribute this." % cpv) |
88 |
elif "bindist" in restrict: |
89 |
eout.ewarn("%s: package has RESTRICT=bindist!" % cpv) |
90 |
eout.ewarn("%s: it may not be legal to redistribute this." % cpv) |
91 |
eout.ebegin("Building package for %s" % cpv) |
92 |
pkgs_for_arg += 1 |
93 |
contents = dblnk.getcontents() |
94 |
protect = None |
95 |
if not include_config: |
96 |
confprot = ConfigProtect(root, |
97 |
portage.settings.get("CONFIG_PROTECT","").split(), |
98 |
portage.settings.get("CONFIG_PROTECT_MASK","").split()) |
99 |
def protect(filename): |
100 |
if not confprot.isprotected(filename): |
101 |
return False |
102 |
if include_unmodified_config: |
103 |
file_data = contents[filename] |
104 |
if file_data[0] == "obj": |
105 |
orig_md5 = file_data[2].lower() |
106 |
cur_md5 = perform_md5(filename, calc_prelink=1) |
107 |
if orig_md5 == cur_md5: |
108 |
return False |
109 |
excluded_config_files.append(filename) |
110 |
return True |
111 |
existing_metadata = dict(zip(fix_metadata_keys, |
112 |
vardb.aux_get(cpv, fix_metadata_keys))) |
113 |
category, pf = portage.catsplit(cpv) |
114 |
required_metadata = {} |
115 |
required_metadata["CATEGORY"] = category |
116 |
required_metadata["PF"] = pf |
117 |
update_metadata = {} |
118 |
for k, v in required_metadata.items(): |
119 |
if v != existing_metadata[k]: |
120 |
update_metadata[k] = v |
121 |
if update_metadata: |
122 |
vardb.aux_update(cpv, update_metadata) |
123 |
xpdata = xpak.xpak(dblnk.dbdir) |
124 |
binpkg_tmpfile = os.path.join(bintree.pkgdir, |
125 |
cpv + ".tbz2." + str(os.getpid())) |
126 |
ensure_dirs(os.path.dirname(binpkg_tmpfile)) |
127 |
tar = tarfile.open(binpkg_tmpfile, "w:bz2") |
128 |
tar_contents(contents, root, tar, protect=protect) |
129 |
tar.close() |
130 |
xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata) |
131 |
finally: |
132 |
dblnk.unlockdb() |
133 |
bintree.inject(cpv, filename=binpkg_tmpfile) |
134 |
binpkg_path = bintree.getname(cpv) |
135 |
try: |
136 |
s = os.stat(binpkg_path) |
137 |
except OSError as e: |
138 |
# Sanity check, shouldn't happen normally. |
139 |
eout.eend(1) |
140 |
eout.eerror(str(e)) |
141 |
del e |
142 |
eout.eerror("Failed to create package: '%s'" % binpkg_path) |
143 |
else: |
144 |
eout.eend(0) |
145 |
infos["successes"].append((cpv, s.st_size)) |
146 |
infos["config_files_excluded"] += len(excluded_config_files) |
147 |
for filename in excluded_config_files: |
148 |
eout.ewarn("Excluded config: '%s'" % filename) |
149 |
if not pkgs_for_arg: |
150 |
eout.eerror("Could not find anything " + \ |
151 |
"to match '%s'; skipping" % arg) |
152 |
infos["missing"].append(arg) |
153 |
|
154 |
def quickpkg_set(options, infos, arg, eout): |
155 |
root = portage.settings["ROOT"] |
156 |
trees = portage.db[root] |
157 |
vartree = trees["vartree"] |
158 |
|
159 |
settings = vartree.settings |
160 |
settings._init_dirs() |
161 |
setconfig = load_default_config(settings, trees) |
162 |
sets = setconfig.getSets() |
163 |
|
164 |
set = arg[1:] |
165 |
if not set in sets: |
166 |
eout.eerror("Package set not found: '%s'; skipping" % (arg,)) |
167 |
infos["missing"].append(arg) |
168 |
return |
169 |
|
170 |
try: |
171 |
atoms = setconfig.getSetAtoms(set) |
172 |
except PackageSetNotFound as e: |
173 |
eout.eerror("Failed to process package set '%s' because " % set + |
174 |
"it contains the non-existent package set '%s'; skipping" % e) |
175 |
infos["missing"].append(arg) |
176 |
return |
177 |
|
178 |
for atom in atoms: |
179 |
quickpkg_atom(options, infos, atom, eout) |
19 |
|
180 |
|
20 |
def quickpkg_main(options, args, eout): |
181 |
def quickpkg_main(options, args, eout): |
21 |
from portage import catsplit, flatten, isvalidatom, xpak |
|
|
22 |
from portage.dbapi.dep_expand import dep_expand |
23 |
from portage.dep import use_reduce, paren_reduce |
24 |
from portage.util import ConfigProtect, ensure_dirs |
25 |
from portage.exception import InvalidAtom, InvalidData, InvalidDependString |
26 |
from portage.dbapi.vartree import dblink, tar_contents |
27 |
from portage.checksum import perform_md5 |
28 |
import tarfile |
29 |
import portage |
30 |
root = portage.settings["ROOT"] |
182 |
root = portage.settings["ROOT"] |
31 |
trees = portage.db[root] |
183 |
trees = portage.db[root] |
32 |
vartree = trees["vartree"] |
184 |
vartree = trees["vartree"] |
33 |
vardb = vartree.dbapi |
185 |
vardb = vartree.dbapi |
34 |
bintree = trees["bintree"] |
186 |
bintree = trees["bintree"] |
|
|
187 |
|
35 |
try: |
188 |
try: |
36 |
ensure_dirs(bintree.pkgdir) |
189 |
ensure_dirs(bintree.pkgdir) |
37 |
except portage.exception.PortageException: |
190 |
except portage.exception.PortageException: |
Lines 39-165
def quickpkg_main(options, args, eout):
Link Here
|
39 |
if not os.access(bintree.pkgdir, os.W_OK): |
192 |
if not os.access(bintree.pkgdir, os.W_OK): |
40 |
eout.eerror("No write access to '%s'" % bintree.pkgdir) |
193 |
eout.eerror("No write access to '%s'" % bintree.pkgdir) |
41 |
return errno.EACCES |
194 |
return errno.EACCES |
42 |
successes = [] |
195 |
|
43 |
missing = [] |
196 |
infos = {} |
44 |
config_files_excluded = 0 |
197 |
infos["successes"] = [] |
45 |
include_config = options.include_config == "y" |
198 |
infos["missing"] = [] |
46 |
include_unmodified_config = options.include_unmodified_config == "y" |
199 |
infos["config_files_excluded"] = 0 |
47 |
fix_metadata_keys = ["PF", "CATEGORY"] |
|
|
48 |
for arg in args: |
200 |
for arg in args: |
49 |
try: |
201 |
if arg[0] == SETPREFIX: |
50 |
atom = dep_expand(arg, mydb=vardb, settings=vartree.settings) |
202 |
quickpkg_set(options, infos, arg, eout) |
51 |
except ValueError as e: |
203 |
else: |
52 |
# Multiple matches thrown from cpv_expand |
204 |
quickpkg_atom(options, infos, arg, eout) |
53 |
eout.eerror("Please use a more specific atom: %s" % \ |
205 |
|
54 |
" ".join(e.args[0])) |
206 |
if not infos["successes"]: |
55 |
del e |
|
|
56 |
missing.append(arg) |
57 |
continue |
58 |
except (InvalidAtom, InvalidData): |
59 |
eout.eerror("Invalid atom: %s" % (arg,)) |
60 |
missing.append(arg) |
61 |
continue |
62 |
if atom[:1] == '=' and arg[:1] != '=': |
63 |
# dep_expand() allows missing '=' but it's really invalid |
64 |
eout.eerror("Invalid atom: %s" % (arg,)) |
65 |
missing.append(arg) |
66 |
continue |
67 |
|
68 |
matches = vardb.match(atom) |
69 |
pkgs_for_arg = 0 |
70 |
for cpv in matches: |
71 |
excluded_config_files = [] |
72 |
bintree.prevent_collision(cpv) |
73 |
cat, pkg = catsplit(cpv) |
74 |
dblnk = dblink(cat, pkg, root, |
75 |
vartree.settings, treetype="vartree", |
76 |
vartree=vartree) |
77 |
dblnk.lockdb() |
78 |
try: |
79 |
if not dblnk.exists(): |
80 |
# unmerged by a concurrent process |
81 |
continue |
82 |
iuse, use, restrict = vardb.aux_get(cpv, |
83 |
["IUSE","USE","RESTRICT"]) |
84 |
iuse = [ x.lstrip("+-") for x in iuse.split() ] |
85 |
use = use.split() |
86 |
try: |
87 |
restrict = flatten(use_reduce( |
88 |
paren_reduce(restrict), uselist=use)) |
89 |
except InvalidDependString as e: |
90 |
eout.eerror("Invalid RESTRICT metadata " + \ |
91 |
"for '%s': %s; skipping" % (cpv, str(e))) |
92 |
del e |
93 |
continue |
94 |
if "bindist" in iuse and "bindist" not in use: |
95 |
eout.ewarn("%s: package was emerged with USE=-bindist!" % cpv) |
96 |
eout.ewarn("%s: it may not be legal to redistribute this." % cpv) |
97 |
elif "bindist" in restrict: |
98 |
eout.ewarn("%s: package has RESTRICT=bindist!" % cpv) |
99 |
eout.ewarn("%s: it may not be legal to redistribute this." % cpv) |
100 |
eout.ebegin("Building package for %s" % cpv) |
101 |
pkgs_for_arg += 1 |
102 |
contents = dblnk.getcontents() |
103 |
protect = None |
104 |
if not include_config: |
105 |
confprot = ConfigProtect(root, |
106 |
portage.settings.get("CONFIG_PROTECT","").split(), |
107 |
portage.settings.get("CONFIG_PROTECT_MASK","").split()) |
108 |
def protect(filename): |
109 |
if not confprot.isprotected(filename): |
110 |
return False |
111 |
if include_unmodified_config: |
112 |
file_data = contents[filename] |
113 |
if file_data[0] == "obj": |
114 |
orig_md5 = file_data[2].lower() |
115 |
cur_md5 = perform_md5(filename, calc_prelink=1) |
116 |
if orig_md5 == cur_md5: |
117 |
return False |
118 |
excluded_config_files.append(filename) |
119 |
return True |
120 |
existing_metadata = dict(zip(fix_metadata_keys, |
121 |
vardb.aux_get(cpv, fix_metadata_keys))) |
122 |
category, pf = portage.catsplit(cpv) |
123 |
required_metadata = {} |
124 |
required_metadata["CATEGORY"] = category |
125 |
required_metadata["PF"] = pf |
126 |
update_metadata = {} |
127 |
for k, v in required_metadata.items(): |
128 |
if v != existing_metadata[k]: |
129 |
update_metadata[k] = v |
130 |
if update_metadata: |
131 |
vardb.aux_update(cpv, update_metadata) |
132 |
xpdata = xpak.xpak(dblnk.dbdir) |
133 |
binpkg_tmpfile = os.path.join(bintree.pkgdir, |
134 |
cpv + ".tbz2." + str(os.getpid())) |
135 |
ensure_dirs(os.path.dirname(binpkg_tmpfile)) |
136 |
tar = tarfile.open(binpkg_tmpfile, "w:bz2") |
137 |
tar_contents(contents, root, tar, protect=protect) |
138 |
tar.close() |
139 |
xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata) |
140 |
finally: |
141 |
dblnk.unlockdb() |
142 |
bintree.inject(cpv, filename=binpkg_tmpfile) |
143 |
binpkg_path = bintree.getname(cpv) |
144 |
try: |
145 |
s = os.stat(binpkg_path) |
146 |
except OSError as e: |
147 |
# Sanity check, shouldn't happen normally. |
148 |
eout.eend(1) |
149 |
eout.eerror(str(e)) |
150 |
del e |
151 |
eout.eerror("Failed to create package: '%s'" % binpkg_path) |
152 |
else: |
153 |
eout.eend(0) |
154 |
successes.append((cpv, s.st_size)) |
155 |
config_files_excluded += len(excluded_config_files) |
156 |
for filename in excluded_config_files: |
157 |
eout.ewarn("Excluded config: '%s'" % filename) |
158 |
if not pkgs_for_arg: |
159 |
eout.eerror("Could not find anything " + \ |
160 |
"to match '%s'; skipping" % arg) |
161 |
missing.append(arg) |
162 |
if not successes: |
163 |
eout.eerror("No packages found") |
207 |
eout.eerror("No packages found") |
164 |
return 1 |
208 |
return 1 |
165 |
print() |
209 |
print() |
Lines 167-173
def quickpkg_main(options, args, eout):
Link Here
|
167 |
import math |
211 |
import math |
168 |
units = {10:'K', 20:'M', 30:'G', 40:'T', |
212 |
units = {10:'K', 20:'M', 30:'G', 40:'T', |
169 |
50:'P', 60:'E', 70:'Z', 80:'Y'} |
213 |
50:'P', 60:'E', 70:'Z', 80:'Y'} |
170 |
for cpv, size in successes: |
214 |
for cpv, size in infos["successes"]: |
171 |
if not size: |
215 |
if not size: |
172 |
# avoid OverflowError in math.log() |
216 |
# avoid OverflowError in math.log() |
173 |
size_str = "0" |
217 |
size_str = "0" |
Lines 185-203
def quickpkg_main(options, args, eout):
Link Here
|
185 |
else: |
229 |
else: |
186 |
size_str = str(size) |
230 |
size_str = str(size) |
187 |
eout.einfo("%s: %s" % (cpv, size_str)) |
231 |
eout.einfo("%s: %s" % (cpv, size_str)) |
188 |
if config_files_excluded: |
232 |
if infos["config_files_excluded"]: |
189 |
print() |
233 |
print() |
190 |
eout.ewarn("Excluded config files: %d" % config_files_excluded) |
234 |
eout.ewarn("Excluded config files: %d" % infos["config_files_excluded"]) |
191 |
eout.ewarn("See --help if you would like to include config files.") |
235 |
eout.ewarn("See --help if you would like to include config files.") |
192 |
if missing: |
236 |
if infos["missing"]: |
193 |
print() |
237 |
print() |
194 |
eout.ewarn("The following packages could not be found:") |
238 |
eout.ewarn("The following packages could not be found:") |
195 |
eout.ewarn(" ".join(missing)) |
239 |
eout.ewarn(" ".join(infos["missing"])) |
196 |
return 2 |
240 |
return 2 |
197 |
return os.EX_OK |
241 |
return os.EX_OK |
198 |
|
242 |
|
199 |
if __name__ == "__main__": |
243 |
if __name__ == "__main__": |
200 |
usage = "quickpkg [options] <list of package atoms>" |
244 |
usage = "quickpkg [options] <list of package atoms or package sets>" |
201 |
from optparse import OptionParser |
245 |
from optparse import OptionParser |
202 |
parser = OptionParser(usage=usage) |
246 |
parser = OptionParser(usage=usage) |
203 |
parser.add_option("--umask", |
247 |
parser.add_option("--umask", |