1 |
Author: zmedico |
2 |
Date: 2009-06-26 20:06:08 +0000 (Fri, 26 Jun 2009) |
3 |
New Revision: 13697 |
4 |
|
5 |
Added: |
6 |
main/trunk/pym/_emerge/main.py |
7 |
Removed: |
8 |
main/trunk/pym/_emerge/__init__.py |
9 |
Log: |
10 |
Move __init__.py to main.py. |
11 |
|
12 |
|
13 |
Deleted: main/trunk/pym/_emerge/__init__.py |
14 |
=================================================================== |
15 |
--- main/trunk/pym/_emerge/__init__.py 2009-06-25 21:59:58 UTC (rev 13696) |
16 |
+++ main/trunk/pym/_emerge/__init__.py 2009-06-26 20:06:08 UTC (rev 13697) |
17 |
@@ -1,1282 +0,0 @@ |
18 |
-# Copyright 1999-2009 Gentoo Foundation |
19 |
-# Distributed under the terms of the GNU General Public License v2 |
20 |
-# $Id$ |
21 |
- |
22 |
-import logging |
23 |
-import shlex |
24 |
-import signal |
25 |
-import sys |
26 |
-import textwrap |
27 |
-import os |
28 |
-import platform |
29 |
- |
30 |
-try: |
31 |
- import portage |
32 |
-except ImportError: |
33 |
- from os import path as osp |
34 |
- sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) |
35 |
- import portage |
36 |
- |
37 |
-import _emerge.help |
38 |
-import portage.xpak, commands, errno, re, time |
39 |
-from portage.output import colorize, xtermTitleReset |
40 |
-from portage.output import create_color_func |
41 |
-good = create_color_func("GOOD") |
42 |
-bad = create_color_func("BAD") |
43 |
- |
44 |
-import portage.elog |
45 |
-import portage.dep |
46 |
-portage.dep._dep_check_strict = True |
47 |
-import portage.util |
48 |
-import portage.locks |
49 |
-import portage.exception |
50 |
-from portage.data import secpass |
51 |
-from portage.util import normalize_path as normpath |
52 |
-from portage.util import writemsg, writemsg_level |
53 |
-from portage.sets import SETPREFIX |
54 |
- |
55 |
-from _emerge.actions import action_config, action_sync, action_metadata, \ |
56 |
- action_regen, action_search, action_uninstall, action_info, action_build, \ |
57 |
- adjust_config, chk_updated_cfg_files, display_missing_pkg_set, \ |
58 |
- display_news_notification, getportageversion, load_emerge_config |
59 |
-from _emerge.emergelog import emergelog |
60 |
-from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo |
61 |
-from _emerge.is_valid_package_atom import is_valid_package_atom |
62 |
-from _emerge.stdout_spinner import stdout_spinner |
63 |
- |
64 |
-options=[ |
65 |
-"--ask", "--alphabetical", |
66 |
-"--buildpkg", "--buildpkgonly", |
67 |
-"--changelog", "--columns", |
68 |
-"--complete-graph", |
69 |
-"--debug", "--deep", |
70 |
-"--digest", |
71 |
-"--emptytree", |
72 |
-"--fetchonly", "--fetch-all-uri", |
73 |
-"--getbinpkg", "--getbinpkgonly", |
74 |
-"--help", "--ignore-default-opts", |
75 |
-"--keep-going", |
76 |
-"--noconfmem", |
77 |
-"--newuse", |
78 |
-"--nodeps", "--noreplace", |
79 |
-"--nospinner", "--oneshot", |
80 |
-"--onlydeps", "--pretend", |
81 |
-"--quiet", "--resume", |
82 |
-"--searchdesc", "--selective", |
83 |
-"--skipfirst", |
84 |
-"--tree", |
85 |
-"--update", |
86 |
-"--usepkg", "--usepkgonly", |
87 |
-"--verbose", |
88 |
-] |
89 |
- |
90 |
-shortmapping={ |
91 |
-"1":"--oneshot", |
92 |
-"a":"--ask", |
93 |
-"b":"--buildpkg", "B":"--buildpkgonly", |
94 |
-"c":"--clean", "C":"--unmerge", |
95 |
-"d":"--debug", "D":"--deep", |
96 |
-"e":"--emptytree", |
97 |
-"f":"--fetchonly", "F":"--fetch-all-uri", |
98 |
-"g":"--getbinpkg", "G":"--getbinpkgonly", |
99 |
-"h":"--help", |
100 |
-"k":"--usepkg", "K":"--usepkgonly", |
101 |
-"l":"--changelog", |
102 |
-"n":"--noreplace", "N":"--newuse", |
103 |
-"o":"--onlydeps", "O":"--nodeps", |
104 |
-"p":"--pretend", "P":"--prune", |
105 |
-"q":"--quiet", |
106 |
-"s":"--search", "S":"--searchdesc", |
107 |
-"t":"--tree", |
108 |
-"u":"--update", |
109 |
-"v":"--verbose", "V":"--version" |
110 |
-} |
111 |
- |
112 |
-def chk_updated_info_files(root, infodirs, prev_mtimes, retval): |
113 |
- |
114 |
- if os.path.exists("/usr/bin/install-info"): |
115 |
- out = portage.output.EOutput() |
116 |
- regen_infodirs=[] |
117 |
- for z in infodirs: |
118 |
- if z=='': |
119 |
- continue |
120 |
- inforoot=normpath(root+z) |
121 |
- if os.path.isdir(inforoot): |
122 |
- infomtime = long(os.stat(inforoot).st_mtime) |
123 |
- if inforoot not in prev_mtimes or \ |
124 |
- prev_mtimes[inforoot] != infomtime: |
125 |
- regen_infodirs.append(inforoot) |
126 |
- |
127 |
- if not regen_infodirs: |
128 |
- portage.writemsg_stdout("\n") |
129 |
- out.einfo("GNU info directory index is up-to-date.") |
130 |
- else: |
131 |
- portage.writemsg_stdout("\n") |
132 |
- out.einfo("Regenerating GNU info directory index...") |
133 |
- |
134 |
- dir_extensions = ("", ".gz", ".bz2") |
135 |
- icount=0 |
136 |
- badcount=0 |
137 |
- errmsg = "" |
138 |
- for inforoot in regen_infodirs: |
139 |
- if inforoot=='': |
140 |
- continue |
141 |
- |
142 |
- if not os.path.isdir(inforoot) or \ |
143 |
- not os.access(inforoot, os.W_OK): |
144 |
- continue |
145 |
- |
146 |
- file_list = os.listdir(inforoot) |
147 |
- file_list.sort() |
148 |
- dir_file = os.path.join(inforoot, "dir") |
149 |
- moved_old_dir = False |
150 |
- processed_count = 0 |
151 |
- for x in file_list: |
152 |
- if x.startswith(".") or \ |
153 |
- os.path.isdir(os.path.join(inforoot, x)): |
154 |
- continue |
155 |
- if x.startswith("dir"): |
156 |
- skip = False |
157 |
- for ext in dir_extensions: |
158 |
- if x == "dir" + ext or \ |
159 |
- x == "dir" + ext + ".old": |
160 |
- skip = True |
161 |
- break |
162 |
- if skip: |
163 |
- continue |
164 |
- if processed_count == 0: |
165 |
- for ext in dir_extensions: |
166 |
- try: |
167 |
- os.rename(dir_file + ext, dir_file + ext + ".old") |
168 |
- moved_old_dir = True |
169 |
- except EnvironmentError, e: |
170 |
- if e.errno != errno.ENOENT: |
171 |
- raise |
172 |
- del e |
173 |
- processed_count += 1 |
174 |
- myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] |
175 |
- existsstr="already exists, for file `" |
176 |
- if myso!="": |
177 |
- if re.search(existsstr,myso): |
178 |
- # Already exists... Don't increment the count for this. |
179 |
- pass |
180 |
- elif myso[:44]=="install-info: warning: no info dir entry in ": |
181 |
- # This info file doesn't contain a DIR-header: install-info produces this |
182 |
- # (harmless) warning (the --quiet switch doesn't seem to work). |
183 |
- # Don't increment the count for this. |
184 |
- pass |
185 |
- else: |
186 |
- badcount=badcount+1 |
187 |
- errmsg += myso + "\n" |
188 |
- icount=icount+1 |
189 |
- |
190 |
- if moved_old_dir and not os.path.exists(dir_file): |
191 |
- # We didn't generate a new dir file, so put the old file |
192 |
- # back where it was originally found. |
193 |
- for ext in dir_extensions: |
194 |
- try: |
195 |
- os.rename(dir_file + ext + ".old", dir_file + ext) |
196 |
- except EnvironmentError, e: |
197 |
- if e.errno != errno.ENOENT: |
198 |
- raise |
199 |
- del e |
200 |
- |
201 |
- # Clean dir.old cruft so that they don't prevent |
202 |
- # unmerge of otherwise empty directories. |
203 |
- for ext in dir_extensions: |
204 |
- try: |
205 |
- os.unlink(dir_file + ext + ".old") |
206 |
- except EnvironmentError, e: |
207 |
- if e.errno != errno.ENOENT: |
208 |
- raise |
209 |
- del e |
210 |
- |
211 |
- #update mtime so we can potentially avoid regenerating. |
212 |
- prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime) |
213 |
- |
214 |
- if badcount: |
215 |
- out.eerror("Processed %d info files; %d errors." % \ |
216 |
- (icount, badcount)) |
217 |
- writemsg_level(errmsg, level=logging.ERROR, noiselevel=-1) |
218 |
- else: |
219 |
- if icount > 0: |
220 |
- out.einfo("Processed %d info files." % (icount,)) |
221 |
- |
222 |
- |
223 |
-def display_preserved_libs(vardbapi): |
224 |
- MAX_DISPLAY = 3 |
225 |
- |
226 |
- # Ensure the registry is consistent with existing files. |
227 |
- vardbapi.plib_registry.pruneNonExisting() |
228 |
- |
229 |
- if vardbapi.plib_registry.hasEntries(): |
230 |
- print |
231 |
- print colorize("WARN", "!!!") + " existing preserved libs:" |
232 |
- plibdata = vardbapi.plib_registry.getPreservedLibs() |
233 |
- linkmap = vardbapi.linkmap |
234 |
- consumer_map = {} |
235 |
- owners = {} |
236 |
- linkmap_broken = False |
237 |
- |
238 |
- try: |
239 |
- linkmap.rebuild() |
240 |
- except portage.exception.CommandNotFound, e: |
241 |
- writemsg_level("!!! Command Not Found: %s\n" % (e,), |
242 |
- level=logging.ERROR, noiselevel=-1) |
243 |
- del e |
244 |
- linkmap_broken = True |
245 |
- else: |
246 |
- search_for_owners = set() |
247 |
- for cpv in plibdata: |
248 |
- internal_plib_keys = set(linkmap._obj_key(f) \ |
249 |
- for f in plibdata[cpv]) |
250 |
- for f in plibdata[cpv]: |
251 |
- if f in consumer_map: |
252 |
- continue |
253 |
- consumers = [] |
254 |
- for c in linkmap.findConsumers(f): |
255 |
- # Filter out any consumers that are also preserved libs |
256 |
- # belonging to the same package as the provider. |
257 |
- if linkmap._obj_key(c) not in internal_plib_keys: |
258 |
- consumers.append(c) |
259 |
- consumers.sort() |
260 |
- consumer_map[f] = consumers |
261 |
- search_for_owners.update(consumers[:MAX_DISPLAY+1]) |
262 |
- |
263 |
- owners = vardbapi._owners.getFileOwnerMap(search_for_owners) |
264 |
- |
265 |
- for cpv in plibdata: |
266 |
- print colorize("WARN", ">>>") + " package: %s" % cpv |
267 |
- samefile_map = {} |
268 |
- for f in plibdata[cpv]: |
269 |
- obj_key = linkmap._obj_key(f) |
270 |
- alt_paths = samefile_map.get(obj_key) |
271 |
- if alt_paths is None: |
272 |
- alt_paths = set() |
273 |
- samefile_map[obj_key] = alt_paths |
274 |
- alt_paths.add(f) |
275 |
- |
276 |
- for alt_paths in samefile_map.itervalues(): |
277 |
- alt_paths = sorted(alt_paths) |
278 |
- for p in alt_paths: |
279 |
- print colorize("WARN", " * ") + " - %s" % (p,) |
280 |
- f = alt_paths[0] |
281 |
- consumers = consumer_map.get(f, []) |
282 |
- for c in consumers[:MAX_DISPLAY]: |
283 |
- print colorize("WARN", " * ") + " used by %s (%s)" % \ |
284 |
- (c, ", ".join(x.mycpv for x in owners.get(c, []))) |
285 |
- if len(consumers) == MAX_DISPLAY + 1: |
286 |
- print colorize("WARN", " * ") + " used by %s (%s)" % \ |
287 |
- (consumers[MAX_DISPLAY], ", ".join(x.mycpv \ |
288 |
- for x in owners.get(consumers[MAX_DISPLAY], []))) |
289 |
- elif len(consumers) > MAX_DISPLAY: |
290 |
- print colorize("WARN", " * ") + " used by %d other files" % (len(consumers) - MAX_DISPLAY) |
291 |
- print "Use " + colorize("GOOD", "emerge @preserved-rebuild") + " to rebuild packages using these libraries" |
292 |
- |
293 |
- |
294 |
-def post_emerge(root_config, myopts, mtimedb, retval): |
295 |
- """ |
296 |
- Misc. things to run at the end of a merge session. |
297 |
- |
298 |
- Update Info Files |
299 |
- Update Config Files |
300 |
- Update News Items |
301 |
- Commit mtimeDB |
302 |
- Display preserved libs warnings |
303 |
- Exit Emerge |
304 |
- |
305 |
- @param trees: A dictionary mapping each ROOT to it's package databases |
306 |
- @type trees: dict |
307 |
- @param mtimedb: The mtimeDB to store data needed across merge invocations |
308 |
- @type mtimedb: MtimeDB class instance |
309 |
- @param retval: Emerge's return value |
310 |
- @type retval: Int |
311 |
- @rype: None |
312 |
- @returns: |
313 |
- 1. Calls sys.exit(retval) |
314 |
- """ |
315 |
- |
316 |
- target_root = root_config.root |
317 |
- trees = { target_root : root_config.trees } |
318 |
- vardbapi = trees[target_root]["vartree"].dbapi |
319 |
- settings = vardbapi.settings |
320 |
- info_mtimes = mtimedb["info"] |
321 |
- |
322 |
- # Load the most current variables from ${ROOT}/etc/profile.env |
323 |
- settings.unlock() |
324 |
- settings.reload() |
325 |
- settings.regenerate() |
326 |
- settings.lock() |
327 |
- |
328 |
- config_protect = settings.get("CONFIG_PROTECT","").split() |
329 |
- infodirs = settings.get("INFOPATH","").split(":") + \ |
330 |
- settings.get("INFODIR","").split(":") |
331 |
- |
332 |
- os.chdir("/") |
333 |
- |
334 |
- if retval == os.EX_OK: |
335 |
- exit_msg = " *** exiting successfully." |
336 |
- else: |
337 |
- exit_msg = " *** exiting unsuccessfully with status '%s'." % retval |
338 |
- emergelog("notitles" not in settings.features, exit_msg) |
339 |
- |
340 |
- _flush_elog_mod_echo() |
341 |
- |
342 |
- counter_hash = settings.get("PORTAGE_COUNTER_HASH") |
343 |
- if "--pretend" in myopts or (counter_hash is not None and \ |
344 |
- counter_hash == vardbapi._counter_hash()): |
345 |
- display_news_notification(root_config, myopts) |
346 |
- # If vdb state has not changed then there's nothing else to do. |
347 |
- sys.exit(retval) |
348 |
- |
349 |
- vdb_path = os.path.join(target_root, portage.VDB_PATH) |
350 |
- portage.util.ensure_dirs(vdb_path) |
351 |
- vdb_lock = None |
352 |
- if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts: |
353 |
- vdb_lock = portage.locks.lockdir(vdb_path) |
354 |
- |
355 |
- if vdb_lock: |
356 |
- try: |
357 |
- if "noinfo" not in settings.features: |
358 |
- chk_updated_info_files(target_root, |
359 |
- infodirs, info_mtimes, retval) |
360 |
- mtimedb.commit() |
361 |
- finally: |
362 |
- if vdb_lock: |
363 |
- portage.locks.unlockdir(vdb_lock) |
364 |
- |
365 |
- chk_updated_cfg_files(target_root, config_protect) |
366 |
- |
367 |
- display_news_notification(root_config, myopts) |
368 |
- if retval in (None, os.EX_OK) or (not "--pretend" in myopts): |
369 |
- display_preserved_libs(vardbapi) |
370 |
- |
371 |
- sys.exit(retval) |
372 |
- |
373 |
- |
374 |
-def multiple_actions(action1, action2): |
375 |
- sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n") |
376 |
- sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2)) |
377 |
- sys.exit(1) |
378 |
- |
379 |
-def insert_optional_args(args): |
380 |
- """ |
381 |
- Parse optional arguments and insert a value if one has |
382 |
- not been provided. This is done before feeding the args |
383 |
- to the optparse parser since that parser does not support |
384 |
- this feature natively. |
385 |
- """ |
386 |
- |
387 |
- new_args = [] |
388 |
- jobs_opts = ("-j", "--jobs") |
389 |
- default_arg_opts = { |
390 |
- '--deselect' : ('n',), |
391 |
- '--root-deps' : ('rdeps',), |
392 |
- } |
393 |
- arg_stack = args[:] |
394 |
- arg_stack.reverse() |
395 |
- while arg_stack: |
396 |
- arg = arg_stack.pop() |
397 |
- |
398 |
- default_arg_choices = default_arg_opts.get(arg) |
399 |
- if default_arg_choices is not None: |
400 |
- new_args.append(arg) |
401 |
- if arg_stack and arg_stack[-1] in default_arg_choices: |
402 |
- new_args.append(arg_stack.pop()) |
403 |
- else: |
404 |
- # insert default argument |
405 |
- new_args.append('True') |
406 |
- continue |
407 |
- |
408 |
- short_job_opt = bool("j" in arg and arg[:1] == "-" and arg[:2] != "--") |
409 |
- if not (short_job_opt or arg in jobs_opts): |
410 |
- new_args.append(arg) |
411 |
- continue |
412 |
- |
413 |
- # Insert an empty placeholder in order to |
414 |
- # satisfy the requirements of optparse. |
415 |
- |
416 |
- new_args.append("--jobs") |
417 |
- job_count = None |
418 |
- saved_opts = None |
419 |
- if short_job_opt and len(arg) > 2: |
420 |
- if arg[:2] == "-j": |
421 |
- try: |
422 |
- job_count = int(arg[2:]) |
423 |
- except ValueError: |
424 |
- saved_opts = arg[2:] |
425 |
- else: |
426 |
- job_count = "True" |
427 |
- saved_opts = arg[1:].replace("j", "") |
428 |
- |
429 |
- if job_count is None and arg_stack: |
430 |
- try: |
431 |
- job_count = int(arg_stack[-1]) |
432 |
- except ValueError: |
433 |
- pass |
434 |
- else: |
435 |
- # Discard the job count from the stack |
436 |
- # since we're consuming it here. |
437 |
- arg_stack.pop() |
438 |
- |
439 |
- if job_count is None: |
440 |
- # unlimited number of jobs |
441 |
- new_args.append("True") |
442 |
- else: |
443 |
- new_args.append(str(job_count)) |
444 |
- |
445 |
- if saved_opts is not None: |
446 |
- new_args.append("-" + saved_opts) |
447 |
- |
448 |
- return new_args |
449 |
- |
450 |
-def parse_opts(tmpcmdline, silent=False): |
451 |
- myaction=None |
452 |
- myopts = {} |
453 |
- myfiles=[] |
454 |
- |
455 |
- global options, shortmapping |
456 |
- |
457 |
- actions = frozenset([ |
458 |
- "clean", "config", "depclean", |
459 |
- "info", "list-sets", "metadata", |
460 |
- "prune", "regen", "search", |
461 |
- "sync", "unmerge", "version", |
462 |
- ]) |
463 |
- |
464 |
- longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} |
465 |
- argument_options = { |
466 |
- "--config-root": { |
467 |
- "help":"specify the location for portage configuration files", |
468 |
- "action":"store" |
469 |
- }, |
470 |
- "--color": { |
471 |
- "help":"enable or disable color output", |
472 |
- "type":"choice", |
473 |
- "choices":("y", "n") |
474 |
- }, |
475 |
- |
476 |
- "--deselect": { |
477 |
- "help" : "remove atoms from the world file", |
478 |
- "type" : "choice", |
479 |
- "choices" : ("True", "n") |
480 |
- }, |
481 |
- |
482 |
- "--jobs": { |
483 |
- |
484 |
- "help" : "Specifies the number of packages to build " + \ |
485 |
- "simultaneously.", |
486 |
- |
487 |
- "action" : "store" |
488 |
- }, |
489 |
- |
490 |
- "--load-average": { |
491 |
- |
492 |
- "help" :"Specifies that no new builds should be started " + \ |
493 |
- "if there are other builds running and the load average " + \ |
494 |
- "is at least LOAD (a floating-point number).", |
495 |
- |
496 |
- "action" : "store" |
497 |
- }, |
498 |
- |
499 |
- "--with-bdeps": { |
500 |
- "help":"include unnecessary build time dependencies", |
501 |
- "type":"choice", |
502 |
- "choices":("y", "n") |
503 |
- }, |
504 |
- "--reinstall": { |
505 |
- "help":"specify conditions to trigger package reinstallation", |
506 |
- "type":"choice", |
507 |
- "choices":["changed-use"] |
508 |
- }, |
509 |
- "--root": { |
510 |
- "help" : "specify the target root filesystem for merging packages", |
511 |
- "action" : "store" |
512 |
- }, |
513 |
- |
514 |
- "--root-deps": { |
515 |
- "help" : "modify interpretation of depedencies", |
516 |
- "type" : "choice", |
517 |
- "choices" :("True", "rdeps") |
518 |
- }, |
519 |
- } |
520 |
- |
521 |
- from optparse import OptionParser |
522 |
- parser = OptionParser() |
523 |
- if parser.has_option("--help"): |
524 |
- parser.remove_option("--help") |
525 |
- |
526 |
- for action_opt in actions: |
527 |
- parser.add_option("--" + action_opt, action="store_true", |
528 |
- dest=action_opt.replace("-", "_"), default=False) |
529 |
- for myopt in options: |
530 |
- parser.add_option(myopt, action="store_true", |
531 |
- dest=myopt.lstrip("--").replace("-", "_"), default=False) |
532 |
- for shortopt, longopt in shortmapping.iteritems(): |
533 |
- parser.add_option("-" + shortopt, action="store_true", |
534 |
- dest=longopt.lstrip("--").replace("-", "_"), default=False) |
535 |
- for myalias, myopt in longopt_aliases.iteritems(): |
536 |
- parser.add_option(myalias, action="store_true", |
537 |
- dest=myopt.lstrip("--").replace("-", "_"), default=False) |
538 |
- |
539 |
- for myopt, kwargs in argument_options.iteritems(): |
540 |
- parser.add_option(myopt, |
541 |
- dest=myopt.lstrip("--").replace("-", "_"), **kwargs) |
542 |
- |
543 |
- tmpcmdline = insert_optional_args(tmpcmdline) |
544 |
- |
545 |
- myoptions, myargs = parser.parse_args(args=tmpcmdline) |
546 |
- |
547 |
- if myoptions.deselect == "True": |
548 |
- myoptions.deselect = True |
549 |
- |
550 |
- if myoptions.root_deps == "True": |
551 |
- myoptions.root_deps = True |
552 |
- |
553 |
- if myoptions.jobs: |
554 |
- jobs = None |
555 |
- if myoptions.jobs == "True": |
556 |
- jobs = True |
557 |
- else: |
558 |
- try: |
559 |
- jobs = int(myoptions.jobs) |
560 |
- except ValueError: |
561 |
- jobs = -1 |
562 |
- |
563 |
- if jobs is not True and \ |
564 |
- jobs < 1: |
565 |
- jobs = None |
566 |
- if not silent: |
567 |
- writemsg("!!! Invalid --jobs parameter: '%s'\n" % \ |
568 |
- (myoptions.jobs,), noiselevel=-1) |
569 |
- |
570 |
- myoptions.jobs = jobs |
571 |
- |
572 |
- if myoptions.load_average: |
573 |
- try: |
574 |
- load_average = float(myoptions.load_average) |
575 |
- except ValueError: |
576 |
- load_average = 0.0 |
577 |
- |
578 |
- if load_average <= 0.0: |
579 |
- load_average = None |
580 |
- if not silent: |
581 |
- writemsg("!!! Invalid --load-average parameter: '%s'\n" % \ |
582 |
- (myoptions.load_average,), noiselevel=-1) |
583 |
- |
584 |
- myoptions.load_average = load_average |
585 |
- |
586 |
- for myopt in options: |
587 |
- v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) |
588 |
- if v: |
589 |
- myopts[myopt] = True |
590 |
- |
591 |
- for myopt in argument_options: |
592 |
- v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) |
593 |
- if v is not None: |
594 |
- myopts[myopt] = v |
595 |
- |
596 |
- if myoptions.searchdesc: |
597 |
- myoptions.search = True |
598 |
- |
599 |
- for action_opt in actions: |
600 |
- v = getattr(myoptions, action_opt.replace("-", "_")) |
601 |
- if v: |
602 |
- if myaction: |
603 |
- multiple_actions(myaction, action_opt) |
604 |
- sys.exit(1) |
605 |
- myaction = action_opt |
606 |
- |
607 |
- if myaction is None and myoptions.deselect is True: |
608 |
- myaction = 'deselect' |
609 |
- |
610 |
- myfiles += myargs |
611 |
- |
612 |
- return myaction, myopts, myfiles |
613 |
- |
614 |
-def validate_ebuild_environment(trees): |
615 |
- for myroot in trees: |
616 |
- settings = trees[myroot]["vartree"].settings |
617 |
- settings.validate() |
618 |
- |
619 |
-def apply_priorities(settings): |
620 |
- ionice(settings) |
621 |
- nice(settings) |
622 |
- |
623 |
-def nice(settings): |
624 |
- try: |
625 |
- os.nice(int(settings.get("PORTAGE_NICENESS", "0"))) |
626 |
- except (OSError, ValueError), e: |
627 |
- out = portage.output.EOutput() |
628 |
- out.eerror("Failed to change nice value to '%s'" % \ |
629 |
- settings["PORTAGE_NICENESS"]) |
630 |
- out.eerror("%s\n" % str(e)) |
631 |
- |
632 |
-def ionice(settings): |
633 |
- |
634 |
- ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND") |
635 |
- if ionice_cmd: |
636 |
- ionice_cmd = shlex.split(ionice_cmd) |
637 |
- if not ionice_cmd: |
638 |
- return |
639 |
- |
640 |
- from portage.util import varexpand |
641 |
- variables = {"PID" : str(os.getpid())} |
642 |
- cmd = [varexpand(x, mydict=variables) for x in ionice_cmd] |
643 |
- |
644 |
- try: |
645 |
- rval = portage.process.spawn(cmd, env=os.environ) |
646 |
- except portage.exception.CommandNotFound: |
647 |
- # The OS kernel probably doesn't support ionice, |
648 |
- # so return silently. |
649 |
- return |
650 |
- |
651 |
- if rval != os.EX_OK: |
652 |
- out = portage.output.EOutput() |
653 |
- out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,)) |
654 |
- out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.") |
655 |
- |
656 |
-def expand_set_arguments(myfiles, myaction, root_config): |
657 |
- retval = os.EX_OK |
658 |
- setconfig = root_config.setconfig |
659 |
- |
660 |
- sets = setconfig.getSets() |
661 |
- |
662 |
- # In order to know exactly which atoms/sets should be added to the |
663 |
- # world file, the depgraph performs set expansion later. It will get |
664 |
- # confused about where the atoms came from if it's not allowed to |
665 |
- # expand them itself. |
666 |
- do_not_expand = (None, ) |
667 |
- newargs = [] |
668 |
- for a in myfiles: |
669 |
- if a in ("system", "world"): |
670 |
- newargs.append(SETPREFIX+a) |
671 |
- else: |
672 |
- newargs.append(a) |
673 |
- myfiles = newargs |
674 |
- del newargs |
675 |
- newargs = [] |
676 |
- |
677 |
- # separators for set arguments |
678 |
- ARG_START = "{" |
679 |
- ARG_END = "}" |
680 |
- |
681 |
- # WARNING: all operators must be of equal length |
682 |
- IS_OPERATOR = "/@" |
683 |
- DIFF_OPERATOR = "-@" |
684 |
- UNION_OPERATOR = "+@" |
685 |
- |
686 |
- for i in range(0, len(myfiles)): |
687 |
- if myfiles[i].startswith(SETPREFIX): |
688 |
- start = 0 |
689 |
- end = 0 |
690 |
- x = myfiles[i][len(SETPREFIX):] |
691 |
- newset = "" |
692 |
- while x: |
693 |
- start = x.find(ARG_START) |
694 |
- end = x.find(ARG_END) |
695 |
- if start > 0 and start < end: |
696 |
- namepart = x[:start] |
697 |
- argpart = x[start+1:end] |
698 |
- |
699 |
- # TODO: implement proper quoting |
700 |
- args = argpart.split(",") |
701 |
- options = {} |
702 |
- for a in args: |
703 |
- if "=" in a: |
704 |
- k, v = a.split("=", 1) |
705 |
- options[k] = v |
706 |
- else: |
707 |
- options[a] = "True" |
708 |
- setconfig.update(namepart, options) |
709 |
- newset += (x[:start-len(namepart)]+namepart) |
710 |
- x = x[end+len(ARG_END):] |
711 |
- else: |
712 |
- newset += x |
713 |
- x = "" |
714 |
- myfiles[i] = SETPREFIX+newset |
715 |
- |
716 |
- sets = setconfig.getSets() |
717 |
- |
718 |
- # display errors that occured while loading the SetConfig instance |
719 |
- for e in setconfig.errors: |
720 |
- print colorize("BAD", "Error during set creation: %s" % e) |
721 |
- |
722 |
- # emerge relies on the existance of sets with names "world" and "system" |
723 |
- required_sets = ("world", "system") |
724 |
- missing_sets = [] |
725 |
- |
726 |
- for s in required_sets: |
727 |
- if s not in sets: |
728 |
- missing_sets.append(s) |
729 |
- if missing_sets: |
730 |
- if len(missing_sets) > 2: |
731 |
- missing_sets_str = ", ".join('"%s"' % s for s in missing_sets[:-1]) |
732 |
- missing_sets_str += ', and "%s"' % missing_sets[-1] |
733 |
- elif len(missing_sets) == 2: |
734 |
- missing_sets_str = '"%s" and "%s"' % tuple(missing_sets) |
735 |
- else: |
736 |
- missing_sets_str = '"%s"' % missing_sets[-1] |
737 |
- msg = ["emerge: incomplete set configuration, " + \ |
738 |
- "missing set(s): %s" % missing_sets_str] |
739 |
- if sets: |
740 |
- msg.append(" sets defined: %s" % ", ".join(sets)) |
741 |
- msg.append(" This usually means that '%s'" % \ |
742 |
- (os.path.join(portage.const.GLOBAL_CONFIG_PATH, "sets.conf"),)) |
743 |
- msg.append(" is missing or corrupt.") |
744 |
- for line in msg: |
745 |
- writemsg_level(line + "\n", level=logging.ERROR, noiselevel=-1) |
746 |
- return (None, 1) |
747 |
- unmerge_actions = ("unmerge", "prune", "clean", "depclean") |
748 |
- |
749 |
- for a in myfiles: |
750 |
- if a.startswith(SETPREFIX): |
751 |
- # support simple set operations (intersection, difference and union) |
752 |
- # on the commandline. Expressions are evaluated strictly left-to-right |
753 |
- if IS_OPERATOR in a or DIFF_OPERATOR in a or UNION_OPERATOR in a: |
754 |
- expression = a[len(SETPREFIX):] |
755 |
- expr_sets = [] |
756 |
- expr_ops = [] |
757 |
- while IS_OPERATOR in expression or DIFF_OPERATOR in expression or UNION_OPERATOR in expression: |
758 |
- is_pos = expression.rfind(IS_OPERATOR) |
759 |
- diff_pos = expression.rfind(DIFF_OPERATOR) |
760 |
- union_pos = expression.rfind(UNION_OPERATOR) |
761 |
- op_pos = max(is_pos, diff_pos, union_pos) |
762 |
- s1 = expression[:op_pos] |
763 |
- s2 = expression[op_pos+len(IS_OPERATOR):] |
764 |
- op = expression[op_pos:op_pos+len(IS_OPERATOR)] |
765 |
- if not s2 in sets: |
766 |
- display_missing_pkg_set(root_config, s2) |
767 |
- return (None, 1) |
768 |
- expr_sets.insert(0, s2) |
769 |
- expr_ops.insert(0, op) |
770 |
- expression = s1 |
771 |
- if not expression in sets: |
772 |
- display_missing_pkg_set(root_config, expression) |
773 |
- return (None, 1) |
774 |
- expr_sets.insert(0, expression) |
775 |
- result = set(setconfig.getSetAtoms(expression)) |
776 |
- for i in range(0, len(expr_ops)): |
777 |
- s2 = setconfig.getSetAtoms(expr_sets[i+1]) |
778 |
- if expr_ops[i] == IS_OPERATOR: |
779 |
- result.intersection_update(s2) |
780 |
- elif expr_ops[i] == DIFF_OPERATOR: |
781 |
- result.difference_update(s2) |
782 |
- elif expr_ops[i] == UNION_OPERATOR: |
783 |
- result.update(s2) |
784 |
- else: |
785 |
- raise NotImplementedError("unknown set operator %s" % expr_ops[i]) |
786 |
- newargs.extend(result) |
787 |
- else: |
788 |
- s = a[len(SETPREFIX):] |
789 |
- if s not in sets: |
790 |
- display_missing_pkg_set(root_config, s) |
791 |
- return (None, 1) |
792 |
- setconfig.active.append(s) |
793 |
- try: |
794 |
- set_atoms = setconfig.getSetAtoms(s) |
795 |
- except portage.exception.PackageSetNotFound, e: |
796 |
- writemsg_level(("emerge: the given set '%s' " + \ |
797 |
- "contains a non-existent set named '%s'.\n") % \ |
798 |
- (s, e), level=logging.ERROR, noiselevel=-1) |
799 |
- return (None, 1) |
800 |
- if myaction in unmerge_actions and \ |
801 |
- not sets[s].supportsOperation("unmerge"): |
802 |
- sys.stderr.write("emerge: the given set '%s' does " % s + \ |
803 |
- "not support unmerge operations\n") |
804 |
- retval = 1 |
805 |
- elif not set_atoms: |
806 |
- print "emerge: '%s' is an empty set" % s |
807 |
- elif myaction not in do_not_expand: |
808 |
- newargs.extend(set_atoms) |
809 |
- else: |
810 |
- newargs.append(SETPREFIX+s) |
811 |
- for e in sets[s].errors: |
812 |
- print e |
813 |
- else: |
814 |
- newargs.append(a) |
815 |
- return (newargs, retval) |
816 |
- |
817 |
-def repo_name_check(trees): |
818 |
- missing_repo_names = set() |
819 |
- for root, root_trees in trees.iteritems(): |
820 |
- if "porttree" in root_trees: |
821 |
- portdb = root_trees["porttree"].dbapi |
822 |
- missing_repo_names.update(portdb.porttrees) |
823 |
- repos = portdb.getRepositories() |
824 |
- for r in repos: |
825 |
- missing_repo_names.discard(portdb.getRepositoryPath(r)) |
826 |
- if portdb.porttree_root in missing_repo_names and \ |
827 |
- not os.path.exists(os.path.join( |
828 |
- portdb.porttree_root, "profiles")): |
829 |
- # This is normal if $PORTDIR happens to be empty, |
830 |
- # so don't warn about it. |
831 |
- missing_repo_names.remove(portdb.porttree_root) |
832 |
- |
833 |
- if missing_repo_names: |
834 |
- msg = [] |
835 |
- msg.append("WARNING: One or more repositories " + \ |
836 |
- "have missing repo_name entries:") |
837 |
- msg.append("") |
838 |
- for p in missing_repo_names: |
839 |
- msg.append("\t%s/profiles/repo_name" % (p,)) |
840 |
- msg.append("") |
841 |
- msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \ |
842 |
- "should be a plain text file containing a unique " + \ |
843 |
- "name for the repository on the first line.", 70)) |
844 |
- writemsg_level("".join("%s\n" % l for l in msg), |
845 |
- level=logging.WARNING, noiselevel=-1) |
846 |
- |
847 |
- return bool(missing_repo_names) |
848 |
- |
849 |
-def repo_name_duplicate_check(trees): |
850 |
- ignored_repos = {} |
851 |
- for root, root_trees in trees.iteritems(): |
852 |
- if 'porttree' in root_trees: |
853 |
- portdb = root_trees['porttree'].dbapi |
854 |
- if portdb.mysettings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0': |
855 |
- for repo_name, paths in portdb._ignored_repos: |
856 |
- k = (root, repo_name, portdb.getRepositoryPath(repo_name)) |
857 |
- ignored_repos.setdefault(k, []).extend(paths) |
858 |
- |
859 |
- if ignored_repos: |
860 |
- msg = [] |
861 |
- msg.append('WARNING: One or more repositories ' + \ |
862 |
- 'have been ignored due to duplicate') |
863 |
- msg.append(' profiles/repo_name entries:') |
864 |
- msg.append('') |
865 |
- for k in sorted(ignored_repos): |
866 |
- msg.append(' %s overrides' % (k,)) |
867 |
- for path in ignored_repos[k]: |
868 |
- msg.append(' %s' % (path,)) |
869 |
- msg.append('') |
870 |
- msg.extend(' ' + x for x in textwrap.wrap( |
871 |
- "All profiles/repo_name entries must be unique in order " + \ |
872 |
- "to avoid having duplicates ignored. " + \ |
873 |
- "Set PORTAGE_REPO_DUPLICATE_WARN=\"0\" in " + \ |
874 |
- "/etc/make.conf if you would like to disable this warning.")) |
875 |
- writemsg_level(''.join('%s\n' % l for l in msg), |
876 |
- level=logging.WARNING, noiselevel=-1) |
877 |
- |
878 |
- return bool(ignored_repos) |
879 |
- |
880 |
-def config_protect_check(trees): |
881 |
- for root, root_trees in trees.iteritems(): |
882 |
- if not root_trees["root_config"].settings.get("CONFIG_PROTECT"): |
883 |
- msg = "!!! CONFIG_PROTECT is empty" |
884 |
- if root != "/": |
885 |
- msg += " for '%s'" % root |
886 |
- writemsg_level(msg, level=logging.WARN, noiselevel=-1) |
887 |
- |
888 |
-def profile_check(trees, myaction, myopts): |
889 |
- if myaction in ("info", "sync"): |
890 |
- return os.EX_OK |
891 |
- elif "--version" in myopts or "--help" in myopts: |
892 |
- return os.EX_OK |
893 |
- for root, root_trees in trees.iteritems(): |
894 |
- if root_trees["root_config"].settings.profiles: |
895 |
- continue |
896 |
- # generate some profile related warning messages |
897 |
- validate_ebuild_environment(trees) |
898 |
- msg = "If you have just changed your profile configuration, you " + \ |
899 |
- "should revert back to the previous configuration. Due to " + \ |
900 |
- "your current profile being invalid, allowed actions are " + \ |
901 |
- "limited to --help, --info, --sync, and --version." |
902 |
- writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)), |
903 |
- level=logging.ERROR, noiselevel=-1) |
904 |
- return 1 |
905 |
- return os.EX_OK |
906 |
- |
907 |
-def emerge_main(): |
908 |
- global portage # NFC why this is necessary now - genone |
909 |
- portage._disable_legacy_globals() |
910 |
- # Disable color until we're sure that it should be enabled (after |
911 |
- # EMERGE_DEFAULT_OPTS has been parsed). |
912 |
- portage.output.havecolor = 0 |
913 |
- # This first pass is just for options that need to be known as early as |
914 |
- # possible, such as --config-root. They will be parsed again later, |
915 |
- # together with EMERGE_DEFAULT_OPTS (which may vary depending on the |
916 |
- # the value of --config-root). |
917 |
- myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True) |
918 |
- if "--debug" in myopts: |
919 |
- os.environ["PORTAGE_DEBUG"] = "1" |
920 |
- if "--config-root" in myopts: |
921 |
- os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] |
922 |
- if "--root" in myopts: |
923 |
- os.environ["ROOT"] = myopts["--root"] |
924 |
- |
925 |
- # Portage needs to ensure a sane umask for the files it creates. |
926 |
- os.umask(022) |
927 |
- settings, trees, mtimedb = load_emerge_config() |
928 |
- portdb = trees[settings["ROOT"]]["porttree"].dbapi |
929 |
- rval = profile_check(trees, myaction, myopts) |
930 |
- if rval != os.EX_OK: |
931 |
- return rval |
932 |
- |
933 |
- if portage._global_updates(trees, mtimedb["updates"]): |
934 |
- mtimedb.commit() |
935 |
- # Reload the whole config from scratch. |
936 |
- settings, trees, mtimedb = load_emerge_config(trees=trees) |
937 |
- portdb = trees[settings["ROOT"]]["porttree"].dbapi |
938 |
- |
939 |
- xterm_titles = "notitles" not in settings.features |
940 |
- |
941 |
- tmpcmdline = [] |
942 |
- if "--ignore-default-opts" not in myopts: |
943 |
- tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) |
944 |
- tmpcmdline.extend(sys.argv[1:]) |
945 |
- myaction, myopts, myfiles = parse_opts(tmpcmdline) |
946 |
- |
947 |
- if "--digest" in myopts: |
948 |
- os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" |
949 |
- # Reload the whole config from scratch so that the portdbapi internal |
950 |
- # config is updated with new FEATURES. |
951 |
- settings, trees, mtimedb = load_emerge_config(trees=trees) |
952 |
- portdb = trees[settings["ROOT"]]["porttree"].dbapi |
953 |
- |
954 |
- for myroot in trees: |
955 |
- mysettings = trees[myroot]["vartree"].settings |
956 |
- mysettings.unlock() |
957 |
- adjust_config(myopts, mysettings) |
958 |
- if '--pretend' not in myopts and myaction in \ |
959 |
- (None, 'clean', 'depclean', 'prune', 'unmerge'): |
960 |
- mysettings["PORTAGE_COUNTER_HASH"] = \ |
961 |
- trees[myroot]["vartree"].dbapi._counter_hash() |
962 |
- mysettings.backup_changes("PORTAGE_COUNTER_HASH") |
963 |
- mysettings.lock() |
964 |
- del myroot, mysettings |
965 |
- |
966 |
- apply_priorities(settings) |
967 |
- |
968 |
- spinner = stdout_spinner() |
969 |
- if "candy" in settings.features: |
970 |
- spinner.update = spinner.update_scroll |
971 |
- |
972 |
- if "--quiet" not in myopts: |
973 |
- portage.deprecated_profile_check(settings=settings) |
974 |
- repo_name_check(trees) |
975 |
- repo_name_duplicate_check(trees) |
976 |
- config_protect_check(trees) |
977 |
- |
978 |
- for mytrees in trees.itervalues(): |
979 |
- mydb = mytrees["porttree"].dbapi |
980 |
- # Freeze the portdbapi for performance (memoize all xmatch results). |
981 |
- mydb.freeze() |
982 |
- del mytrees, mydb |
983 |
- |
984 |
- if "moo" in myfiles: |
985 |
- print """ |
986 |
- |
987 |
- Larry loves Gentoo (""" + platform.system() + """) |
988 |
- |
989 |
- _______________________ |
990 |
-< Have you mooed today? > |
991 |
- ----------------------- |
992 |
- \ ^__^ |
993 |
- \ (oo)\_______ |
994 |
- (__)\ )\/\ |
995 |
- ||----w | |
996 |
- || || |
997 |
- |
998 |
-""" |
999 |
- |
1000 |
- for x in myfiles: |
1001 |
- ext = os.path.splitext(x)[1] |
1002 |
- if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): |
1003 |
- print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n") |
1004 |
- break |
1005 |
- |
1006 |
- root_config = trees[settings["ROOT"]]["root_config"] |
1007 |
- if myaction == "list-sets": |
1008 |
- sys.stdout.write("".join("%s\n" % s for s in sorted(root_config.sets))) |
1009 |
- sys.stdout.flush() |
1010 |
- return os.EX_OK |
1011 |
- |
1012 |
- # only expand sets for actions taking package arguments |
1013 |
- oldargs = myfiles[:] |
1014 |
- if myaction in ("clean", "config", "depclean", "info", "prune", "unmerge", None): |
1015 |
- myfiles, retval = expand_set_arguments(myfiles, myaction, root_config) |
1016 |
- if retval != os.EX_OK: |
1017 |
- return retval |
1018 |
- |
1019 |
- # Need to handle empty sets specially, otherwise emerge will react |
1020 |
- # with the help message for empty argument lists |
1021 |
- if oldargs and not myfiles: |
1022 |
- print "emerge: no targets left after set expansion" |
1023 |
- return 0 |
1024 |
- |
1025 |
- if ("--tree" in myopts) and ("--columns" in myopts): |
1026 |
- print "emerge: can't specify both of \"--tree\" and \"--columns\"." |
1027 |
- return 1 |
1028 |
- |
1029 |
- if ("--quiet" in myopts): |
1030 |
- spinner.update = spinner.update_quiet |
1031 |
- portage.util.noiselimit = -1 |
1032 |
- |
1033 |
- # Always create packages if FEATURES=buildpkg |
1034 |
- # Imply --buildpkg if --buildpkgonly |
1035 |
- if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts): |
1036 |
- if "--buildpkg" not in myopts: |
1037 |
- myopts["--buildpkg"] = True |
1038 |
- |
1039 |
- # Always try and fetch binary packages if FEATURES=getbinpkg |
1040 |
- if ("getbinpkg" in settings.features): |
1041 |
- myopts["--getbinpkg"] = True |
1042 |
- |
1043 |
- if "--buildpkgonly" in myopts: |
1044 |
- # --buildpkgonly will not merge anything, so |
1045 |
- # it cancels all binary package options. |
1046 |
- for opt in ("--getbinpkg", "--getbinpkgonly", |
1047 |
- "--usepkg", "--usepkgonly"): |
1048 |
- myopts.pop(opt, None) |
1049 |
- |
1050 |
- if "--fetch-all-uri" in myopts: |
1051 |
- myopts["--fetchonly"] = True |
1052 |
- |
1053 |
- if "--skipfirst" in myopts and "--resume" not in myopts: |
1054 |
- myopts["--resume"] = True |
1055 |
- |
1056 |
- if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): |
1057 |
- myopts["--usepkgonly"] = True |
1058 |
- |
1059 |
- if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): |
1060 |
- myopts["--getbinpkg"] = True |
1061 |
- |
1062 |
- if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): |
1063 |
- myopts["--usepkg"] = True |
1064 |
- |
1065 |
- # Also allow -K to apply --usepkg/-k |
1066 |
- if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): |
1067 |
- myopts["--usepkg"] = True |
1068 |
- |
1069 |
- # Allow -p to remove --ask |
1070 |
- if "--pretend" in myopts: |
1071 |
- myopts.pop("--ask", None) |
1072 |
- |
1073 |
- # forbid --ask when not in a terminal |
1074 |
- # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. |
1075 |
- if ("--ask" in myopts) and (not sys.stdin.isatty()): |
1076 |
- portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", |
1077 |
- noiselevel=-1) |
1078 |
- return 1 |
1079 |
- |
1080 |
- if settings.get("PORTAGE_DEBUG", "") == "1": |
1081 |
- spinner.update = spinner.update_quiet |
1082 |
- portage.debug=1 |
1083 |
- if "python-trace" in settings.features: |
1084 |
- import portage.debug |
1085 |
- portage.debug.set_trace(True) |
1086 |
- |
1087 |
- if not ("--quiet" in myopts): |
1088 |
- if not sys.stdout.isatty() or ("--nospinner" in myopts): |
1089 |
- spinner.update = spinner.update_basic |
1090 |
- |
1091 |
- if myaction == 'version': |
1092 |
- print getportageversion(settings["PORTDIR"], settings["ROOT"], |
1093 |
- settings.profile_path, settings["CHOST"], |
1094 |
- trees[settings["ROOT"]]["vartree"].dbapi) |
1095 |
- return 0 |
1096 |
- elif "--help" in myopts: |
1097 |
- _emerge.help.help(myaction, myopts, portage.output.havecolor) |
1098 |
- return 0 |
1099 |
- |
1100 |
- if "--debug" in myopts: |
1101 |
- print "myaction", myaction |
1102 |
- print "myopts", myopts |
1103 |
- |
1104 |
- if not myaction and not myfiles and "--resume" not in myopts: |
1105 |
- _emerge.help.help(myaction, myopts, portage.output.havecolor) |
1106 |
- return 1 |
1107 |
- |
1108 |
- pretend = "--pretend" in myopts |
1109 |
- fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts |
1110 |
- buildpkgonly = "--buildpkgonly" in myopts |
1111 |
- |
1112 |
- # check if root user is the current user for the actions where emerge needs this |
1113 |
- if portage.secpass < 2: |
1114 |
- # We've already allowed "--version" and "--help" above. |
1115 |
- if "--pretend" not in myopts and myaction not in ("search","info"): |
1116 |
- need_superuser = myaction in ('clean', 'depclean', 'deselect', |
1117 |
- 'prune', 'unmerge') or not \ |
1118 |
- (fetchonly or \ |
1119 |
- (buildpkgonly and secpass >= 1) or \ |
1120 |
- myaction in ("metadata", "regen") or \ |
1121 |
- (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK))) |
1122 |
- if portage.secpass < 1 or \ |
1123 |
- need_superuser: |
1124 |
- if need_superuser: |
1125 |
- access_desc = "superuser" |
1126 |
- else: |
1127 |
- access_desc = "portage group" |
1128 |
- # Always show portage_group_warning() when only portage group |
1129 |
- # access is required but the user is not in the portage group. |
1130 |
- from portage.data import portage_group_warning |
1131 |
- if "--ask" in myopts: |
1132 |
- myopts["--pretend"] = True |
1133 |
- del myopts["--ask"] |
1134 |
- print ("%s access is required... " + \ |
1135 |
- "adding --pretend to options\n") % access_desc |
1136 |
- if portage.secpass < 1 and not need_superuser: |
1137 |
- portage_group_warning() |
1138 |
- else: |
1139 |
- sys.stderr.write(("emerge: %s access is required\n") \ |
1140 |
- % access_desc) |
1141 |
- if portage.secpass < 1 and not need_superuser: |
1142 |
- portage_group_warning() |
1143 |
- return 1 |
1144 |
- |
1145 |
- disable_emergelog = False |
1146 |
- for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): |
1147 |
- if x in myopts: |
1148 |
- disable_emergelog = True |
1149 |
- break |
1150 |
- if myaction in ("search", "info"): |
1151 |
- disable_emergelog = True |
1152 |
- if disable_emergelog: |
1153 |
- """ Disable emergelog for everything except build or unmerge |
1154 |
- operations. This helps minimize parallel emerge.log entries that can |
1155 |
- confuse log parsers. We especially want it disabled during |
1156 |
- parallel-fetch, which uses --resume --fetchonly.""" |
1157 |
- global emergelog |
1158 |
- def emergelog(*pargs, **kargs): |
1159 |
- pass |
1160 |
- |
1161 |
- else: |
1162 |
- if 'EMERGE_LOG_DIR' in settings: |
1163 |
- try: |
1164 |
- # At least the parent needs to exist for the lock file. |
1165 |
- portage.util.ensure_dirs(settings['EMERGE_LOG_DIR']) |
1166 |
- except portage.exception.PortageException, e: |
1167 |
- writemsg_level("!!! Error creating directory for " + \ |
1168 |
- "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \ |
1169 |
- (settings['EMERGE_LOG_DIR'], e), |
1170 |
- noiselevel=-1, level=logging.ERROR) |
1171 |
- else: |
1172 |
- global _emerge_log_dir |
1173 |
- _emerge_log_dir = settings['EMERGE_LOG_DIR'] |
1174 |
- |
1175 |
- if not "--pretend" in myopts: |
1176 |
- emergelog(xterm_titles, "Started emerge on: "+\ |
1177 |
- time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) |
1178 |
- myelogstr="" |
1179 |
- if myopts: |
1180 |
- myelogstr=" ".join(myopts) |
1181 |
- if myaction: |
1182 |
- myelogstr+=" "+myaction |
1183 |
- if myfiles: |
1184 |
- myelogstr += " " + " ".join(oldargs) |
1185 |
- emergelog(xterm_titles, " *** emerge " + myelogstr) |
1186 |
- del oldargs |
1187 |
- |
1188 |
- def emergeexitsig(signum, frame): |
1189 |
- signal.signal(signal.SIGINT, signal.SIG_IGN) |
1190 |
- signal.signal(signal.SIGTERM, signal.SIG_IGN) |
1191 |
- portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) |
1192 |
- sys.exit(100+signum) |
1193 |
- signal.signal(signal.SIGINT, emergeexitsig) |
1194 |
- signal.signal(signal.SIGTERM, emergeexitsig) |
1195 |
- |
1196 |
- def emergeexit(): |
1197 |
- """This gets out final log message in before we quit.""" |
1198 |
- if "--pretend" not in myopts: |
1199 |
- emergelog(xterm_titles, " *** terminating.") |
1200 |
- if "notitles" not in settings.features: |
1201 |
- xtermTitleReset() |
1202 |
- portage.atexit_register(emergeexit) |
1203 |
- |
1204 |
- if myaction in ("config", "metadata", "regen", "sync"): |
1205 |
- if "--pretend" in myopts: |
1206 |
- sys.stderr.write(("emerge: The '%s' action does " + \ |
1207 |
- "not support '--pretend'.\n") % myaction) |
1208 |
- return 1 |
1209 |
- |
1210 |
- if "sync" == myaction: |
1211 |
- return action_sync(settings, trees, mtimedb, myopts, myaction) |
1212 |
- elif "metadata" == myaction: |
1213 |
- action_metadata(settings, portdb, myopts) |
1214 |
- elif myaction=="regen": |
1215 |
- validate_ebuild_environment(trees) |
1216 |
- return action_regen(settings, portdb, myopts.get("--jobs"), |
1217 |
- myopts.get("--load-average")) |
1218 |
- # HELP action |
1219 |
- elif "config"==myaction: |
1220 |
- validate_ebuild_environment(trees) |
1221 |
- action_config(settings, trees, myopts, myfiles) |
1222 |
- |
1223 |
- # SEARCH action |
1224 |
- elif "search"==myaction: |
1225 |
- validate_ebuild_environment(trees) |
1226 |
- action_search(trees[settings["ROOT"]]["root_config"], |
1227 |
- myopts, myfiles, spinner) |
1228 |
- |
1229 |
- elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'): |
1230 |
- validate_ebuild_environment(trees) |
1231 |
- rval = action_uninstall(settings, trees, mtimedb["ldpath"], |
1232 |
- myopts, myaction, myfiles, spinner) |
1233 |
- if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend): |
1234 |
- post_emerge(root_config, myopts, mtimedb, rval) |
1235 |
- return rval |
1236 |
- |
1237 |
- elif myaction == 'info': |
1238 |
- |
1239 |
- # Ensure atoms are valid before calling unmerge(). |
1240 |
- vardb = trees[settings["ROOT"]]["vartree"].dbapi |
1241 |
- valid_atoms = [] |
1242 |
- for x in myfiles: |
1243 |
- if is_valid_package_atom(x): |
1244 |
- try: |
1245 |
- valid_atoms.append( |
1246 |
- portage.dep_expand(x, mydb=vardb, settings=settings)) |
1247 |
- except portage.exception.AmbiguousPackageName, e: |
1248 |
- msg = "The short ebuild name \"" + x + \ |
1249 |
- "\" is ambiguous. Please specify " + \ |
1250 |
- "one of the following " + \ |
1251 |
- "fully-qualified ebuild names instead:" |
1252 |
- for line in textwrap.wrap(msg, 70): |
1253 |
- writemsg_level("!!! %s\n" % (line,), |
1254 |
- level=logging.ERROR, noiselevel=-1) |
1255 |
- for i in e[0]: |
1256 |
- writemsg_level(" %s\n" % colorize("INFORM", i), |
1257 |
- level=logging.ERROR, noiselevel=-1) |
1258 |
- writemsg_level("\n", level=logging.ERROR, noiselevel=-1) |
1259 |
- return 1 |
1260 |
- continue |
1261 |
- msg = [] |
1262 |
- msg.append("'%s' is not a valid package atom." % (x,)) |
1263 |
- msg.append("Please check ebuild(5) for full details.") |
1264 |
- writemsg_level("".join("!!! %s\n" % line for line in msg), |
1265 |
- level=logging.ERROR, noiselevel=-1) |
1266 |
- return 1 |
1267 |
- |
1268 |
- return action_info(settings, trees, myopts, valid_atoms) |
1269 |
- |
1270 |
- # "update", "system", or just process files: |
1271 |
- else: |
1272 |
- validate_ebuild_environment(trees) |
1273 |
- |
1274 |
- for x in myfiles: |
1275 |
- if x.startswith(SETPREFIX) or \ |
1276 |
- is_valid_package_atom(x): |
1277 |
- continue |
1278 |
- if x[:1] == os.sep: |
1279 |
- continue |
1280 |
- try: |
1281 |
- os.lstat(x) |
1282 |
- continue |
1283 |
- except OSError: |
1284 |
- pass |
1285 |
- msg = [] |
1286 |
- msg.append("'%s' is not a valid package atom." % (x,)) |
1287 |
- msg.append("Please check ebuild(5) for full details.") |
1288 |
- writemsg_level("".join("!!! %s\n" % line for line in msg), |
1289 |
- level=logging.ERROR, noiselevel=-1) |
1290 |
- return 1 |
1291 |
- |
1292 |
- if "--pretend" not in myopts: |
1293 |
- display_news_notification(root_config, myopts) |
1294 |
- retval = action_build(settings, trees, mtimedb, |
1295 |
- myopts, myaction, myfiles, spinner) |
1296 |
- root_config = trees[settings["ROOT"]]["root_config"] |
1297 |
- post_emerge(root_config, myopts, mtimedb, retval) |
1298 |
- |
1299 |
- return retval |
1300 |
|
1301 |
Copied: main/trunk/pym/_emerge/main.py (from rev 13696, main/trunk/pym/_emerge/__init__.py) |
1302 |
=================================================================== |
1303 |
--- main/trunk/pym/_emerge/main.py (rev 0) |
1304 |
+++ main/trunk/pym/_emerge/main.py 2009-06-26 20:06:08 UTC (rev 13697) |
1305 |
@@ -0,0 +1,1282 @@ |
1306 |
+# Copyright 1999-2009 Gentoo Foundation |
1307 |
+# Distributed under the terms of the GNU General Public License v2 |
1308 |
+# $Id$ |
1309 |
+ |
1310 |
+import logging |
1311 |
+import shlex |
1312 |
+import signal |
1313 |
+import sys |
1314 |
+import textwrap |
1315 |
+import os |
1316 |
+import platform |
1317 |
+ |
1318 |
+try: |
1319 |
+ import portage |
1320 |
+except ImportError: |
1321 |
+ from os import path as osp |
1322 |
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) |
1323 |
+ import portage |
1324 |
+ |
1325 |
+import _emerge.help |
1326 |
+import portage.xpak, commands, errno, re, time |
1327 |
+from portage.output import colorize, xtermTitleReset |
1328 |
+from portage.output import create_color_func |
1329 |
+good = create_color_func("GOOD") |
1330 |
+bad = create_color_func("BAD") |
1331 |
+ |
1332 |
+import portage.elog |
1333 |
+import portage.dep |
1334 |
+portage.dep._dep_check_strict = True |
1335 |
+import portage.util |
1336 |
+import portage.locks |
1337 |
+import portage.exception |
1338 |
+from portage.data import secpass |
1339 |
+from portage.util import normalize_path as normpath |
1340 |
+from portage.util import writemsg, writemsg_level |
1341 |
+from portage.sets import SETPREFIX |
1342 |
+ |
1343 |
+from _emerge.actions import action_config, action_sync, action_metadata, \ |
1344 |
+ action_regen, action_search, action_uninstall, action_info, action_build, \ |
1345 |
+ adjust_config, chk_updated_cfg_files, display_missing_pkg_set, \ |
1346 |
+ display_news_notification, getportageversion, load_emerge_config |
1347 |
+from _emerge.emergelog import emergelog |
1348 |
+from _emerge._flush_elog_mod_echo import _flush_elog_mod_echo |
1349 |
+from _emerge.is_valid_package_atom import is_valid_package_atom |
1350 |
+from _emerge.stdout_spinner import stdout_spinner |
1351 |
+ |
1352 |
+options=[ |
1353 |
+"--ask", "--alphabetical", |
1354 |
+"--buildpkg", "--buildpkgonly", |
1355 |
+"--changelog", "--columns", |
1356 |
+"--complete-graph", |
1357 |
+"--debug", "--deep", |
1358 |
+"--digest", |
1359 |
+"--emptytree", |
1360 |
+"--fetchonly", "--fetch-all-uri", |
1361 |
+"--getbinpkg", "--getbinpkgonly", |
1362 |
+"--help", "--ignore-default-opts", |
1363 |
+"--keep-going", |
1364 |
+"--noconfmem", |
1365 |
+"--newuse", |
1366 |
+"--nodeps", "--noreplace", |
1367 |
+"--nospinner", "--oneshot", |
1368 |
+"--onlydeps", "--pretend", |
1369 |
+"--quiet", "--resume", |
1370 |
+"--searchdesc", "--selective", |
1371 |
+"--skipfirst", |
1372 |
+"--tree", |
1373 |
+"--update", |
1374 |
+"--usepkg", "--usepkgonly", |
1375 |
+"--verbose", |
1376 |
+] |
1377 |
+ |
1378 |
+shortmapping={ |
1379 |
+"1":"--oneshot", |
1380 |
+"a":"--ask", |
1381 |
+"b":"--buildpkg", "B":"--buildpkgonly", |
1382 |
+"c":"--clean", "C":"--unmerge", |
1383 |
+"d":"--debug", "D":"--deep", |
1384 |
+"e":"--emptytree", |
1385 |
+"f":"--fetchonly", "F":"--fetch-all-uri", |
1386 |
+"g":"--getbinpkg", "G":"--getbinpkgonly", |
1387 |
+"h":"--help", |
1388 |
+"k":"--usepkg", "K":"--usepkgonly", |
1389 |
+"l":"--changelog", |
1390 |
+"n":"--noreplace", "N":"--newuse", |
1391 |
+"o":"--onlydeps", "O":"--nodeps", |
1392 |
+"p":"--pretend", "P":"--prune", |
1393 |
+"q":"--quiet", |
1394 |
+"s":"--search", "S":"--searchdesc", |
1395 |
+"t":"--tree", |
1396 |
+"u":"--update", |
1397 |
+"v":"--verbose", "V":"--version" |
1398 |
+} |
1399 |
+ |
1400 |
+def chk_updated_info_files(root, infodirs, prev_mtimes, retval): |
1401 |
+ |
1402 |
+ if os.path.exists("/usr/bin/install-info"): |
1403 |
+ out = portage.output.EOutput() |
1404 |
+ regen_infodirs=[] |
1405 |
+ for z in infodirs: |
1406 |
+ if z=='': |
1407 |
+ continue |
1408 |
+ inforoot=normpath(root+z) |
1409 |
+ if os.path.isdir(inforoot): |
1410 |
+ infomtime = long(os.stat(inforoot).st_mtime) |
1411 |
+ if inforoot not in prev_mtimes or \ |
1412 |
+ prev_mtimes[inforoot] != infomtime: |
1413 |
+ regen_infodirs.append(inforoot) |
1414 |
+ |
1415 |
+ if not regen_infodirs: |
1416 |
+ portage.writemsg_stdout("\n") |
1417 |
+ out.einfo("GNU info directory index is up-to-date.") |
1418 |
+ else: |
1419 |
+ portage.writemsg_stdout("\n") |
1420 |
+ out.einfo("Regenerating GNU info directory index...") |
1421 |
+ |
1422 |
+ dir_extensions = ("", ".gz", ".bz2") |
1423 |
+ icount=0 |
1424 |
+ badcount=0 |
1425 |
+ errmsg = "" |
1426 |
+ for inforoot in regen_infodirs: |
1427 |
+ if inforoot=='': |
1428 |
+ continue |
1429 |
+ |
1430 |
+ if not os.path.isdir(inforoot) or \ |
1431 |
+ not os.access(inforoot, os.W_OK): |
1432 |
+ continue |
1433 |
+ |
1434 |
+ file_list = os.listdir(inforoot) |
1435 |
+ file_list.sort() |
1436 |
+ dir_file = os.path.join(inforoot, "dir") |
1437 |
+ moved_old_dir = False |
1438 |
+ processed_count = 0 |
1439 |
+ for x in file_list: |
1440 |
+ if x.startswith(".") or \ |
1441 |
+ os.path.isdir(os.path.join(inforoot, x)): |
1442 |
+ continue |
1443 |
+ if x.startswith("dir"): |
1444 |
+ skip = False |
1445 |
+ for ext in dir_extensions: |
1446 |
+ if x == "dir" + ext or \ |
1447 |
+ x == "dir" + ext + ".old": |
1448 |
+ skip = True |
1449 |
+ break |
1450 |
+ if skip: |
1451 |
+ continue |
1452 |
+ if processed_count == 0: |
1453 |
+ for ext in dir_extensions: |
1454 |
+ try: |
1455 |
+ os.rename(dir_file + ext, dir_file + ext + ".old") |
1456 |
+ moved_old_dir = True |
1457 |
+ except EnvironmentError, e: |
1458 |
+ if e.errno != errno.ENOENT: |
1459 |
+ raise |
1460 |
+ del e |
1461 |
+ processed_count += 1 |
1462 |
+ myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] |
1463 |
+ existsstr="already exists, for file `" |
1464 |
+ if myso!="": |
1465 |
+ if re.search(existsstr,myso): |
1466 |
+ # Already exists... Don't increment the count for this. |
1467 |
+ pass |
1468 |
+ elif myso[:44]=="install-info: warning: no info dir entry in ": |
1469 |
+ # This info file doesn't contain a DIR-header: install-info produces this |
1470 |
+ # (harmless) warning (the --quiet switch doesn't seem to work). |
1471 |
+ # Don't increment the count for this. |
1472 |
+ pass |
1473 |
+ else: |
1474 |
+ badcount=badcount+1 |
1475 |
+ errmsg += myso + "\n" |
1476 |
+ icount=icount+1 |
1477 |
+ |
1478 |
+ if moved_old_dir and not os.path.exists(dir_file): |
1479 |
+ # We didn't generate a new dir file, so put the old file |
1480 |
+ # back where it was originally found. |
1481 |
+ for ext in dir_extensions: |
1482 |
+ try: |
1483 |
+ os.rename(dir_file + ext + ".old", dir_file + ext) |
1484 |
+ except EnvironmentError, e: |
1485 |
+ if e.errno != errno.ENOENT: |
1486 |
+ raise |
1487 |
+ del e |
1488 |
+ |
1489 |
+ # Clean dir.old cruft so that they don't prevent |
1490 |
+ # unmerge of otherwise empty directories. |
1491 |
+ for ext in dir_extensions: |
1492 |
+ try: |
1493 |
+ os.unlink(dir_file + ext + ".old") |
1494 |
+ except EnvironmentError, e: |
1495 |
+ if e.errno != errno.ENOENT: |
1496 |
+ raise |
1497 |
+ del e |
1498 |
+ |
1499 |
+ #update mtime so we can potentially avoid regenerating. |
1500 |
+ prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime) |
1501 |
+ |
1502 |
+ if badcount: |
1503 |
+ out.eerror("Processed %d info files; %d errors." % \ |
1504 |
+ (icount, badcount)) |
1505 |
+ writemsg_level(errmsg, level=logging.ERROR, noiselevel=-1) |
1506 |
+ else: |
1507 |
+ if icount > 0: |
1508 |
+ out.einfo("Processed %d info files." % (icount,)) |
1509 |
+ |
1510 |
+ |
1511 |
+def display_preserved_libs(vardbapi): |
1512 |
+ MAX_DISPLAY = 3 |
1513 |
+ |
1514 |
+ # Ensure the registry is consistent with existing files. |
1515 |
+ vardbapi.plib_registry.pruneNonExisting() |
1516 |
+ |
1517 |
+ if vardbapi.plib_registry.hasEntries(): |
1518 |
+ print |
1519 |
+ print colorize("WARN", "!!!") + " existing preserved libs:" |
1520 |
+ plibdata = vardbapi.plib_registry.getPreservedLibs() |
1521 |
+ linkmap = vardbapi.linkmap |
1522 |
+ consumer_map = {} |
1523 |
+ owners = {} |
1524 |
+ linkmap_broken = False |
1525 |
+ |
1526 |
+ try: |
1527 |
+ linkmap.rebuild() |
1528 |
+ except portage.exception.CommandNotFound, e: |
1529 |
+ writemsg_level("!!! Command Not Found: %s\n" % (e,), |
1530 |
+ level=logging.ERROR, noiselevel=-1) |
1531 |
+ del e |
1532 |
+ linkmap_broken = True |
1533 |
+ else: |
1534 |
+ search_for_owners = set() |
1535 |
+ for cpv in plibdata: |
1536 |
+ internal_plib_keys = set(linkmap._obj_key(f) \ |
1537 |
+ for f in plibdata[cpv]) |
1538 |
+ for f in plibdata[cpv]: |
1539 |
+ if f in consumer_map: |
1540 |
+ continue |
1541 |
+ consumers = [] |
1542 |
+ for c in linkmap.findConsumers(f): |
1543 |
+ # Filter out any consumers that are also preserved libs |
1544 |
+ # belonging to the same package as the provider. |
1545 |
+ if linkmap._obj_key(c) not in internal_plib_keys: |
1546 |
+ consumers.append(c) |
1547 |
+ consumers.sort() |
1548 |
+ consumer_map[f] = consumers |
1549 |
+ search_for_owners.update(consumers[:MAX_DISPLAY+1]) |
1550 |
+ |
1551 |
+ owners = vardbapi._owners.getFileOwnerMap(search_for_owners) |
1552 |
+ |
1553 |
+ for cpv in plibdata: |
1554 |
+ print colorize("WARN", ">>>") + " package: %s" % cpv |
1555 |
+ samefile_map = {} |
1556 |
+ for f in plibdata[cpv]: |
1557 |
+ obj_key = linkmap._obj_key(f) |
1558 |
+ alt_paths = samefile_map.get(obj_key) |
1559 |
+ if alt_paths is None: |
1560 |
+ alt_paths = set() |
1561 |
+ samefile_map[obj_key] = alt_paths |
1562 |
+ alt_paths.add(f) |
1563 |
+ |
1564 |
+ for alt_paths in samefile_map.itervalues(): |
1565 |
+ alt_paths = sorted(alt_paths) |
1566 |
+ for p in alt_paths: |
1567 |
+ print colorize("WARN", " * ") + " - %s" % (p,) |
1568 |
+ f = alt_paths[0] |
1569 |
+ consumers = consumer_map.get(f, []) |
1570 |
+ for c in consumers[:MAX_DISPLAY]: |
1571 |
+ print colorize("WARN", " * ") + " used by %s (%s)" % \ |
1572 |
+ (c, ", ".join(x.mycpv for x in owners.get(c, []))) |
1573 |
+ if len(consumers) == MAX_DISPLAY + 1: |
1574 |
+ print colorize("WARN", " * ") + " used by %s (%s)" % \ |
1575 |
+ (consumers[MAX_DISPLAY], ", ".join(x.mycpv \ |
1576 |
+ for x in owners.get(consumers[MAX_DISPLAY], []))) |
1577 |
+ elif len(consumers) > MAX_DISPLAY: |
1578 |
+ print colorize("WARN", " * ") + " used by %d other files" % (len(consumers) - MAX_DISPLAY) |
1579 |
+ print "Use " + colorize("GOOD", "emerge @preserved-rebuild") + " to rebuild packages using these libraries" |
1580 |
+ |
1581 |
+ |
1582 |
+def post_emerge(root_config, myopts, mtimedb, retval): |
1583 |
+ """ |
1584 |
+ Misc. things to run at the end of a merge session. |
1585 |
+ |
1586 |
+ Update Info Files |
1587 |
+ Update Config Files |
1588 |
+ Update News Items |
1589 |
+ Commit mtimeDB |
1590 |
+ Display preserved libs warnings |
1591 |
+ Exit Emerge |
1592 |
+ |
1593 |
+ @param trees: A dictionary mapping each ROOT to it's package databases |
1594 |
+ @type trees: dict |
1595 |
+ @param mtimedb: The mtimeDB to store data needed across merge invocations |
1596 |
+ @type mtimedb: MtimeDB class instance |
1597 |
+ @param retval: Emerge's return value |
1598 |
+ @type retval: Int |
1599 |
+ @rype: None |
1600 |
+ @returns: |
1601 |
+ 1. Calls sys.exit(retval) |
1602 |
+ """ |
1603 |
+ |
1604 |
+ target_root = root_config.root |
1605 |
+ trees = { target_root : root_config.trees } |
1606 |
+ vardbapi = trees[target_root]["vartree"].dbapi |
1607 |
+ settings = vardbapi.settings |
1608 |
+ info_mtimes = mtimedb["info"] |
1609 |
+ |
1610 |
+ # Load the most current variables from ${ROOT}/etc/profile.env |
1611 |
+ settings.unlock() |
1612 |
+ settings.reload() |
1613 |
+ settings.regenerate() |
1614 |
+ settings.lock() |
1615 |
+ |
1616 |
+ config_protect = settings.get("CONFIG_PROTECT","").split() |
1617 |
+ infodirs = settings.get("INFOPATH","").split(":") + \ |
1618 |
+ settings.get("INFODIR","").split(":") |
1619 |
+ |
1620 |
+ os.chdir("/") |
1621 |
+ |
1622 |
+ if retval == os.EX_OK: |
1623 |
+ exit_msg = " *** exiting successfully." |
1624 |
+ else: |
1625 |
+ exit_msg = " *** exiting unsuccessfully with status '%s'." % retval |
1626 |
+ emergelog("notitles" not in settings.features, exit_msg) |
1627 |
+ |
1628 |
+ _flush_elog_mod_echo() |
1629 |
+ |
1630 |
+ counter_hash = settings.get("PORTAGE_COUNTER_HASH") |
1631 |
+ if "--pretend" in myopts or (counter_hash is not None and \ |
1632 |
+ counter_hash == vardbapi._counter_hash()): |
1633 |
+ display_news_notification(root_config, myopts) |
1634 |
+ # If vdb state has not changed then there's nothing else to do. |
1635 |
+ sys.exit(retval) |
1636 |
+ |
1637 |
+ vdb_path = os.path.join(target_root, portage.VDB_PATH) |
1638 |
+ portage.util.ensure_dirs(vdb_path) |
1639 |
+ vdb_lock = None |
1640 |
+ if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts: |
1641 |
+ vdb_lock = portage.locks.lockdir(vdb_path) |
1642 |
+ |
1643 |
+ if vdb_lock: |
1644 |
+ try: |
1645 |
+ if "noinfo" not in settings.features: |
1646 |
+ chk_updated_info_files(target_root, |
1647 |
+ infodirs, info_mtimes, retval) |
1648 |
+ mtimedb.commit() |
1649 |
+ finally: |
1650 |
+ if vdb_lock: |
1651 |
+ portage.locks.unlockdir(vdb_lock) |
1652 |
+ |
1653 |
+ chk_updated_cfg_files(target_root, config_protect) |
1654 |
+ |
1655 |
+ display_news_notification(root_config, myopts) |
1656 |
+ if retval in (None, os.EX_OK) or (not "--pretend" in myopts): |
1657 |
+ display_preserved_libs(vardbapi) |
1658 |
+ |
1659 |
+ sys.exit(retval) |
1660 |
+ |
1661 |
+ |
1662 |
+def multiple_actions(action1, action2): |
1663 |
+ sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n") |
1664 |
+ sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2)) |
1665 |
+ sys.exit(1) |
1666 |
+ |
1667 |
+def insert_optional_args(args): |
1668 |
+ """ |
1669 |
+ Parse optional arguments and insert a value if one has |
1670 |
+ not been provided. This is done before feeding the args |
1671 |
+ to the optparse parser since that parser does not support |
1672 |
+ this feature natively. |
1673 |
+ """ |
1674 |
+ |
1675 |
+ new_args = [] |
1676 |
+ jobs_opts = ("-j", "--jobs") |
1677 |
+ default_arg_opts = { |
1678 |
+ '--deselect' : ('n',), |
1679 |
+ '--root-deps' : ('rdeps',), |
1680 |
+ } |
1681 |
+ arg_stack = args[:] |
1682 |
+ arg_stack.reverse() |
1683 |
+ while arg_stack: |
1684 |
+ arg = arg_stack.pop() |
1685 |
+ |
1686 |
+ default_arg_choices = default_arg_opts.get(arg) |
1687 |
+ if default_arg_choices is not None: |
1688 |
+ new_args.append(arg) |
1689 |
+ if arg_stack and arg_stack[-1] in default_arg_choices: |
1690 |
+ new_args.append(arg_stack.pop()) |
1691 |
+ else: |
1692 |
+ # insert default argument |
1693 |
+ new_args.append('True') |
1694 |
+ continue |
1695 |
+ |
1696 |
+ short_job_opt = bool("j" in arg and arg[:1] == "-" and arg[:2] != "--") |
1697 |
+ if not (short_job_opt or arg in jobs_opts): |
1698 |
+ new_args.append(arg) |
1699 |
+ continue |
1700 |
+ |
1701 |
+ # Insert an empty placeholder in order to |
1702 |
+ # satisfy the requirements of optparse. |
1703 |
+ |
1704 |
+ new_args.append("--jobs") |
1705 |
+ job_count = None |
1706 |
+ saved_opts = None |
1707 |
+ if short_job_opt and len(arg) > 2: |
1708 |
+ if arg[:2] == "-j": |
1709 |
+ try: |
1710 |
+ job_count = int(arg[2:]) |
1711 |
+ except ValueError: |
1712 |
+ saved_opts = arg[2:] |
1713 |
+ else: |
1714 |
+ job_count = "True" |
1715 |
+ saved_opts = arg[1:].replace("j", "") |
1716 |
+ |
1717 |
+ if job_count is None and arg_stack: |
1718 |
+ try: |
1719 |
+ job_count = int(arg_stack[-1]) |
1720 |
+ except ValueError: |
1721 |
+ pass |
1722 |
+ else: |
1723 |
+ # Discard the job count from the stack |
1724 |
+ # since we're consuming it here. |
1725 |
+ arg_stack.pop() |
1726 |
+ |
1727 |
+ if job_count is None: |
1728 |
+ # unlimited number of jobs |
1729 |
+ new_args.append("True") |
1730 |
+ else: |
1731 |
+ new_args.append(str(job_count)) |
1732 |
+ |
1733 |
+ if saved_opts is not None: |
1734 |
+ new_args.append("-" + saved_opts) |
1735 |
+ |
1736 |
+ return new_args |
1737 |
+ |
1738 |
+def parse_opts(tmpcmdline, silent=False): |
1739 |
+ myaction=None |
1740 |
+ myopts = {} |
1741 |
+ myfiles=[] |
1742 |
+ |
1743 |
+ global options, shortmapping |
1744 |
+ |
1745 |
+ actions = frozenset([ |
1746 |
+ "clean", "config", "depclean", |
1747 |
+ "info", "list-sets", "metadata", |
1748 |
+ "prune", "regen", "search", |
1749 |
+ "sync", "unmerge", "version", |
1750 |
+ ]) |
1751 |
+ |
1752 |
+ longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} |
1753 |
+ argument_options = { |
1754 |
+ "--config-root": { |
1755 |
+ "help":"specify the location for portage configuration files", |
1756 |
+ "action":"store" |
1757 |
+ }, |
1758 |
+ "--color": { |
1759 |
+ "help":"enable or disable color output", |
1760 |
+ "type":"choice", |
1761 |
+ "choices":("y", "n") |
1762 |
+ }, |
1763 |
+ |
1764 |
+ "--deselect": { |
1765 |
+ "help" : "remove atoms from the world file", |
1766 |
+ "type" : "choice", |
1767 |
+ "choices" : ("True", "n") |
1768 |
+ }, |
1769 |
+ |
1770 |
+ "--jobs": { |
1771 |
+ |
1772 |
+ "help" : "Specifies the number of packages to build " + \ |
1773 |
+ "simultaneously.", |
1774 |
+ |
1775 |
+ "action" : "store" |
1776 |
+ }, |
1777 |
+ |
1778 |
+ "--load-average": { |
1779 |
+ |
1780 |
+ "help" :"Specifies that no new builds should be started " + \ |
1781 |
+ "if there are other builds running and the load average " + \ |
1782 |
+ "is at least LOAD (a floating-point number).", |
1783 |
+ |
1784 |
+ "action" : "store" |
1785 |
+ }, |
1786 |
+ |
1787 |
+ "--with-bdeps": { |
1788 |
+ "help":"include unnecessary build time dependencies", |
1789 |
+ "type":"choice", |
1790 |
+ "choices":("y", "n") |
1791 |
+ }, |
1792 |
+ "--reinstall": { |
1793 |
+ "help":"specify conditions to trigger package reinstallation", |
1794 |
+ "type":"choice", |
1795 |
+ "choices":["changed-use"] |
1796 |
+ }, |
1797 |
+ "--root": { |
1798 |
+ "help" : "specify the target root filesystem for merging packages", |
1799 |
+ "action" : "store" |
1800 |
+ }, |
1801 |
+ |
1802 |
+ "--root-deps": { |
1803 |
+ "help" : "modify interpretation of depedencies", |
1804 |
+ "type" : "choice", |
1805 |
+ "choices" :("True", "rdeps") |
1806 |
+ }, |
1807 |
+ } |
1808 |
+ |
1809 |
+ from optparse import OptionParser |
1810 |
+ parser = OptionParser() |
1811 |
+ if parser.has_option("--help"): |
1812 |
+ parser.remove_option("--help") |
1813 |
+ |
1814 |
+ for action_opt in actions: |
1815 |
+ parser.add_option("--" + action_opt, action="store_true", |
1816 |
+ dest=action_opt.replace("-", "_"), default=False) |
1817 |
+ for myopt in options: |
1818 |
+ parser.add_option(myopt, action="store_true", |
1819 |
+ dest=myopt.lstrip("--").replace("-", "_"), default=False) |
1820 |
+ for shortopt, longopt in shortmapping.iteritems(): |
1821 |
+ parser.add_option("-" + shortopt, action="store_true", |
1822 |
+ dest=longopt.lstrip("--").replace("-", "_"), default=False) |
1823 |
+ for myalias, myopt in longopt_aliases.iteritems(): |
1824 |
+ parser.add_option(myalias, action="store_true", |
1825 |
+ dest=myopt.lstrip("--").replace("-", "_"), default=False) |
1826 |
+ |
1827 |
+ for myopt, kwargs in argument_options.iteritems(): |
1828 |
+ parser.add_option(myopt, |
1829 |
+ dest=myopt.lstrip("--").replace("-", "_"), **kwargs) |
1830 |
+ |
1831 |
+ tmpcmdline = insert_optional_args(tmpcmdline) |
1832 |
+ |
1833 |
+ myoptions, myargs = parser.parse_args(args=tmpcmdline) |
1834 |
+ |
1835 |
+ if myoptions.deselect == "True": |
1836 |
+ myoptions.deselect = True |
1837 |
+ |
1838 |
+ if myoptions.root_deps == "True": |
1839 |
+ myoptions.root_deps = True |
1840 |
+ |
1841 |
+ if myoptions.jobs: |
1842 |
+ jobs = None |
1843 |
+ if myoptions.jobs == "True": |
1844 |
+ jobs = True |
1845 |
+ else: |
1846 |
+ try: |
1847 |
+ jobs = int(myoptions.jobs) |
1848 |
+ except ValueError: |
1849 |
+ jobs = -1 |
1850 |
+ |
1851 |
+ if jobs is not True and \ |
1852 |
+ jobs < 1: |
1853 |
+ jobs = None |
1854 |
+ if not silent: |
1855 |
+ writemsg("!!! Invalid --jobs parameter: '%s'\n" % \ |
1856 |
+ (myoptions.jobs,), noiselevel=-1) |
1857 |
+ |
1858 |
+ myoptions.jobs = jobs |
1859 |
+ |
1860 |
+ if myoptions.load_average: |
1861 |
+ try: |
1862 |
+ load_average = float(myoptions.load_average) |
1863 |
+ except ValueError: |
1864 |
+ load_average = 0.0 |
1865 |
+ |
1866 |
+ if load_average <= 0.0: |
1867 |
+ load_average = None |
1868 |
+ if not silent: |
1869 |
+ writemsg("!!! Invalid --load-average parameter: '%s'\n" % \ |
1870 |
+ (myoptions.load_average,), noiselevel=-1) |
1871 |
+ |
1872 |
+ myoptions.load_average = load_average |
1873 |
+ |
1874 |
+ for myopt in options: |
1875 |
+ v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) |
1876 |
+ if v: |
1877 |
+ myopts[myopt] = True |
1878 |
+ |
1879 |
+ for myopt in argument_options: |
1880 |
+ v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) |
1881 |
+ if v is not None: |
1882 |
+ myopts[myopt] = v |
1883 |
+ |
1884 |
+ if myoptions.searchdesc: |
1885 |
+ myoptions.search = True |
1886 |
+ |
1887 |
+ for action_opt in actions: |
1888 |
+ v = getattr(myoptions, action_opt.replace("-", "_")) |
1889 |
+ if v: |
1890 |
+ if myaction: |
1891 |
+ multiple_actions(myaction, action_opt) |
1892 |
+ sys.exit(1) |
1893 |
+ myaction = action_opt |
1894 |
+ |
1895 |
+ if myaction is None and myoptions.deselect is True: |
1896 |
+ myaction = 'deselect' |
1897 |
+ |
1898 |
+ myfiles += myargs |
1899 |
+ |
1900 |
+ return myaction, myopts, myfiles |
1901 |
+ |
1902 |
+def validate_ebuild_environment(trees): |
1903 |
+ for myroot in trees: |
1904 |
+ settings = trees[myroot]["vartree"].settings |
1905 |
+ settings.validate() |
1906 |
+ |
1907 |
+def apply_priorities(settings): |
1908 |
+ ionice(settings) |
1909 |
+ nice(settings) |
1910 |
+ |
1911 |
+def nice(settings): |
1912 |
+ try: |
1913 |
+ os.nice(int(settings.get("PORTAGE_NICENESS", "0"))) |
1914 |
+ except (OSError, ValueError), e: |
1915 |
+ out = portage.output.EOutput() |
1916 |
+ out.eerror("Failed to change nice value to '%s'" % \ |
1917 |
+ settings["PORTAGE_NICENESS"]) |
1918 |
+ out.eerror("%s\n" % str(e)) |
1919 |
+ |
1920 |
+def ionice(settings): |
1921 |
+ |
1922 |
+ ionice_cmd = settings.get("PORTAGE_IONICE_COMMAND") |
1923 |
+ if ionice_cmd: |
1924 |
+ ionice_cmd = shlex.split(ionice_cmd) |
1925 |
+ if not ionice_cmd: |
1926 |
+ return |
1927 |
+ |
1928 |
+ from portage.util import varexpand |
1929 |
+ variables = {"PID" : str(os.getpid())} |
1930 |
+ cmd = [varexpand(x, mydict=variables) for x in ionice_cmd] |
1931 |
+ |
1932 |
+ try: |
1933 |
+ rval = portage.process.spawn(cmd, env=os.environ) |
1934 |
+ except portage.exception.CommandNotFound: |
1935 |
+ # The OS kernel probably doesn't support ionice, |
1936 |
+ # so return silently. |
1937 |
+ return |
1938 |
+ |
1939 |
+ if rval != os.EX_OK: |
1940 |
+ out = portage.output.EOutput() |
1941 |
+ out.eerror("PORTAGE_IONICE_COMMAND returned %d" % (rval,)) |
1942 |
+ out.eerror("See the make.conf(5) man page for PORTAGE_IONICE_COMMAND usage instructions.") |
1943 |
+ |
1944 |
+def expand_set_arguments(myfiles, myaction, root_config): |
1945 |
+ retval = os.EX_OK |
1946 |
+ setconfig = root_config.setconfig |
1947 |
+ |
1948 |
+ sets = setconfig.getSets() |
1949 |
+ |
1950 |
+ # In order to know exactly which atoms/sets should be added to the |
1951 |
+ # world file, the depgraph performs set expansion later. It will get |
1952 |
+ # confused about where the atoms came from if it's not allowed to |
1953 |
+ # expand them itself. |
1954 |
+ do_not_expand = (None, ) |
1955 |
+ newargs = [] |
1956 |
+ for a in myfiles: |
1957 |
+ if a in ("system", "world"): |
1958 |
+ newargs.append(SETPREFIX+a) |
1959 |
+ else: |
1960 |
+ newargs.append(a) |
1961 |
+ myfiles = newargs |
1962 |
+ del newargs |
1963 |
+ newargs = [] |
1964 |
+ |
1965 |
+ # separators for set arguments |
1966 |
+ ARG_START = "{" |
1967 |
+ ARG_END = "}" |
1968 |
+ |
1969 |
+ # WARNING: all operators must be of equal length |
1970 |
+ IS_OPERATOR = "/@" |
1971 |
+ DIFF_OPERATOR = "-@" |
1972 |
+ UNION_OPERATOR = "+@" |
1973 |
+ |
1974 |
+ for i in range(0, len(myfiles)): |
1975 |
+ if myfiles[i].startswith(SETPREFIX): |
1976 |
+ start = 0 |
1977 |
+ end = 0 |
1978 |
+ x = myfiles[i][len(SETPREFIX):] |
1979 |
+ newset = "" |
1980 |
+ while x: |
1981 |
+ start = x.find(ARG_START) |
1982 |
+ end = x.find(ARG_END) |
1983 |
+ if start > 0 and start < end: |
1984 |
+ namepart = x[:start] |
1985 |
+ argpart = x[start+1:end] |
1986 |
+ |
1987 |
+ # TODO: implement proper quoting |
1988 |
+ args = argpart.split(",") |
1989 |
+ options = {} |
1990 |
+ for a in args: |
1991 |
+ if "=" in a: |
1992 |
+ k, v = a.split("=", 1) |
1993 |
+ options[k] = v |
1994 |
+ else: |
1995 |
+ options[a] = "True" |
1996 |
+ setconfig.update(namepart, options) |
1997 |
+ newset += (x[:start-len(namepart)]+namepart) |
1998 |
+ x = x[end+len(ARG_END):] |
1999 |
+ else: |
2000 |
+ newset += x |
2001 |
+ x = "" |
2002 |
+ myfiles[i] = SETPREFIX+newset |
2003 |
+ |
2004 |
+ sets = setconfig.getSets() |
2005 |
+ |
2006 |
+ # display errors that occured while loading the SetConfig instance |
2007 |
+ for e in setconfig.errors: |
2008 |
+ print colorize("BAD", "Error during set creation: %s" % e) |
2009 |
+ |
2010 |
+ # emerge relies on the existance of sets with names "world" and "system" |
2011 |
+ required_sets = ("world", "system") |
2012 |
+ missing_sets = [] |
2013 |
+ |
2014 |
+ for s in required_sets: |
2015 |
+ if s not in sets: |
2016 |
+ missing_sets.append(s) |
2017 |
+ if missing_sets: |
2018 |
+ if len(missing_sets) > 2: |
2019 |
+ missing_sets_str = ", ".join('"%s"' % s for s in missing_sets[:-1]) |
2020 |
+ missing_sets_str += ', and "%s"' % missing_sets[-1] |
2021 |
+ elif len(missing_sets) == 2: |
2022 |
+ missing_sets_str = '"%s" and "%s"' % tuple(missing_sets) |
2023 |
+ else: |
2024 |
+ missing_sets_str = '"%s"' % missing_sets[-1] |
2025 |
+ msg = ["emerge: incomplete set configuration, " + \ |
2026 |
+ "missing set(s): %s" % missing_sets_str] |
2027 |
+ if sets: |
2028 |
+ msg.append(" sets defined: %s" % ", ".join(sets)) |
2029 |
+ msg.append(" This usually means that '%s'" % \ |
2030 |
+ (os.path.join(portage.const.GLOBAL_CONFIG_PATH, "sets.conf"),)) |
2031 |
+ msg.append(" is missing or corrupt.") |
2032 |
+ for line in msg: |
2033 |
+ writemsg_level(line + "\n", level=logging.ERROR, noiselevel=-1) |
2034 |
+ return (None, 1) |
2035 |
+ unmerge_actions = ("unmerge", "prune", "clean", "depclean") |
2036 |
+ |
2037 |
+ for a in myfiles: |
2038 |
+ if a.startswith(SETPREFIX): |
2039 |
+ # support simple set operations (intersection, difference and union) |
2040 |
+ # on the commandline. Expressions are evaluated strictly left-to-right |
2041 |
+ if IS_OPERATOR in a or DIFF_OPERATOR in a or UNION_OPERATOR in a: |
2042 |
+ expression = a[len(SETPREFIX):] |
2043 |
+ expr_sets = [] |
2044 |
+ expr_ops = [] |
2045 |
+ while IS_OPERATOR in expression or DIFF_OPERATOR in expression or UNION_OPERATOR in expression: |
2046 |
+ is_pos = expression.rfind(IS_OPERATOR) |
2047 |
+ diff_pos = expression.rfind(DIFF_OPERATOR) |
2048 |
+ union_pos = expression.rfind(UNION_OPERATOR) |
2049 |
+ op_pos = max(is_pos, diff_pos, union_pos) |
2050 |
+ s1 = expression[:op_pos] |
2051 |
+ s2 = expression[op_pos+len(IS_OPERATOR):] |
2052 |
+ op = expression[op_pos:op_pos+len(IS_OPERATOR)] |
2053 |
+ if not s2 in sets: |
2054 |
+ display_missing_pkg_set(root_config, s2) |
2055 |
+ return (None, 1) |
2056 |
+ expr_sets.insert(0, s2) |
2057 |
+ expr_ops.insert(0, op) |
2058 |
+ expression = s1 |
2059 |
+ if not expression in sets: |
2060 |
+ display_missing_pkg_set(root_config, expression) |
2061 |
+ return (None, 1) |
2062 |
+ expr_sets.insert(0, expression) |
2063 |
+ result = set(setconfig.getSetAtoms(expression)) |
2064 |
+ for i in range(0, len(expr_ops)): |
2065 |
+ s2 = setconfig.getSetAtoms(expr_sets[i+1]) |
2066 |
+ if expr_ops[i] == IS_OPERATOR: |
2067 |
+ result.intersection_update(s2) |
2068 |
+ elif expr_ops[i] == DIFF_OPERATOR: |
2069 |
+ result.difference_update(s2) |
2070 |
+ elif expr_ops[i] == UNION_OPERATOR: |
2071 |
+ result.update(s2) |
2072 |
+ else: |
2073 |
+ raise NotImplementedError("unknown set operator %s" % expr_ops[i]) |
2074 |
+ newargs.extend(result) |
2075 |
+ else: |
2076 |
+ s = a[len(SETPREFIX):] |
2077 |
+ if s not in sets: |
2078 |
+ display_missing_pkg_set(root_config, s) |
2079 |
+ return (None, 1) |
2080 |
+ setconfig.active.append(s) |
2081 |
+ try: |
2082 |
+ set_atoms = setconfig.getSetAtoms(s) |
2083 |
+ except portage.exception.PackageSetNotFound, e: |
2084 |
+ writemsg_level(("emerge: the given set '%s' " + \ |
2085 |
+ "contains a non-existent set named '%s'.\n") % \ |
2086 |
+ (s, e), level=logging.ERROR, noiselevel=-1) |
2087 |
+ return (None, 1) |
2088 |
+ if myaction in unmerge_actions and \ |
2089 |
+ not sets[s].supportsOperation("unmerge"): |
2090 |
+ sys.stderr.write("emerge: the given set '%s' does " % s + \ |
2091 |
+ "not support unmerge operations\n") |
2092 |
+ retval = 1 |
2093 |
+ elif not set_atoms: |
2094 |
+ print "emerge: '%s' is an empty set" % s |
2095 |
+ elif myaction not in do_not_expand: |
2096 |
+ newargs.extend(set_atoms) |
2097 |
+ else: |
2098 |
+ newargs.append(SETPREFIX+s) |
2099 |
+ for e in sets[s].errors: |
2100 |
+ print e |
2101 |
+ else: |
2102 |
+ newargs.append(a) |
2103 |
+ return (newargs, retval) |
2104 |
+ |
2105 |
+def repo_name_check(trees): |
2106 |
+ missing_repo_names = set() |
2107 |
+ for root, root_trees in trees.iteritems(): |
2108 |
+ if "porttree" in root_trees: |
2109 |
+ portdb = root_trees["porttree"].dbapi |
2110 |
+ missing_repo_names.update(portdb.porttrees) |
2111 |
+ repos = portdb.getRepositories() |
2112 |
+ for r in repos: |
2113 |
+ missing_repo_names.discard(portdb.getRepositoryPath(r)) |
2114 |
+ if portdb.porttree_root in missing_repo_names and \ |
2115 |
+ not os.path.exists(os.path.join( |
2116 |
+ portdb.porttree_root, "profiles")): |
2117 |
+ # This is normal if $PORTDIR happens to be empty, |
2118 |
+ # so don't warn about it. |
2119 |
+ missing_repo_names.remove(portdb.porttree_root) |
2120 |
+ |
2121 |
+ if missing_repo_names: |
2122 |
+ msg = [] |
2123 |
+ msg.append("WARNING: One or more repositories " + \ |
2124 |
+ "have missing repo_name entries:") |
2125 |
+ msg.append("") |
2126 |
+ for p in missing_repo_names: |
2127 |
+ msg.append("\t%s/profiles/repo_name" % (p,)) |
2128 |
+ msg.append("") |
2129 |
+ msg.extend(textwrap.wrap("NOTE: Each repo_name entry " + \ |
2130 |
+ "should be a plain text file containing a unique " + \ |
2131 |
+ "name for the repository on the first line.", 70)) |
2132 |
+ writemsg_level("".join("%s\n" % l for l in msg), |
2133 |
+ level=logging.WARNING, noiselevel=-1) |
2134 |
+ |
2135 |
+ return bool(missing_repo_names) |
2136 |
+ |
2137 |
+def repo_name_duplicate_check(trees): |
2138 |
+ ignored_repos = {} |
2139 |
+ for root, root_trees in trees.iteritems(): |
2140 |
+ if 'porttree' in root_trees: |
2141 |
+ portdb = root_trees['porttree'].dbapi |
2142 |
+ if portdb.mysettings.get('PORTAGE_REPO_DUPLICATE_WARN') != '0': |
2143 |
+ for repo_name, paths in portdb._ignored_repos: |
2144 |
+ k = (root, repo_name, portdb.getRepositoryPath(repo_name)) |
2145 |
+ ignored_repos.setdefault(k, []).extend(paths) |
2146 |
+ |
2147 |
+ if ignored_repos: |
2148 |
+ msg = [] |
2149 |
+ msg.append('WARNING: One or more repositories ' + \ |
2150 |
+ 'have been ignored due to duplicate') |
2151 |
+ msg.append(' profiles/repo_name entries:') |
2152 |
+ msg.append('') |
2153 |
+ for k in sorted(ignored_repos): |
2154 |
+ msg.append(' %s overrides' % (k,)) |
2155 |
+ for path in ignored_repos[k]: |
2156 |
+ msg.append(' %s' % (path,)) |
2157 |
+ msg.append('') |
2158 |
+ msg.extend(' ' + x for x in textwrap.wrap( |
2159 |
+ "All profiles/repo_name entries must be unique in order " + \ |
2160 |
+ "to avoid having duplicates ignored. " + \ |
2161 |
+ "Set PORTAGE_REPO_DUPLICATE_WARN=\"0\" in " + \ |
2162 |
+ "/etc/make.conf if you would like to disable this warning.")) |
2163 |
+ writemsg_level(''.join('%s\n' % l for l in msg), |
2164 |
+ level=logging.WARNING, noiselevel=-1) |
2165 |
+ |
2166 |
+ return bool(ignored_repos) |
2167 |
+ |
2168 |
+def config_protect_check(trees): |
2169 |
+ for root, root_trees in trees.iteritems(): |
2170 |
+ if not root_trees["root_config"].settings.get("CONFIG_PROTECT"): |
2171 |
+ msg = "!!! CONFIG_PROTECT is empty" |
2172 |
+ if root != "/": |
2173 |
+ msg += " for '%s'" % root |
2174 |
+ writemsg_level(msg, level=logging.WARN, noiselevel=-1) |
2175 |
+ |
2176 |
+def profile_check(trees, myaction, myopts): |
2177 |
+ if myaction in ("info", "sync"): |
2178 |
+ return os.EX_OK |
2179 |
+ elif "--version" in myopts or "--help" in myopts: |
2180 |
+ return os.EX_OK |
2181 |
+ for root, root_trees in trees.iteritems(): |
2182 |
+ if root_trees["root_config"].settings.profiles: |
2183 |
+ continue |
2184 |
+ # generate some profile related warning messages |
2185 |
+ validate_ebuild_environment(trees) |
2186 |
+ msg = "If you have just changed your profile configuration, you " + \ |
2187 |
+ "should revert back to the previous configuration. Due to " + \ |
2188 |
+ "your current profile being invalid, allowed actions are " + \ |
2189 |
+ "limited to --help, --info, --sync, and --version." |
2190 |
+ writemsg_level("".join("!!! %s\n" % l for l in textwrap.wrap(msg, 70)), |
2191 |
+ level=logging.ERROR, noiselevel=-1) |
2192 |
+ return 1 |
2193 |
+ return os.EX_OK |
2194 |
+ |
2195 |
+def emerge_main(): |
2196 |
+ global portage # NFC why this is necessary now - genone |
2197 |
+ portage._disable_legacy_globals() |
2198 |
+ # Disable color until we're sure that it should be enabled (after |
2199 |
+ # EMERGE_DEFAULT_OPTS has been parsed). |
2200 |
+ portage.output.havecolor = 0 |
2201 |
+ # This first pass is just for options that need to be known as early as |
2202 |
+ # possible, such as --config-root. They will be parsed again later, |
2203 |
+ # together with EMERGE_DEFAULT_OPTS (which may vary depending on the |
2204 |
+ # the value of --config-root). |
2205 |
+ myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True) |
2206 |
+ if "--debug" in myopts: |
2207 |
+ os.environ["PORTAGE_DEBUG"] = "1" |
2208 |
+ if "--config-root" in myopts: |
2209 |
+ os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] |
2210 |
+ if "--root" in myopts: |
2211 |
+ os.environ["ROOT"] = myopts["--root"] |
2212 |
+ |
2213 |
+ # Portage needs to ensure a sane umask for the files it creates. |
2214 |
+ os.umask(022) |
2215 |
+ settings, trees, mtimedb = load_emerge_config() |
2216 |
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi |
2217 |
+ rval = profile_check(trees, myaction, myopts) |
2218 |
+ if rval != os.EX_OK: |
2219 |
+ return rval |
2220 |
+ |
2221 |
+ if portage._global_updates(trees, mtimedb["updates"]): |
2222 |
+ mtimedb.commit() |
2223 |
+ # Reload the whole config from scratch. |
2224 |
+ settings, trees, mtimedb = load_emerge_config(trees=trees) |
2225 |
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi |
2226 |
+ |
2227 |
+ xterm_titles = "notitles" not in settings.features |
2228 |
+ |
2229 |
+ tmpcmdline = [] |
2230 |
+ if "--ignore-default-opts" not in myopts: |
2231 |
+ tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) |
2232 |
+ tmpcmdline.extend(sys.argv[1:]) |
2233 |
+ myaction, myopts, myfiles = parse_opts(tmpcmdline) |
2234 |
+ |
2235 |
+ if "--digest" in myopts: |
2236 |
+ os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" |
2237 |
+ # Reload the whole config from scratch so that the portdbapi internal |
2238 |
+ # config is updated with new FEATURES. |
2239 |
+ settings, trees, mtimedb = load_emerge_config(trees=trees) |
2240 |
+ portdb = trees[settings["ROOT"]]["porttree"].dbapi |
2241 |
+ |
2242 |
+ for myroot in trees: |
2243 |
+ mysettings = trees[myroot]["vartree"].settings |
2244 |
+ mysettings.unlock() |
2245 |
+ adjust_config(myopts, mysettings) |
2246 |
+ if '--pretend' not in myopts and myaction in \ |
2247 |
+ (None, 'clean', 'depclean', 'prune', 'unmerge'): |
2248 |
+ mysettings["PORTAGE_COUNTER_HASH"] = \ |
2249 |
+ trees[myroot]["vartree"].dbapi._counter_hash() |
2250 |
+ mysettings.backup_changes("PORTAGE_COUNTER_HASH") |
2251 |
+ mysettings.lock() |
2252 |
+ del myroot, mysettings |
2253 |
+ |
2254 |
+ apply_priorities(settings) |
2255 |
+ |
2256 |
+ spinner = stdout_spinner() |
2257 |
+ if "candy" in settings.features: |
2258 |
+ spinner.update = spinner.update_scroll |
2259 |
+ |
2260 |
+ if "--quiet" not in myopts: |
2261 |
+ portage.deprecated_profile_check(settings=settings) |
2262 |
+ repo_name_check(trees) |
2263 |
+ repo_name_duplicate_check(trees) |
2264 |
+ config_protect_check(trees) |
2265 |
+ |
2266 |
+ for mytrees in trees.itervalues(): |
2267 |
+ mydb = mytrees["porttree"].dbapi |
2268 |
+ # Freeze the portdbapi for performance (memoize all xmatch results). |
2269 |
+ mydb.freeze() |
2270 |
+ del mytrees, mydb |
2271 |
+ |
2272 |
+ if "moo" in myfiles: |
2273 |
+ print """ |
2274 |
+ |
2275 |
+ Larry loves Gentoo (""" + platform.system() + """) |
2276 |
+ |
2277 |
+ _______________________ |
2278 |
+< Have you mooed today? > |
2279 |
+ ----------------------- |
2280 |
+ \ ^__^ |
2281 |
+ \ (oo)\_______ |
2282 |
+ (__)\ )\/\ |
2283 |
+ ||----w | |
2284 |
+ || || |
2285 |
+ |
2286 |
+""" |
2287 |
+ |
2288 |
+ for x in myfiles: |
2289 |
+ ext = os.path.splitext(x)[1] |
2290 |
+ if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): |
2291 |
+ print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n") |
2292 |
+ break |
2293 |
+ |
2294 |
+ root_config = trees[settings["ROOT"]]["root_config"] |
2295 |
+ if myaction == "list-sets": |
2296 |
+ sys.stdout.write("".join("%s\n" % s for s in sorted(root_config.sets))) |
2297 |
+ sys.stdout.flush() |
2298 |
+ return os.EX_OK |
2299 |
+ |
2300 |
+ # only expand sets for actions taking package arguments |
2301 |
+ oldargs = myfiles[:] |
2302 |
+ if myaction in ("clean", "config", "depclean", "info", "prune", "unmerge", None): |
2303 |
+ myfiles, retval = expand_set_arguments(myfiles, myaction, root_config) |
2304 |
+ if retval != os.EX_OK: |
2305 |
+ return retval |
2306 |
+ |
2307 |
+ # Need to handle empty sets specially, otherwise emerge will react |
2308 |
+ # with the help message for empty argument lists |
2309 |
+ if oldargs and not myfiles: |
2310 |
+ print "emerge: no targets left after set expansion" |
2311 |
+ return 0 |
2312 |
+ |
2313 |
+ if ("--tree" in myopts) and ("--columns" in myopts): |
2314 |
+ print "emerge: can't specify both of \"--tree\" and \"--columns\"." |
2315 |
+ return 1 |
2316 |
+ |
2317 |
+ if ("--quiet" in myopts): |
2318 |
+ spinner.update = spinner.update_quiet |
2319 |
+ portage.util.noiselimit = -1 |
2320 |
+ |
2321 |
+ # Always create packages if FEATURES=buildpkg |
2322 |
+ # Imply --buildpkg if --buildpkgonly |
2323 |
+ if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts): |
2324 |
+ if "--buildpkg" not in myopts: |
2325 |
+ myopts["--buildpkg"] = True |
2326 |
+ |
2327 |
+ # Always try and fetch binary packages if FEATURES=getbinpkg |
2328 |
+ if ("getbinpkg" in settings.features): |
2329 |
+ myopts["--getbinpkg"] = True |
2330 |
+ |
2331 |
+ if "--buildpkgonly" in myopts: |
2332 |
+ # --buildpkgonly will not merge anything, so |
2333 |
+ # it cancels all binary package options. |
2334 |
+ for opt in ("--getbinpkg", "--getbinpkgonly", |
2335 |
+ "--usepkg", "--usepkgonly"): |
2336 |
+ myopts.pop(opt, None) |
2337 |
+ |
2338 |
+ if "--fetch-all-uri" in myopts: |
2339 |
+ myopts["--fetchonly"] = True |
2340 |
+ |
2341 |
+ if "--skipfirst" in myopts and "--resume" not in myopts: |
2342 |
+ myopts["--resume"] = True |
2343 |
+ |
2344 |
+ if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): |
2345 |
+ myopts["--usepkgonly"] = True |
2346 |
+ |
2347 |
+ if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): |
2348 |
+ myopts["--getbinpkg"] = True |
2349 |
+ |
2350 |
+ if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): |
2351 |
+ myopts["--usepkg"] = True |
2352 |
+ |
2353 |
+ # Also allow -K to apply --usepkg/-k |
2354 |
+ if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): |
2355 |
+ myopts["--usepkg"] = True |
2356 |
+ |
2357 |
+ # Allow -p to remove --ask |
2358 |
+ if "--pretend" in myopts: |
2359 |
+ myopts.pop("--ask", None) |
2360 |
+ |
2361 |
+ # forbid --ask when not in a terminal |
2362 |
+ # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. |
2363 |
+ if ("--ask" in myopts) and (not sys.stdin.isatty()): |
2364 |
+ portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", |
2365 |
+ noiselevel=-1) |
2366 |
+ return 1 |
2367 |
+ |
2368 |
+ if settings.get("PORTAGE_DEBUG", "") == "1": |
2369 |
+ spinner.update = spinner.update_quiet |
2370 |
+ portage.debug=1 |
2371 |
+ if "python-trace" in settings.features: |
2372 |
+ import portage.debug |
2373 |
+ portage.debug.set_trace(True) |
2374 |
+ |
2375 |
+ if not ("--quiet" in myopts): |
2376 |
+ if not sys.stdout.isatty() or ("--nospinner" in myopts): |
2377 |
+ spinner.update = spinner.update_basic |
2378 |
+ |
2379 |
+ if myaction == 'version': |
2380 |
+ print getportageversion(settings["PORTDIR"], settings["ROOT"], |
2381 |
+ settings.profile_path, settings["CHOST"], |
2382 |
+ trees[settings["ROOT"]]["vartree"].dbapi) |
2383 |
+ return 0 |
2384 |
+ elif "--help" in myopts: |
2385 |
+ _emerge.help.help(myaction, myopts, portage.output.havecolor) |
2386 |
+ return 0 |
2387 |
+ |
2388 |
+ if "--debug" in myopts: |
2389 |
+ print "myaction", myaction |
2390 |
+ print "myopts", myopts |
2391 |
+ |
2392 |
+ if not myaction and not myfiles and "--resume" not in myopts: |
2393 |
+ _emerge.help.help(myaction, myopts, portage.output.havecolor) |
2394 |
+ return 1 |
2395 |
+ |
2396 |
+ pretend = "--pretend" in myopts |
2397 |
+ fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts |
2398 |
+ buildpkgonly = "--buildpkgonly" in myopts |
2399 |
+ |
2400 |
+ # check if root user is the current user for the actions where emerge needs this |
2401 |
+ if portage.secpass < 2: |
2402 |
+ # We've already allowed "--version" and "--help" above. |
2403 |
+ if "--pretend" not in myopts and myaction not in ("search","info"): |
2404 |
+ need_superuser = myaction in ('clean', 'depclean', 'deselect', |
2405 |
+ 'prune', 'unmerge') or not \ |
2406 |
+ (fetchonly or \ |
2407 |
+ (buildpkgonly and secpass >= 1) or \ |
2408 |
+ myaction in ("metadata", "regen") or \ |
2409 |
+ (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK))) |
2410 |
+ if portage.secpass < 1 or \ |
2411 |
+ need_superuser: |
2412 |
+ if need_superuser: |
2413 |
+ access_desc = "superuser" |
2414 |
+ else: |
2415 |
+ access_desc = "portage group" |
2416 |
+ # Always show portage_group_warning() when only portage group |
2417 |
+ # access is required but the user is not in the portage group. |
2418 |
+ from portage.data import portage_group_warning |
2419 |
+ if "--ask" in myopts: |
2420 |
+ myopts["--pretend"] = True |
2421 |
+ del myopts["--ask"] |
2422 |
+ print ("%s access is required... " + \ |
2423 |
+ "adding --pretend to options\n") % access_desc |
2424 |
+ if portage.secpass < 1 and not need_superuser: |
2425 |
+ portage_group_warning() |
2426 |
+ else: |
2427 |
+ sys.stderr.write(("emerge: %s access is required\n") \ |
2428 |
+ % access_desc) |
2429 |
+ if portage.secpass < 1 and not need_superuser: |
2430 |
+ portage_group_warning() |
2431 |
+ return 1 |
2432 |
+ |
2433 |
+ disable_emergelog = False |
2434 |
+ for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): |
2435 |
+ if x in myopts: |
2436 |
+ disable_emergelog = True |
2437 |
+ break |
2438 |
+ if myaction in ("search", "info"): |
2439 |
+ disable_emergelog = True |
2440 |
+ if disable_emergelog: |
2441 |
+ """ Disable emergelog for everything except build or unmerge |
2442 |
+ operations. This helps minimize parallel emerge.log entries that can |
2443 |
+ confuse log parsers. We especially want it disabled during |
2444 |
+ parallel-fetch, which uses --resume --fetchonly.""" |
2445 |
+ global emergelog |
2446 |
+ def emergelog(*pargs, **kargs): |
2447 |
+ pass |
2448 |
+ |
2449 |
+ else: |
2450 |
+ if 'EMERGE_LOG_DIR' in settings: |
2451 |
+ try: |
2452 |
+ # At least the parent needs to exist for the lock file. |
2453 |
+ portage.util.ensure_dirs(settings['EMERGE_LOG_DIR']) |
2454 |
+ except portage.exception.PortageException, e: |
2455 |
+ writemsg_level("!!! Error creating directory for " + \ |
2456 |
+ "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \ |
2457 |
+ (settings['EMERGE_LOG_DIR'], e), |
2458 |
+ noiselevel=-1, level=logging.ERROR) |
2459 |
+ else: |
2460 |
+ global _emerge_log_dir |
2461 |
+ _emerge_log_dir = settings['EMERGE_LOG_DIR'] |
2462 |
+ |
2463 |
+ if not "--pretend" in myopts: |
2464 |
+ emergelog(xterm_titles, "Started emerge on: "+\ |
2465 |
+ time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) |
2466 |
+ myelogstr="" |
2467 |
+ if myopts: |
2468 |
+ myelogstr=" ".join(myopts) |
2469 |
+ if myaction: |
2470 |
+ myelogstr+=" "+myaction |
2471 |
+ if myfiles: |
2472 |
+ myelogstr += " " + " ".join(oldargs) |
2473 |
+ emergelog(xterm_titles, " *** emerge " + myelogstr) |
2474 |
+ del oldargs |
2475 |
+ |
2476 |
+ def emergeexitsig(signum, frame): |
2477 |
+ signal.signal(signal.SIGINT, signal.SIG_IGN) |
2478 |
+ signal.signal(signal.SIGTERM, signal.SIG_IGN) |
2479 |
+ portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) |
2480 |
+ sys.exit(100+signum) |
2481 |
+ signal.signal(signal.SIGINT, emergeexitsig) |
2482 |
+ signal.signal(signal.SIGTERM, emergeexitsig) |
2483 |
+ |
2484 |
+ def emergeexit(): |
2485 |
+ """This gets out final log message in before we quit.""" |
2486 |
+ if "--pretend" not in myopts: |
2487 |
+ emergelog(xterm_titles, " *** terminating.") |
2488 |
+ if "notitles" not in settings.features: |
2489 |
+ xtermTitleReset() |
2490 |
+ portage.atexit_register(emergeexit) |
2491 |
+ |
2492 |
+ if myaction in ("config", "metadata", "regen", "sync"): |
2493 |
+ if "--pretend" in myopts: |
2494 |
+ sys.stderr.write(("emerge: The '%s' action does " + \ |
2495 |
+ "not support '--pretend'.\n") % myaction) |
2496 |
+ return 1 |
2497 |
+ |
2498 |
+ if "sync" == myaction: |
2499 |
+ return action_sync(settings, trees, mtimedb, myopts, myaction) |
2500 |
+ elif "metadata" == myaction: |
2501 |
+ action_metadata(settings, portdb, myopts) |
2502 |
+ elif myaction=="regen": |
2503 |
+ validate_ebuild_environment(trees) |
2504 |
+ return action_regen(settings, portdb, myopts.get("--jobs"), |
2505 |
+ myopts.get("--load-average")) |
2506 |
+ # HELP action |
2507 |
+ elif "config"==myaction: |
2508 |
+ validate_ebuild_environment(trees) |
2509 |
+ action_config(settings, trees, myopts, myfiles) |
2510 |
+ |
2511 |
+ # SEARCH action |
2512 |
+ elif "search"==myaction: |
2513 |
+ validate_ebuild_environment(trees) |
2514 |
+ action_search(trees[settings["ROOT"]]["root_config"], |
2515 |
+ myopts, myfiles, spinner) |
2516 |
+ |
2517 |
+ elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'): |
2518 |
+ validate_ebuild_environment(trees) |
2519 |
+ rval = action_uninstall(settings, trees, mtimedb["ldpath"], |
2520 |
+ myopts, myaction, myfiles, spinner) |
2521 |
+ if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend): |
2522 |
+ post_emerge(root_config, myopts, mtimedb, rval) |
2523 |
+ return rval |
2524 |
+ |
2525 |
+ elif myaction == 'info': |
2526 |
+ |
2527 |
+ # Ensure atoms are valid before calling unmerge(). |
2528 |
+ vardb = trees[settings["ROOT"]]["vartree"].dbapi |
2529 |
+ valid_atoms = [] |
2530 |
+ for x in myfiles: |
2531 |
+ if is_valid_package_atom(x): |
2532 |
+ try: |
2533 |
+ valid_atoms.append( |
2534 |
+ portage.dep_expand(x, mydb=vardb, settings=settings)) |
2535 |
+ except portage.exception.AmbiguousPackageName, e: |
2536 |
+ msg = "The short ebuild name \"" + x + \ |
2537 |
+ "\" is ambiguous. Please specify " + \ |
2538 |
+ "one of the following " + \ |
2539 |
+ "fully-qualified ebuild names instead:" |
2540 |
+ for line in textwrap.wrap(msg, 70): |
2541 |
+ writemsg_level("!!! %s\n" % (line,), |
2542 |
+ level=logging.ERROR, noiselevel=-1) |
2543 |
+ for i in e[0]: |
2544 |
+ writemsg_level(" %s\n" % colorize("INFORM", i), |
2545 |
+ level=logging.ERROR, noiselevel=-1) |
2546 |
+ writemsg_level("\n", level=logging.ERROR, noiselevel=-1) |
2547 |
+ return 1 |
2548 |
+ continue |
2549 |
+ msg = [] |
2550 |
+ msg.append("'%s' is not a valid package atom." % (x,)) |
2551 |
+ msg.append("Please check ebuild(5) for full details.") |
2552 |
+ writemsg_level("".join("!!! %s\n" % line for line in msg), |
2553 |
+ level=logging.ERROR, noiselevel=-1) |
2554 |
+ return 1 |
2555 |
+ |
2556 |
+ return action_info(settings, trees, myopts, valid_atoms) |
2557 |
+ |
2558 |
+ # "update", "system", or just process files: |
2559 |
+ else: |
2560 |
+ validate_ebuild_environment(trees) |
2561 |
+ |
2562 |
+ for x in myfiles: |
2563 |
+ if x.startswith(SETPREFIX) or \ |
2564 |
+ is_valid_package_atom(x): |
2565 |
+ continue |
2566 |
+ if x[:1] == os.sep: |
2567 |
+ continue |
2568 |
+ try: |
2569 |
+ os.lstat(x) |
2570 |
+ continue |
2571 |
+ except OSError: |
2572 |
+ pass |
2573 |
+ msg = [] |
2574 |
+ msg.append("'%s' is not a valid package atom." % (x,)) |
2575 |
+ msg.append("Please check ebuild(5) for full details.") |
2576 |
+ writemsg_level("".join("!!! %s\n" % line for line in msg), |
2577 |
+ level=logging.ERROR, noiselevel=-1) |
2578 |
+ return 1 |
2579 |
+ |
2580 |
+ if "--pretend" not in myopts: |
2581 |
+ display_news_notification(root_config, myopts) |
2582 |
+ retval = action_build(settings, trees, mtimedb, |
2583 |
+ myopts, myaction, myfiles, spinner) |
2584 |
+ root_config = trees[settings["ROOT"]]["root_config"] |
2585 |
+ post_emerge(root_config, myopts, mtimedb, retval) |
2586 |
+ |
2587 |
+ return retval |