1 |
Author: grobian |
2 |
Date: 2010-02-27 19:32:48 +0000 (Sat, 27 Feb 2010) |
3 |
New Revision: 15483 |
4 |
|
5 |
Added: |
6 |
main/branches/prefix/pym/portage/dep/ |
7 |
main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py |
8 |
main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py |
9 |
main/branches/prefix/pym/portage/util/movefile.py |
10 |
Removed: |
11 |
main/branches/prefix/pym/portage/dep.py |
12 |
Modified: |
13 |
main/branches/prefix/pym/portage/__init__.py |
14 |
main/branches/prefix/pym/portage/dbapi/__init__.py |
15 |
main/branches/prefix/pym/portage/dbapi/vartree.py |
16 |
Log: |
17 |
Merged from trunk -r15460:15465 |
18 |
|
19 |
| 15461 | Move dep.py to dep/__init__.py, for splitting into smaller | |
20 |
| zmedico | files. | |
21 |
|
22 |
| 15462 | Move portage.dep_check and related functions to | |
23 |
| zmedico | portage.dep.dep_check. | |
24 |
|
25 |
| 15463 | Split getmaskingstatus and getmaskingreason info | |
26 |
| zmedico | portage.package.ebuild submodules. | |
27 |
|
28 |
| 15464 | Move portage.movefile to portage.util.movefile. | |
29 |
| zmedico | | |
30 |
|
31 |
| 15465 | Avoid name collision with dep_expand submodule so epydoc | |
32 |
| zmedico | won't crash. | |
33 |
|
34 |
|
35 |
Modified: main/branches/prefix/pym/portage/__init__.py |
36 |
=================================================================== |
37 |
--- main/branches/prefix/pym/portage/__init__.py 2010-02-27 19:26:00 UTC (rev 15482) |
38 |
+++ main/branches/prefix/pym/portage/__init__.py 2010-02-27 19:32:48 UTC (rev 15483) |
39 |
@@ -92,6 +92,7 @@ |
40 |
'portage.dep:best_match_to_list,dep_getcpv,dep_getkey,' + \ |
41 |
'flatten,get_operator,isjustname,isspecific,isvalidatom,' + \ |
42 |
'match_from_list,match_to_list', |
43 |
+ 'portage.dep.dep_check:dep_check,dep_eval,dep_wordreduce,dep_zapdeps', |
44 |
'portage.eclass_cache', |
45 |
'portage.env.loaders', |
46 |
'portage.exception', |
47 |
@@ -109,6 +110,8 @@ |
48 |
'portage.package.ebuild.digestcheck:digestcheck', |
49 |
'portage.package.ebuild.digestgen:digestgen', |
50 |
'portage.package.ebuild.fetch:fetch', |
51 |
+ 'portage.package.ebuild.getmaskingreason:getmaskingreason', |
52 |
+ 'portage.package.ebuild.getmaskingstatus:getmaskingstatus', |
53 |
'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs', |
54 |
'portage.process', |
55 |
'portage.process:atexit_register,run_exitfuncs', |
56 |
@@ -127,6 +130,7 @@ |
57 |
'portage.util.env_update:env_update', |
58 |
'portage.util.ExtractKernelVersion:ExtractKernelVersion', |
59 |
'portage.util.listdir:cacheddir,listdir', |
60 |
+ 'portage.util.movefile:movefile', |
61 |
'portage.versions', |
62 |
'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,' + \ |
63 |
'cpv_getkey@getCPFromCPV,endversion_keys,' + \ |
64 |
@@ -634,223 +638,6 @@ |
65 |
raise portage.exception.PortageException( |
66 |
"mv '%s' '%s'" % (src, dest)) |
67 |
|
68 |
-def movefile(src, dest, newmtime=None, sstat=None, mysettings=None, |
69 |
- hardlink_candidates=None, encoding=_encodings['fs']): |
70 |
- """moves a file from src to dest, preserving all permissions and attributes; mtime will |
71 |
- be preserved even when moving across filesystems. Returns true on success and false on |
72 |
- failure. Move is atomic.""" |
73 |
- #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")" |
74 |
- |
75 |
- if mysettings is None: |
76 |
- global settings |
77 |
- mysettings = settings |
78 |
- |
79 |
- selinux_enabled = mysettings.selinux_enabled() |
80 |
- if selinux_enabled: |
81 |
- selinux = _unicode_module_wrapper(_selinux, encoding=encoding) |
82 |
- |
83 |
- lchown = _unicode_func_wrapper(data.lchown, encoding=encoding) |
84 |
- os = _unicode_module_wrapper(_os, |
85 |
- encoding=encoding, overrides=_os_overrides) |
86 |
- shutil = _unicode_module_wrapper(_shutil, encoding=encoding) |
87 |
- |
88 |
- try: |
89 |
- if not sstat: |
90 |
- sstat=os.lstat(src) |
91 |
- |
92 |
- except SystemExit as e: |
93 |
- raise |
94 |
- except Exception as e: |
95 |
- print(_("!!! Stating source file failed... movefile()")) |
96 |
- print("!!!",e) |
97 |
- return None |
98 |
- |
99 |
- destexists=1 |
100 |
- try: |
101 |
- dstat=os.lstat(dest) |
102 |
- except (OSError, IOError): |
103 |
- dstat=os.lstat(os.path.dirname(dest)) |
104 |
- destexists=0 |
105 |
- |
106 |
- if bsd_chflags: |
107 |
- if destexists and dstat.st_flags != 0: |
108 |
- bsd_chflags.lchflags(dest, 0) |
109 |
- # Use normal stat/chflags for the parent since we want to |
110 |
- # follow any symlinks to the real parent directory. |
111 |
- pflags = os.stat(os.path.dirname(dest)).st_flags |
112 |
- if pflags != 0: |
113 |
- bsd_chflags.chflags(os.path.dirname(dest), 0) |
114 |
- |
115 |
- if destexists: |
116 |
- if stat.S_ISLNK(dstat[stat.ST_MODE]): |
117 |
- try: |
118 |
- os.unlink(dest) |
119 |
- destexists=0 |
120 |
- except SystemExit as e: |
121 |
- raise |
122 |
- except Exception as e: |
123 |
- pass |
124 |
- |
125 |
- if stat.S_ISLNK(sstat[stat.ST_MODE]): |
126 |
- try: |
127 |
- target=os.readlink(src) |
128 |
- if mysettings and mysettings["D"]: |
129 |
- if target.find(mysettings["D"])==0: |
130 |
- target=target[len(mysettings["D"]):] |
131 |
- if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): |
132 |
- os.unlink(dest) |
133 |
- if selinux_enabled: |
134 |
- selinux.symlink(target, dest, src) |
135 |
- else: |
136 |
- os.symlink(target,dest) |
137 |
- lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
138 |
- # utime() only works on the target of a symlink, so it's not |
139 |
- # possible to perserve mtime on symlinks. |
140 |
- return os.lstat(dest)[stat.ST_MTIME] |
141 |
- except SystemExit as e: |
142 |
- raise |
143 |
- except Exception as e: |
144 |
- print(_("!!! failed to properly create symlink:")) |
145 |
- print("!!!",dest,"->",target) |
146 |
- print("!!!",e) |
147 |
- return None |
148 |
- |
149 |
- hardlinked = False |
150 |
- # Since identical files might be merged to multiple filesystems, |
151 |
- # so os.link() calls might fail for some paths, so try them all. |
152 |
- # For atomic replacement, first create the link as a temp file |
153 |
- # and them use os.rename() to replace the destination. |
154 |
- if hardlink_candidates: |
155 |
- head, tail = os.path.split(dest) |
156 |
- hardlink_tmp = os.path.join(head, ".%s._portage_merge_.%s" % \ |
157 |
- (tail, os.getpid())) |
158 |
- try: |
159 |
- os.unlink(hardlink_tmp) |
160 |
- except OSError as e: |
161 |
- if e.errno != errno.ENOENT: |
162 |
- writemsg(_("!!! Failed to remove hardlink temp file: %s\n") % \ |
163 |
- (hardlink_tmp,), noiselevel=-1) |
164 |
- writemsg("!!! %s\n" % (e,), noiselevel=-1) |
165 |
- return None |
166 |
- del e |
167 |
- for hardlink_src in hardlink_candidates: |
168 |
- try: |
169 |
- os.link(hardlink_src, hardlink_tmp) |
170 |
- except OSError: |
171 |
- continue |
172 |
- else: |
173 |
- try: |
174 |
- os.rename(hardlink_tmp, dest) |
175 |
- except OSError as e: |
176 |
- writemsg(_("!!! Failed to rename %s to %s\n") % \ |
177 |
- (hardlink_tmp, dest), noiselevel=-1) |
178 |
- writemsg("!!! %s\n" % (e,), noiselevel=-1) |
179 |
- return None |
180 |
- hardlinked = True |
181 |
- break |
182 |
- |
183 |
- renamefailed=1 |
184 |
- if hardlinked: |
185 |
- renamefailed = False |
186 |
- if not hardlinked and (selinux_enabled or sstat.st_dev == dstat.st_dev): |
187 |
- try: |
188 |
- if selinux_enabled: |
189 |
- ret = selinux.rename(src, dest) |
190 |
- else: |
191 |
- ret=os.rename(src,dest) |
192 |
- renamefailed=0 |
193 |
- except OSError as e: |
194 |
- if e.errno != errno.EXDEV: |
195 |
- # Some random error. |
196 |
- print(_("!!! Failed to move %(src)s to %(dest)s") % {"src": src, "dest": dest}) |
197 |
- print("!!!",e) |
198 |
- return None |
199 |
- # Invalid cross-device-link 'bind' mounted or actually Cross-Device |
200 |
- if renamefailed: |
201 |
- didcopy=0 |
202 |
- if stat.S_ISREG(sstat[stat.ST_MODE]): |
203 |
- try: # For safety copy then move it over. |
204 |
- if selinux_enabled: |
205 |
- selinux.copyfile(src, dest + "#new") |
206 |
- selinux.rename(dest + "#new", dest) |
207 |
- else: |
208 |
- shutil.copyfile(src,dest+"#new") |
209 |
- os.rename(dest+"#new",dest) |
210 |
- didcopy=1 |
211 |
- except SystemExit as e: |
212 |
- raise |
213 |
- except Exception as e: |
214 |
- print(_('!!! copy %(src)s -> %(dest)s failed.') % {"src": src, "dest": dest}) |
215 |
- print("!!!",e) |
216 |
- return None |
217 |
- else: |
218 |
- #we don't yet handle special, so we need to fall back to /bin/mv |
219 |
- a = process.spawn([MOVE_BINARY, '-f', src, dest], env=os.environ) |
220 |
- if a != os.EX_OK: |
221 |
- writemsg(_("!!! Failed to move special file:\n"), noiselevel=-1) |
222 |
- writemsg(_("!!! '%(src)s' to '%(dest)s'\n") % \ |
223 |
- {"src": _unicode_decode(src, encoding=encoding), |
224 |
- "dest": _unicode_decode(dest, encoding=encoding)}, noiselevel=-1) |
225 |
- writemsg("!!! %s\n" % a, noiselevel=-1) |
226 |
- return None # failure |
227 |
- try: |
228 |
- if didcopy: |
229 |
- if stat.S_ISLNK(sstat[stat.ST_MODE]): |
230 |
- lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
231 |
- else: |
232 |
- os.chown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
233 |
- os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown |
234 |
- os.unlink(src) |
235 |
- except SystemExit as e: |
236 |
- raise |
237 |
- except Exception as e: |
238 |
- print(_("!!! Failed to chown/chmod/unlink in movefile()")) |
239 |
- print("!!!",dest) |
240 |
- print("!!!",e) |
241 |
- return None |
242 |
- |
243 |
- # Always use stat_obj[stat.ST_MTIME] for the integral timestamp which |
244 |
- # is returned, since the stat_obj.st_mtime float attribute rounds *up* |
245 |
- # if the nanosecond part of the timestamp is 999999881 ns or greater. |
246 |
- try: |
247 |
- if hardlinked: |
248 |
- newmtime = os.stat(dest)[stat.ST_MTIME] |
249 |
- else: |
250 |
- # Note: It is not possible to preserve nanosecond precision |
251 |
- # (supported in POSIX.1-2008 via utimensat) with the IEEE 754 |
252 |
- # double precision float which only has a 53 bit significand. |
253 |
- if newmtime is not None: |
254 |
- os.utime(dest, (newmtime, newmtime)) |
255 |
- else: |
256 |
- newmtime = sstat[stat.ST_MTIME] |
257 |
- if renamefailed: |
258 |
- # If rename succeeded then timestamps are automatically |
259 |
- # preserved with complete precision because the source |
260 |
- # and destination inode are the same. Otherwise, round |
261 |
- # down to the nearest whole second since python's float |
262 |
- # st_mtime cannot be used to preserve the st_mtim.tv_nsec |
263 |
- # field with complete precision. Note that we have to use |
264 |
- # stat_obj[stat.ST_MTIME] here because the float |
265 |
- # stat_obj.st_mtime rounds *up* sometimes. |
266 |
- os.utime(dest, (newmtime, newmtime)) |
267 |
- except OSError: |
268 |
- # The utime can fail here with EPERM even though the move succeeded. |
269 |
- # Instead of failing, use stat to return the mtime if possible. |
270 |
- try: |
271 |
- newmtime = os.stat(dest)[stat.ST_MTIME] |
272 |
- except OSError as e: |
273 |
- writemsg(_("!!! Failed to stat in movefile()\n"), noiselevel=-1) |
274 |
- writemsg("!!! %s\n" % dest, noiselevel=-1) |
275 |
- writemsg("!!! %s\n" % str(e), noiselevel=-1) |
276 |
- return None |
277 |
- |
278 |
- if bsd_chflags: |
279 |
- # Restore the flags we saved before moving |
280 |
- if pflags: |
281 |
- bsd_chflags.chflags(os.path.dirname(dest), pflags) |
282 |
- |
283 |
- return newmtime |
284 |
- |
285 |
def merge(mycat, mypkg, pkgloc, infloc, myroot, mysettings, myebuild=None, |
286 |
mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None, |
287 |
scheduler=None): |
288 |
@@ -911,835 +698,6 @@ |
289 |
newsplit.append(x) |
290 |
return newsplit |
291 |
|
292 |
-def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/", |
293 |
- trees=None, use_mask=None, use_force=None, **kwargs): |
294 |
- """ |
295 |
- In order to solve bug #141118, recursively expand new-style virtuals so |
296 |
- as to collapse one or more levels of indirection, generating an expanded |
297 |
- search space. In dep_zapdeps, new-style virtuals will be assigned |
298 |
- zero cost regardless of whether or not they are currently installed. Virtual |
299 |
- blockers are supported but only when the virtual expands to a single |
300 |
- atom because it wouldn't necessarily make sense to block all the components |
301 |
- of a compound virtual. When more than one new-style virtual is matched, |
302 |
- the matches are sorted from highest to lowest versions and the atom is |
303 |
- expanded to || ( highest match ... lowest match ).""" |
304 |
- newsplit = [] |
305 |
- mytrees = trees[myroot] |
306 |
- portdb = mytrees["porttree"].dbapi |
307 |
- atom_graph = mytrees.get("atom_graph") |
308 |
- parent = mytrees.get("parent") |
309 |
- virt_parent = mytrees.get("virt_parent") |
310 |
- graph_parent = None |
311 |
- eapi = None |
312 |
- if parent is not None: |
313 |
- if virt_parent is not None: |
314 |
- graph_parent = virt_parent |
315 |
- eapi = virt_parent[0].metadata['EAPI'] |
316 |
- else: |
317 |
- graph_parent = parent |
318 |
- eapi = parent.metadata["EAPI"] |
319 |
- repoman = not mysettings.local_config |
320 |
- if kwargs["use_binaries"]: |
321 |
- portdb = trees[myroot]["bintree"].dbapi |
322 |
- myvirtuals = mysettings.getvirtuals() |
323 |
- pprovideddict = mysettings.pprovideddict |
324 |
- myuse = kwargs["myuse"] |
325 |
- for x in mysplit: |
326 |
- if x == "||": |
327 |
- newsplit.append(x) |
328 |
- continue |
329 |
- elif isinstance(x, list): |
330 |
- newsplit.append(_expand_new_virtuals(x, edebug, mydbapi, |
331 |
- mysettings, myroot=myroot, trees=trees, use_mask=use_mask, |
332 |
- use_force=use_force, **kwargs)) |
333 |
- continue |
334 |
- |
335 |
- if not isinstance(x, portage.dep.Atom): |
336 |
- try: |
337 |
- x = portage.dep.Atom(x) |
338 |
- except portage.exception.InvalidAtom: |
339 |
- if portage.dep._dep_check_strict: |
340 |
- raise portage.exception.ParseError( |
341 |
- _("invalid atom: '%s'") % x) |
342 |
- else: |
343 |
- # Only real Atom instances are allowed past this point. |
344 |
- continue |
345 |
- else: |
346 |
- if x.blocker and x.blocker.overlap.forbid and \ |
347 |
- eapi in ("0", "1") and portage.dep._dep_check_strict: |
348 |
- raise portage.exception.ParseError( |
349 |
- _("invalid atom: '%s'") % (x,)) |
350 |
- if x.use and eapi in ("0", "1") and \ |
351 |
- portage.dep._dep_check_strict: |
352 |
- raise portage.exception.ParseError( |
353 |
- _("invalid atom: '%s'") % (x,)) |
354 |
- |
355 |
- if repoman and x.use and x.use.conditional: |
356 |
- evaluated_atom = portage.dep.remove_slot(x) |
357 |
- if x.slot: |
358 |
- evaluated_atom += ":%s" % x.slot |
359 |
- evaluated_atom += str(x.use._eval_qa_conditionals( |
360 |
- use_mask, use_force)) |
361 |
- x = portage.dep.Atom(evaluated_atom) |
362 |
- |
363 |
- if not repoman and \ |
364 |
- myuse is not None and isinstance(x, portage.dep.Atom) and x.use: |
365 |
- if x.use.conditional: |
366 |
- x = x.evaluate_conditionals(myuse) |
367 |
- |
368 |
- mykey = x.cp |
369 |
- if not mykey.startswith("virtual/"): |
370 |
- newsplit.append(x) |
371 |
- if atom_graph is not None: |
372 |
- atom_graph.add(x, graph_parent) |
373 |
- continue |
374 |
- mychoices = myvirtuals.get(mykey, []) |
375 |
- if x.blocker: |
376 |
- # Virtual blockers are no longer expanded here since |
377 |
- # the un-expanded virtual atom is more useful for |
378 |
- # maintaining a cache of blocker atoms. |
379 |
- newsplit.append(x) |
380 |
- if atom_graph is not None: |
381 |
- atom_graph.add(x, graph_parent) |
382 |
- continue |
383 |
- |
384 |
- if repoman or not hasattr(portdb, 'match_pkgs'): |
385 |
- if portdb.cp_list(x.cp): |
386 |
- newsplit.append(x) |
387 |
- else: |
388 |
- # TODO: Add PROVIDE check for repoman. |
389 |
- a = [] |
390 |
- for y in mychoices: |
391 |
- a.append(dep.Atom(x.replace(x.cp, y.cp, 1))) |
392 |
- if not a: |
393 |
- newsplit.append(x) |
394 |
- elif len(a) == 1: |
395 |
- newsplit.append(a[0]) |
396 |
- else: |
397 |
- newsplit.append(['||'] + a) |
398 |
- continue |
399 |
- |
400 |
- pkgs = [] |
401 |
- # Ignore USE deps here, since otherwise we might not |
402 |
- # get any matches. Choices with correct USE settings |
403 |
- # will be preferred in dep_zapdeps(). |
404 |
- matches = portdb.match_pkgs(x.without_use) |
405 |
- # Use descending order to prefer higher versions. |
406 |
- matches.reverse() |
407 |
- for pkg in matches: |
408 |
- # only use new-style matches |
409 |
- if pkg.cp.startswith("virtual/"): |
410 |
- pkgs.append(pkg) |
411 |
- if not (pkgs or mychoices): |
412 |
- # This one couldn't be expanded as a new-style virtual. Old-style |
413 |
- # virtuals have already been expanded by dep_virtual, so this one |
414 |
- # is unavailable and dep_zapdeps will identify it as such. The |
415 |
- # atom is not eliminated here since it may still represent a |
416 |
- # dependency that needs to be satisfied. |
417 |
- newsplit.append(x) |
418 |
- if atom_graph is not None: |
419 |
- atom_graph.add(x, graph_parent) |
420 |
- continue |
421 |
- |
422 |
- a = [] |
423 |
- for pkg in pkgs: |
424 |
- virt_atom = '=' + pkg.cpv |
425 |
- if x.use: |
426 |
- virt_atom += str(x.use) |
427 |
- virt_atom = dep.Atom(virt_atom) |
428 |
- # According to GLEP 37, RDEPEND is the only dependency |
429 |
- # type that is valid for new-style virtuals. Repoman |
430 |
- # should enforce this. |
431 |
- depstring = pkg.metadata['RDEPEND'] |
432 |
- pkg_kwargs = kwargs.copy() |
433 |
- pkg_kwargs["myuse"] = pkg.use.enabled |
434 |
- if edebug: |
435 |
- util.writemsg_level(_("Virtual Parent: %s\n") \ |
436 |
- % (pkg,), noiselevel=-1, level=logging.DEBUG) |
437 |
- util.writemsg_level(_("Virtual Depstring: %s\n") \ |
438 |
- % (depstring,), noiselevel=-1, level=logging.DEBUG) |
439 |
- |
440 |
- # Set EAPI used for validation in dep_check() recursion. |
441 |
- mytrees["virt_parent"] = (pkg, virt_atom) |
442 |
- |
443 |
- try: |
444 |
- mycheck = dep_check(depstring, mydbapi, mysettings, |
445 |
- myroot=myroot, trees=trees, **pkg_kwargs) |
446 |
- finally: |
447 |
- # Restore previous EAPI after recursion. |
448 |
- if virt_parent is not None: |
449 |
- mytrees["virt_parent"] = virt_parent |
450 |
- else: |
451 |
- del mytrees["virt_parent"] |
452 |
- |
453 |
- if not mycheck[0]: |
454 |
- raise portage.exception.ParseError( |
455 |
- "%s: %s '%s'" % (y[0], mycheck[1], depstring)) |
456 |
- |
457 |
- # pull in the new-style virtual |
458 |
- mycheck[1].append(virt_atom) |
459 |
- a.append(mycheck[1]) |
460 |
- if atom_graph is not None: |
461 |
- atom_graph.add(virt_atom, graph_parent) |
462 |
- # Plain old-style virtuals. New-style virtuals are preferred. |
463 |
- if not pkgs: |
464 |
- for y in mychoices: |
465 |
- new_atom = dep.Atom(x.replace(x.cp, y.cp, 1)) |
466 |
- matches = portdb.match(new_atom) |
467 |
- # portdb is an instance of depgraph._dep_check_composite_db, so |
468 |
- # USE conditionals are already evaluated. |
469 |
- if matches and mykey in \ |
470 |
- portdb.aux_get(matches[-1], ['PROVIDE'])[0].split(): |
471 |
- a.append(new_atom) |
472 |
- if atom_graph is not None: |
473 |
- atom_graph.add(new_atom, graph_parent) |
474 |
- |
475 |
- if not a and mychoices: |
476 |
- # Check for a virtual package.provided match. |
477 |
- for y in mychoices: |
478 |
- new_atom = dep.Atom(x.replace(x.cp, y.cp, 1)) |
479 |
- if match_from_list(new_atom, |
480 |
- pprovideddict.get(new_atom.cp, [])): |
481 |
- a.append(new_atom) |
482 |
- if atom_graph is not None: |
483 |
- atom_graph.add(new_atom, graph_parent) |
484 |
- |
485 |
- if not a: |
486 |
- newsplit.append(x) |
487 |
- if atom_graph is not None: |
488 |
- atom_graph.add(x, graph_parent) |
489 |
- elif len(a) == 1: |
490 |
- newsplit.append(a[0]) |
491 |
- else: |
492 |
- newsplit.append(['||'] + a) |
493 |
- |
494 |
- return newsplit |
495 |
- |
496 |
-def dep_eval(deplist): |
497 |
- if not deplist: |
498 |
- return 1 |
499 |
- if deplist[0]=="||": |
500 |
- #or list; we just need one "1" |
501 |
- for x in deplist[1:]: |
502 |
- if isinstance(x, list): |
503 |
- if dep_eval(x)==1: |
504 |
- return 1 |
505 |
- elif x==1: |
506 |
- return 1 |
507 |
- #XXX: unless there's no available atoms in the list |
508 |
- #in which case we need to assume that everything is |
509 |
- #okay as some ebuilds are relying on an old bug. |
510 |
- if len(deplist) == 1: |
511 |
- return 1 |
512 |
- return 0 |
513 |
- else: |
514 |
- for x in deplist: |
515 |
- if isinstance(x, list): |
516 |
- if dep_eval(x)==0: |
517 |
- return 0 |
518 |
- elif x==0 or x==2: |
519 |
- return 0 |
520 |
- return 1 |
521 |
- |
522 |
-def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): |
523 |
- """Takes an unreduced and reduced deplist and removes satisfied dependencies. |
524 |
- Returned deplist contains steps that must be taken to satisfy dependencies.""" |
525 |
- if trees is None: |
526 |
- global db |
527 |
- trees = db |
528 |
- writemsg("ZapDeps -- %s\n" % (use_binaries), 2) |
529 |
- if not reduced or unreduced == ["||"] or dep_eval(reduced): |
530 |
- return [] |
531 |
- |
532 |
- if unreduced[0] != "||": |
533 |
- unresolved = [] |
534 |
- for x, satisfied in zip(unreduced, reduced): |
535 |
- if isinstance(x, list): |
536 |
- unresolved += dep_zapdeps(x, satisfied, myroot, |
537 |
- use_binaries=use_binaries, trees=trees) |
538 |
- elif not satisfied: |
539 |
- unresolved.append(x) |
540 |
- return unresolved |
541 |
- |
542 |
- # We're at a ( || atom ... ) type level and need to make a choice |
543 |
- deps = unreduced[1:] |
544 |
- satisfieds = reduced[1:] |
545 |
- |
546 |
- # Our preference order is for an the first item that: |
547 |
- # a) contains all unmasked packages with the same key as installed packages |
548 |
- # b) contains all unmasked packages |
549 |
- # c) contains masked installed packages |
550 |
- # d) is the first item |
551 |
- |
552 |
- preferred_installed = [] |
553 |
- preferred_in_graph = [] |
554 |
- preferred_any_slot = [] |
555 |
- preferred_non_installed = [] |
556 |
- unsat_use_in_graph = [] |
557 |
- unsat_use_installed = [] |
558 |
- unsat_use_non_installed = [] |
559 |
- other = [] |
560 |
- |
561 |
- # unsat_use_* must come after preferred_non_installed |
562 |
- # for correct ordering in cases like || ( foo[a] foo[b] ). |
563 |
- choice_bins = ( |
564 |
- preferred_in_graph, |
565 |
- preferred_installed, |
566 |
- preferred_any_slot, |
567 |
- preferred_non_installed, |
568 |
- unsat_use_in_graph, |
569 |
- unsat_use_installed, |
570 |
- unsat_use_non_installed, |
571 |
- other, |
572 |
- ) |
573 |
- |
574 |
- # Alias the trees we'll be checking availability against |
575 |
- parent = trees[myroot].get("parent") |
576 |
- priority = trees[myroot].get("priority") |
577 |
- graph_db = trees[myroot].get("graph_db") |
578 |
- vardb = None |
579 |
- if "vartree" in trees[myroot]: |
580 |
- vardb = trees[myroot]["vartree"].dbapi |
581 |
- if use_binaries: |
582 |
- mydbapi = trees[myroot]["bintree"].dbapi |
583 |
- else: |
584 |
- mydbapi = trees[myroot]["porttree"].dbapi |
585 |
- |
586 |
- # Sort the deps into installed, not installed but already |
587 |
- # in the graph and other, not installed and not in the graph |
588 |
- # and other, with values of [[required_atom], availablility] |
589 |
- for x, satisfied in zip(deps, satisfieds): |
590 |
- if isinstance(x, list): |
591 |
- atoms = dep_zapdeps(x, satisfied, myroot, |
592 |
- use_binaries=use_binaries, trees=trees) |
593 |
- else: |
594 |
- atoms = [x] |
595 |
- if vardb is None: |
596 |
- # When called by repoman, we can simply return the first choice |
597 |
- # because dep_eval() handles preference selection. |
598 |
- return atoms |
599 |
- |
600 |
- all_available = True |
601 |
- all_use_satisfied = True |
602 |
- slot_map = {} |
603 |
- cp_map = {} |
604 |
- for atom in atoms: |
605 |
- if atom.blocker: |
606 |
- continue |
607 |
- # Ignore USE dependencies here since we don't want USE |
608 |
- # settings to adversely affect || preference evaluation. |
609 |
- avail_pkg = mydbapi.match(atom.without_use) |
610 |
- if avail_pkg: |
611 |
- avail_pkg = avail_pkg[-1] # highest (ascending order) |
612 |
- avail_slot = dep.Atom("%s:%s" % (atom.cp, |
613 |
- mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) |
614 |
- if not avail_pkg: |
615 |
- all_available = False |
616 |
- all_use_satisfied = False |
617 |
- break |
618 |
- |
619 |
- if atom.use: |
620 |
- avail_pkg_use = mydbapi.match(atom) |
621 |
- if not avail_pkg_use: |
622 |
- all_use_satisfied = False |
623 |
- else: |
624 |
- # highest (ascending order) |
625 |
- avail_pkg_use = avail_pkg_use[-1] |
626 |
- if avail_pkg_use != avail_pkg: |
627 |
- avail_pkg = avail_pkg_use |
628 |
- avail_slot = dep.Atom("%s:%s" % (atom.cp, |
629 |
- mydbapi.aux_get(avail_pkg, ["SLOT"])[0])) |
630 |
- |
631 |
- slot_map[avail_slot] = avail_pkg |
632 |
- pkg_cp = cpv_getkey(avail_pkg) |
633 |
- highest_cpv = cp_map.get(pkg_cp) |
634 |
- if highest_cpv is None or \ |
635 |
- pkgcmp(catpkgsplit(avail_pkg)[1:], |
636 |
- catpkgsplit(highest_cpv)[1:]) > 0: |
637 |
- cp_map[pkg_cp] = avail_pkg |
638 |
- |
639 |
- this_choice = (atoms, slot_map, cp_map, all_available) |
640 |
- if all_available: |
641 |
- # The "all installed" criterion is not version or slot specific. |
642 |
- # If any version of a package is already in the graph then we |
643 |
- # assume that it is preferred over other possible packages choices. |
644 |
- all_installed = True |
645 |
- for atom in set(dep.Atom(atom.cp) for atom in atoms \ |
646 |
- if not atom.blocker): |
647 |
- # New-style virtuals have zero cost to install. |
648 |
- if not vardb.match(atom) and not atom.startswith("virtual/"): |
649 |
- all_installed = False |
650 |
- break |
651 |
- all_installed_slots = False |
652 |
- if all_installed: |
653 |
- all_installed_slots = True |
654 |
- for slot_atom in slot_map: |
655 |
- # New-style virtuals have zero cost to install. |
656 |
- if not vardb.match(slot_atom) and \ |
657 |
- not slot_atom.startswith("virtual/"): |
658 |
- all_installed_slots = False |
659 |
- break |
660 |
- if graph_db is None: |
661 |
- if all_use_satisfied: |
662 |
- if all_installed: |
663 |
- if all_installed_slots: |
664 |
- preferred_installed.append(this_choice) |
665 |
- else: |
666 |
- preferred_any_slot.append(this_choice) |
667 |
- else: |
668 |
- preferred_non_installed.append(this_choice) |
669 |
- else: |
670 |
- if all_installed_slots: |
671 |
- unsat_use_installed.append(this_choice) |
672 |
- else: |
673 |
- unsat_use_non_installed.append(this_choice) |
674 |
- else: |
675 |
- all_in_graph = True |
676 |
- for slot_atom in slot_map: |
677 |
- # New-style virtuals have zero cost to install. |
678 |
- if not graph_db.match(slot_atom) and \ |
679 |
- not slot_atom.startswith("virtual/"): |
680 |
- all_in_graph = False |
681 |
- break |
682 |
- circular_atom = None |
683 |
- if all_in_graph: |
684 |
- if parent is None or priority is None: |
685 |
- pass |
686 |
- elif priority.buildtime: |
687 |
- # Check if the atom would result in a direct circular |
688 |
- # dependency and try to avoid that if it seems likely |
689 |
- # to be unresolvable. This is only relevant for |
690 |
- # buildtime deps that aren't already satisfied by an |
691 |
- # installed package. |
692 |
- cpv_slot_list = [parent] |
693 |
- for atom in atoms: |
694 |
- if atom.blocker: |
695 |
- continue |
696 |
- if vardb.match(atom): |
697 |
- # If the atom is satisfied by an installed |
698 |
- # version then it's not a circular dep. |
699 |
- continue |
700 |
- if atom.cp != parent.cp: |
701 |
- continue |
702 |
- if match_from_list(atom, cpv_slot_list): |
703 |
- circular_atom = atom |
704 |
- break |
705 |
- if circular_atom is not None: |
706 |
- other.append(this_choice) |
707 |
- else: |
708 |
- if all_use_satisfied: |
709 |
- if all_in_graph: |
710 |
- preferred_in_graph.append(this_choice) |
711 |
- elif all_installed: |
712 |
- if all_installed_slots: |
713 |
- preferred_installed.append(this_choice) |
714 |
- else: |
715 |
- preferred_any_slot.append(this_choice) |
716 |
- else: |
717 |
- preferred_non_installed.append(this_choice) |
718 |
- else: |
719 |
- if all_in_graph: |
720 |
- unsat_use_in_graph.append(this_choice) |
721 |
- elif all_installed_slots: |
722 |
- unsat_use_installed.append(this_choice) |
723 |
- else: |
724 |
- unsat_use_non_installed.append(this_choice) |
725 |
- else: |
726 |
- other.append(this_choice) |
727 |
- |
728 |
- # Prefer choices which contain upgrades to higher slots. This helps |
729 |
- # for deps such as || ( foo:1 foo:2 ), where we want to prefer the |
730 |
- # atom which matches the higher version rather than the atom furthest |
731 |
- # to the left. Sorting is done separately for each of choice_bins, so |
732 |
- # as not to interfere with the ordering of the bins. Because of the |
733 |
- # bin separation, the main function of this code is to allow |
734 |
- # --depclean to remove old slots (rather than to pull in new slots). |
735 |
- for choices in choice_bins: |
736 |
- if len(choices) < 2: |
737 |
- continue |
738 |
- for choice_1 in choices[1:]: |
739 |
- atoms_1, slot_map_1, cp_map_1, all_available_1 = choice_1 |
740 |
- cps = set(cp_map_1) |
741 |
- for choice_2 in choices: |
742 |
- if choice_1 is choice_2: |
743 |
- # choice_1 will not be promoted, so move on |
744 |
- break |
745 |
- atoms_2, slot_map_2, cp_map_2, all_available_2 = choice_2 |
746 |
- intersecting_cps = cps.intersection(cp_map_2) |
747 |
- if not intersecting_cps: |
748 |
- continue |
749 |
- has_upgrade = False |
750 |
- has_downgrade = False |
751 |
- for cp in intersecting_cps: |
752 |
- version_1 = cp_map_1[cp] |
753 |
- version_2 = cp_map_2[cp] |
754 |
- difference = pkgcmp(catpkgsplit(version_1)[1:], |
755 |
- catpkgsplit(version_2)[1:]) |
756 |
- if difference != 0: |
757 |
- if difference > 0: |
758 |
- has_upgrade = True |
759 |
- else: |
760 |
- has_downgrade = True |
761 |
- break |
762 |
- if has_upgrade and not has_downgrade: |
763 |
- # promote choice_1 in front of choice_2 |
764 |
- choices.remove(choice_1) |
765 |
- index_2 = choices.index(choice_2) |
766 |
- choices.insert(index_2, choice_1) |
767 |
- break |
768 |
- |
769 |
- for allow_masked in (False, True): |
770 |
- for choices in choice_bins: |
771 |
- for atoms, slot_map, cp_map, all_available in choices: |
772 |
- if all_available or allow_masked: |
773 |
- return atoms |
774 |
- |
775 |
- assert(False) # This point should not be reachable |
776 |
- |
777 |
-def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None, |
778 |
- use_cache=1, use_binaries=0, myroot="/", trees=None): |
779 |
- """Takes a depend string and parses the condition.""" |
780 |
- edebug = mysettings.get("PORTAGE_DEBUG", None) == "1" |
781 |
- #check_config_instance(mysettings) |
782 |
- if trees is None: |
783 |
- trees = globals()["db"] |
784 |
- if use=="yes": |
785 |
- if myuse is None: |
786 |
- #default behavior |
787 |
- myusesplit = mysettings["PORTAGE_USE"].split() |
788 |
- else: |
789 |
- myusesplit = myuse |
790 |
- # We've been given useflags to use. |
791 |
- #print "USE FLAGS PASSED IN." |
792 |
- #print myuse |
793 |
- #if "bindist" in myusesplit: |
794 |
- # print "BINDIST is set!" |
795 |
- #else: |
796 |
- # print "BINDIST NOT set." |
797 |
- else: |
798 |
- #we are being run by autouse(), don't consult USE vars yet. |
799 |
- # WE ALSO CANNOT USE SETTINGS |
800 |
- myusesplit=[] |
801 |
- |
802 |
- #convert parenthesis to sublists |
803 |
- try: |
804 |
- mysplit = portage.dep.paren_reduce(depstring) |
805 |
- except portage.exception.InvalidDependString as e: |
806 |
- return [0, str(e)] |
807 |
- |
808 |
- mymasks = set() |
809 |
- useforce = set() |
810 |
- useforce.add(mysettings["ARCH"]) |
811 |
- if use == "all": |
812 |
- # This masking/forcing is only for repoman. In other cases, relevant |
813 |
- # masking/forcing should have already been applied via |
814 |
- # config.regenerate(). Also, binary or installed packages may have |
815 |
- # been built with flags that are now masked, and it would be |
816 |
- # inconsistent to mask them now. Additionally, myuse may consist of |
817 |
- # flags from a parent package that is being merged to a $ROOT that is |
818 |
- # different from the one that mysettings represents. |
819 |
- mymasks.update(mysettings.usemask) |
820 |
- mymasks.update(mysettings.archlist()) |
821 |
- mymasks.discard(mysettings["ARCH"]) |
822 |
- useforce.update(mysettings.useforce) |
823 |
- useforce.difference_update(mymasks) |
824 |
- try: |
825 |
- mysplit = portage.dep.use_reduce(mysplit, uselist=myusesplit, |
826 |
- masklist=mymasks, matchall=(use=="all"), excludeall=useforce) |
827 |
- except portage.exception.InvalidDependString as e: |
828 |
- return [0, str(e)] |
829 |
- |
830 |
- # Do the || conversions |
831 |
- mysplit=portage.dep.dep_opconvert(mysplit) |
832 |
- |
833 |
- if mysplit == []: |
834 |
- #dependencies were reduced to nothing |
835 |
- return [1,[]] |
836 |
- |
837 |
- # Recursively expand new-style virtuals so as to |
838 |
- # collapse one or more levels of indirection. |
839 |
- try: |
840 |
- mysplit = _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, |
841 |
- use=use, mode=mode, myuse=myuse, |
842 |
- use_force=useforce, use_mask=mymasks, use_cache=use_cache, |
843 |
- use_binaries=use_binaries, myroot=myroot, trees=trees) |
844 |
- except portage.exception.ParseError as e: |
845 |
- return [0, str(e)] |
846 |
- |
847 |
- mysplit2=mysplit[:] |
848 |
- mysplit2=dep_wordreduce(mysplit2,mysettings,mydbapi,mode,use_cache=use_cache) |
849 |
- if mysplit2 is None: |
850 |
- return [0, _("Invalid token")] |
851 |
- |
852 |
- writemsg("\n\n\n", 1) |
853 |
- writemsg("mysplit: %s\n" % (mysplit), 1) |
854 |
- writemsg("mysplit2: %s\n" % (mysplit2), 1) |
855 |
- |
856 |
- try: |
857 |
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot, |
858 |
- use_binaries=use_binaries, trees=trees) |
859 |
- except portage.exception.InvalidAtom as e: |
860 |
- if portage.dep._dep_check_strict: |
861 |
- raise # This shouldn't happen. |
862 |
- # dbapi.match() failed due to an invalid atom in |
863 |
- # the dependencies of an installed package. |
864 |
- return [0, _("Invalid atom: '%s'") % (e,)] |
865 |
- |
866 |
- return [1, selected_atoms] |
867 |
- |
868 |
-def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1): |
869 |
- "Reduces the deplist to ones and zeros" |
870 |
- deplist=mydeplist[:] |
871 |
- for mypos, token in enumerate(deplist): |
872 |
- if isinstance(deplist[mypos], list): |
873 |
- #recurse |
874 |
- deplist[mypos]=dep_wordreduce(deplist[mypos],mysettings,mydbapi,mode,use_cache=use_cache) |
875 |
- elif deplist[mypos]=="||": |
876 |
- pass |
877 |
- elif token[:1] == "!": |
878 |
- deplist[mypos] = False |
879 |
- else: |
880 |
- mykey = deplist[mypos].cp |
881 |
- if mysettings and mykey in mysettings.pprovideddict and \ |
882 |
- match_from_list(deplist[mypos], mysettings.pprovideddict[mykey]): |
883 |
- deplist[mypos]=True |
884 |
- elif mydbapi is None: |
885 |
- # Assume nothing is satisfied. This forces dep_zapdeps to |
886 |
- # return all of deps the deps that have been selected |
887 |
- # (excluding those satisfied by package.provided). |
888 |
- deplist[mypos] = False |
889 |
- else: |
890 |
- if mode: |
891 |
- x = mydbapi.xmatch(mode, deplist[mypos]) |
892 |
- if mode.startswith("minimum-"): |
893 |
- mydep = [] |
894 |
- if x: |
895 |
- mydep.append(x) |
896 |
- else: |
897 |
- mydep = x |
898 |
- else: |
899 |
- mydep=mydbapi.match(deplist[mypos],use_cache=use_cache) |
900 |
- if mydep!=None: |
901 |
- tmp=(len(mydep)>=1) |
902 |
- if deplist[mypos][0]=="!": |
903 |
- tmp=False |
904 |
- deplist[mypos]=tmp |
905 |
- else: |
906 |
- #encountered invalid string |
907 |
- return None |
908 |
- return deplist |
909 |
- |
910 |
-def getmaskingreason(mycpv, metadata=None, settings=None, portdb=None, return_location=False): |
911 |
- from portage.util import grablines |
912 |
- if settings is None: |
913 |
- settings = globals()["settings"] |
914 |
- if portdb is None: |
915 |
- portdb = globals()["portdb"] |
916 |
- mysplit = catpkgsplit(mycpv) |
917 |
- if not mysplit: |
918 |
- raise ValueError(_("invalid CPV: %s") % mycpv) |
919 |
- if metadata is None: |
920 |
- db_keys = list(portdb._aux_cache_keys) |
921 |
- try: |
922 |
- metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) |
923 |
- except KeyError: |
924 |
- if not portdb.cpv_exists(mycpv): |
925 |
- raise |
926 |
- if metadata is None: |
927 |
- # Can't access SLOT due to corruption. |
928 |
- cpv_slot_list = [mycpv] |
929 |
- else: |
930 |
- cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] |
931 |
- mycp=mysplit[0]+"/"+mysplit[1] |
932 |
- |
933 |
- # XXX- This is a temporary duplicate of code from the config constructor. |
934 |
- locations = [os.path.join(settings["PORTDIR"], "profiles")] |
935 |
- locations.extend(settings.profiles) |
936 |
- for ov in settings["PORTDIR_OVERLAY"].split(): |
937 |
- profdir = os.path.join(normalize_path(ov), "profiles") |
938 |
- if os.path.isdir(profdir): |
939 |
- locations.append(profdir) |
940 |
- locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"], |
941 |
- USER_CONFIG_PATH)) |
942 |
- locations.reverse() |
943 |
- pmasklists = [(x, grablines(os.path.join(x, "package.mask"), recursive=1)) for x in locations] |
944 |
- |
945 |
- if mycp in settings.pmaskdict: |
946 |
- for x in settings.pmaskdict[mycp]: |
947 |
- if match_from_list(x, cpv_slot_list): |
948 |
- for pmask in pmasklists: |
949 |
- comment = "" |
950 |
- comment_valid = -1 |
951 |
- pmask_filename = os.path.join(pmask[0], "package.mask") |
952 |
- for i in range(len(pmask[1])): |
953 |
- l = pmask[1][i].strip() |
954 |
- if l == "": |
955 |
- comment = "" |
956 |
- comment_valid = -1 |
957 |
- elif l[0] == "#": |
958 |
- comment += (l+"\n") |
959 |
- comment_valid = i + 1 |
960 |
- elif l == x: |
961 |
- if comment_valid != i: |
962 |
- comment = "" |
963 |
- if return_location: |
964 |
- return (comment, pmask_filename) |
965 |
- else: |
966 |
- return comment |
967 |
- elif comment_valid != -1: |
968 |
- # Apparently this comment applies to muliple masks, so |
969 |
- # it remains valid until a blank line is encountered. |
970 |
- comment_valid += 1 |
971 |
- if return_location: |
972 |
- return (None, None) |
973 |
- else: |
974 |
- return None |
975 |
- |
976 |
-def getmaskingstatus(mycpv, settings=None, portdb=None): |
977 |
- if settings is None: |
978 |
- settings = config(clone=globals()["settings"]) |
979 |
- if portdb is None: |
980 |
- portdb = globals()["portdb"] |
981 |
- |
982 |
- metadata = None |
983 |
- installed = False |
984 |
- if not isinstance(mycpv, basestring): |
985 |
- # emerge passed in a Package instance |
986 |
- pkg = mycpv |
987 |
- mycpv = pkg.cpv |
988 |
- metadata = pkg.metadata |
989 |
- installed = pkg.installed |
990 |
- |
991 |
- mysplit = catpkgsplit(mycpv) |
992 |
- if not mysplit: |
993 |
- raise ValueError(_("invalid CPV: %s") % mycpv) |
994 |
- if metadata is None: |
995 |
- db_keys = list(portdb._aux_cache_keys) |
996 |
- try: |
997 |
- metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) |
998 |
- except KeyError: |
999 |
- if not portdb.cpv_exists(mycpv): |
1000 |
- raise |
1001 |
- return ["corruption"] |
1002 |
- if "?" in metadata["LICENSE"]: |
1003 |
- settings.setcpv(mycpv, mydb=metadata) |
1004 |
- metadata["USE"] = settings["PORTAGE_USE"] |
1005 |
- else: |
1006 |
- metadata["USE"] = "" |
1007 |
- mycp=mysplit[0]+"/"+mysplit[1] |
1008 |
- |
1009 |
- rValue = [] |
1010 |
- |
1011 |
- # profile checking |
1012 |
- if settings._getProfileMaskAtom(mycpv, metadata): |
1013 |
- rValue.append("profile") |
1014 |
- |
1015 |
- # package.mask checking |
1016 |
- if settings._getMaskAtom(mycpv, metadata): |
1017 |
- rValue.append("package.mask") |
1018 |
- |
1019 |
- # keywords checking |
1020 |
- eapi = metadata["EAPI"] |
1021 |
- mygroups = settings._getKeywords(mycpv, metadata) |
1022 |
- licenses = metadata["LICENSE"] |
1023 |
- properties = metadata["PROPERTIES"] |
1024 |
- slot = metadata["SLOT"] |
1025 |
- if eapi.startswith("-"): |
1026 |
- eapi = eapi[1:] |
1027 |
- if not eapi_is_supported(eapi): |
1028 |
- return ["EAPI %s" % eapi] |
1029 |
- elif _eapi_is_deprecated(eapi) and not installed: |
1030 |
- return ["EAPI %s" % eapi] |
1031 |
- egroups = settings.configdict["backupenv"].get( |
1032 |
- "ACCEPT_KEYWORDS", "").split() |
1033 |
- pgroups = settings["ACCEPT_KEYWORDS"].split() |
1034 |
- myarch = settings["ARCH"] |
1035 |
- if pgroups and myarch not in pgroups: |
1036 |
- """For operating systems other than Linux, ARCH is not necessarily a |
1037 |
- valid keyword.""" |
1038 |
- myarch = pgroups[0].lstrip("~") |
1039 |
- |
1040 |
- cp = cpv_getkey(mycpv) |
1041 |
- pkgdict = settings.pkeywordsdict.get(cp) |
1042 |
- matches = False |
1043 |
- if pkgdict: |
1044 |
- cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] |
1045 |
- for atom, pkgkeywords in pkgdict.items(): |
1046 |
- if match_from_list(atom, cpv_slot_list): |
1047 |
- matches = True |
1048 |
- pgroups.extend(pkgkeywords) |
1049 |
- if matches or egroups: |
1050 |
- pgroups.extend(egroups) |
1051 |
- inc_pgroups = set() |
1052 |
- for x in pgroups: |
1053 |
- if x.startswith("-"): |
1054 |
- if x == "-*": |
1055 |
- inc_pgroups.clear() |
1056 |
- else: |
1057 |
- inc_pgroups.discard(x[1:]) |
1058 |
- else: |
1059 |
- inc_pgroups.add(x) |
1060 |
- pgroups = inc_pgroups |
1061 |
- del inc_pgroups |
1062 |
- |
1063 |
- kmask = "missing" |
1064 |
- |
1065 |
- if '**' in pgroups: |
1066 |
- kmask = None |
1067 |
- else: |
1068 |
- for keyword in pgroups: |
1069 |
- if keyword in mygroups: |
1070 |
- kmask = None |
1071 |
- break |
1072 |
- |
1073 |
- if kmask: |
1074 |
- fallback = None |
1075 |
- for gp in mygroups: |
1076 |
- if gp=="*": |
1077 |
- kmask=None |
1078 |
- break |
1079 |
- elif gp=="-"+myarch and myarch in pgroups: |
1080 |
- kmask="-"+myarch |
1081 |
- break |
1082 |
- elif gp=="~"+myarch and myarch in pgroups: |
1083 |
- kmask="~"+myarch |
1084 |
- break |
1085 |
- |
1086 |
- try: |
1087 |
- missing_licenses = settings._getMissingLicenses(mycpv, metadata) |
1088 |
- if missing_licenses: |
1089 |
- allowed_tokens = set(["||", "(", ")"]) |
1090 |
- allowed_tokens.update(missing_licenses) |
1091 |
- license_split = licenses.split() |
1092 |
- license_split = [x for x in license_split \ |
1093 |
- if x in allowed_tokens] |
1094 |
- msg = license_split[:] |
1095 |
- msg.append("license(s)") |
1096 |
- rValue.append(" ".join(msg)) |
1097 |
- except portage.exception.InvalidDependString as e: |
1098 |
- rValue.append("LICENSE: "+str(e)) |
1099 |
- |
1100 |
- try: |
1101 |
- missing_properties = settings._getMissingProperties(mycpv, metadata) |
1102 |
- if missing_properties: |
1103 |
- allowed_tokens = set(["||", "(", ")"]) |
1104 |
- allowed_tokens.update(missing_properties) |
1105 |
- properties_split = properties.split() |
1106 |
- properties_split = [x for x in properties_split \ |
1107 |
- if x in allowed_tokens] |
1108 |
- msg = properties_split[:] |
1109 |
- msg.append("properties") |
1110 |
- rValue.append(" ".join(msg)) |
1111 |
- except portage.exception.InvalidDependString as e: |
1112 |
- rValue.append("PROPERTIES: "+str(e)) |
1113 |
- |
1114 |
- # Only show KEYWORDS masks for installed packages |
1115 |
- # if they're not masked for any other reason. |
1116 |
- if kmask and (not installed or not rValue): |
1117 |
- rValue.append(kmask+" keyword") |
1118 |
- |
1119 |
- return rValue |
1120 |
- |
1121 |
auxdbkeys = ( |
1122 |
'DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI', |
1123 |
'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION', |
1124 |
|
1125 |
Modified: main/branches/prefix/pym/portage/dbapi/__init__.py |
1126 |
=================================================================== |
1127 |
--- main/branches/prefix/pym/portage/dbapi/__init__.py 2010-02-27 19:26:00 UTC (rev 15482) |
1128 |
+++ main/branches/prefix/pym/portage/dbapi/__init__.py 2010-02-27 19:32:48 UTC (rev 15483) |
1129 |
@@ -8,7 +8,7 @@ |
1130 |
|
1131 |
import portage |
1132 |
portage.proxy.lazyimport.lazyimport(globals(), |
1133 |
- 'portage.dbapi.dep_expand:dep_expand', |
1134 |
+ 'portage.dbapi.dep_expand:_dep_expand', |
1135 |
'portage.dep:match_from_list', |
1136 |
'portage.locks:unlockfile', |
1137 |
'portage.output:colorize', |
1138 |
@@ -122,7 +122,7 @@ |
1139 |
Returns: |
1140 |
a list of packages that match origdep |
1141 |
""" |
1142 |
- mydep = dep_expand(origdep, mydb=self, settings=self.settings) |
1143 |
+ mydep = _dep_expand(origdep, mydb=self, settings=self.settings) |
1144 |
return list(self._iter_match(mydep, |
1145 |
self.cp_list(mydep.cp, use_cache=use_cache))) |
1146 |
|
1147 |
|
1148 |
Modified: main/branches/prefix/pym/portage/dbapi/vartree.py |
1149 |
=================================================================== |
1150 |
--- main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 19:26:00 UTC (rev 15482) |
1151 |
+++ main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 19:32:48 UTC (rev 15483) |
1152 |
@@ -40,8 +40,9 @@ |
1153 |
InvalidData, InvalidPackageName, \ |
1154 |
FileNotFound, PermissionDenied, UnsupportedAPIException |
1155 |
from portage.localization import _ |
1156 |
+from portage.util.movefile import movefile |
1157 |
|
1158 |
-from portage import abssymlink, movefile, _movefile, bsd_chflags |
1159 |
+from portage import abssymlink, _movefile, bsd_chflags |
1160 |
|
1161 |
# This is a special version of the os module, wrapped for unicode support. |
1162 |
from portage import os |
1163 |
|
1164 |
Deleted: main/branches/prefix/pym/portage/dep.py |
1165 |
=================================================================== |
1166 |
--- main/branches/prefix/pym/portage/dep.py 2010-02-27 19:26:00 UTC (rev 15482) |
1167 |
+++ main/branches/prefix/pym/portage/dep.py 2010-02-27 19:32:48 UTC (rev 15483) |
1168 |
@@ -1,1203 +0,0 @@ |
1169 |
-# deps.py -- Portage dependency resolution functions |
1170 |
-# Copyright 2003-2004 Gentoo Foundation |
1171 |
-# Distributed under the terms of the GNU General Public License v2 |
1172 |
-# $Id$ |
1173 |
- |
1174 |
-__all__ = [ |
1175 |
- 'Atom', 'best_match_to_list', 'cpvequal', |
1176 |
- 'dep_getcpv', 'dep_getkey', 'dep_getslot', |
1177 |
- 'dep_getusedeps', 'dep_opconvert', 'flatten', |
1178 |
- 'get_operator', 'isjustname', 'isspecific', |
1179 |
- 'isvalidatom', 'match_from_list', 'match_to_list', |
1180 |
- 'paren_enclose', 'paren_normalize', 'paren_reduce', |
1181 |
- 'remove_slot', 'strip_empty', 'use_reduce' |
1182 |
-] |
1183 |
- |
1184 |
-# DEPEND SYNTAX: |
1185 |
-# |
1186 |
-# 'use?' only affects the immediately following word! |
1187 |
-# Nesting is the only legal way to form multiple '[!]use?' requirements. |
1188 |
-# |
1189 |
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom. |
1190 |
-# |
1191 |
-# "a? z" -- If 'a' in [use], then b is valid. |
1192 |
-# "a? ( z )" -- Syntax with parenthesis. |
1193 |
-# "a? b? z" -- Deprecated. |
1194 |
-# "a? ( b? z )" -- Valid |
1195 |
-# "a? ( b? ( z ) ) -- Valid |
1196 |
-# |
1197 |
- |
1198 |
-import re, sys |
1199 |
-import warnings |
1200 |
-from itertools import chain |
1201 |
-import portage.exception |
1202 |
-from portage.exception import InvalidData, InvalidAtom |
1203 |
-from portage.localization import _ |
1204 |
-from portage.versions import catpkgsplit, catsplit, \ |
1205 |
- pkgcmp, pkgsplit, ververify, _cp, _cpv |
1206 |
-import portage.cache.mappings |
1207 |
- |
1208 |
-if sys.hexversion >= 0x3000000: |
1209 |
- basestring = str |
1210 |
- |
1211 |
-def cpvequal(cpv1, cpv2): |
1212 |
- """ |
1213 |
- |
1214 |
- @param cpv1: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
1215 |
- @type cpv1: String |
1216 |
- @param cpv2: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1" |
1217 |
- @type cpv2: String |
1218 |
- @rtype: Boolean |
1219 |
- @returns: |
1220 |
- 1. True if cpv1 = cpv2 |
1221 |
- 2. False Otherwise |
1222 |
- 3. Throws PortageException if cpv1 or cpv2 is not a CPV |
1223 |
- |
1224 |
- Example Usage: |
1225 |
- >>> from portage.dep import cpvequal |
1226 |
- >>> cpvequal("sys-apps/portage-2.1","sys-apps/portage-2.1") |
1227 |
- >>> True |
1228 |
- |
1229 |
- """ |
1230 |
- |
1231 |
- split1 = catpkgsplit(cpv1) |
1232 |
- split2 = catpkgsplit(cpv2) |
1233 |
- |
1234 |
- if not split1 or not split2: |
1235 |
- raise portage.exception.PortageException(_("Invalid data '%s, %s', parameter was not a CPV") % (cpv1, cpv2)) |
1236 |
- |
1237 |
- if split1[0] != split2[0]: |
1238 |
- return False |
1239 |
- |
1240 |
- return (pkgcmp(split1[1:], split2[1:]) == 0) |
1241 |
- |
1242 |
-def strip_empty(myarr): |
1243 |
- """ |
1244 |
- Strip all empty elements from an array |
1245 |
- |
1246 |
- @param myarr: The list of elements |
1247 |
- @type myarr: List |
1248 |
- @rtype: Array |
1249 |
- @return: The array with empty elements removed |
1250 |
- """ |
1251 |
- return [x for x in myarr if x] |
1252 |
- |
1253 |
-_paren_whitespace_re = re.compile(r'\S(\(|\))|(\(|\))\S') |
1254 |
- |
1255 |
-def paren_reduce(mystr,tokenize=1): |
1256 |
- """ |
1257 |
- Take a string and convert all paren enclosed entities into sublists, optionally |
1258 |
- futher splitting the list elements by spaces. |
1259 |
- |
1260 |
- Example usage: |
1261 |
- >>> paren_reduce('foobar foo ( bar baz )',1) |
1262 |
- ['foobar', 'foo', ['bar', 'baz']] |
1263 |
- >>> paren_reduce('foobar foo ( bar baz )',0) |
1264 |
- ['foobar foo ', [' bar baz ']] |
1265 |
- |
1266 |
- @param mystr: The string to reduce |
1267 |
- @type mystr: String |
1268 |
- @param tokenize: Split on spaces to produces further list breakdown |
1269 |
- @type tokenize: Integer |
1270 |
- @rtype: Array |
1271 |
- @return: The reduced string in an array |
1272 |
- """ |
1273 |
- global _dep_check_strict, _paren_whitespace_re |
1274 |
- if _dep_check_strict: |
1275 |
- m = _paren_whitespace_re.search(mystr) |
1276 |
- if m is not None: |
1277 |
- raise portage.exception.InvalidDependString( |
1278 |
- _("missing space by parenthesis: '%s'") % m.group(0)) |
1279 |
- mylist = [] |
1280 |
- while mystr: |
1281 |
- left_paren = mystr.find("(") |
1282 |
- has_left_paren = left_paren != -1 |
1283 |
- right_paren = mystr.find(")") |
1284 |
- has_right_paren = right_paren != -1 |
1285 |
- if not has_left_paren and not has_right_paren: |
1286 |
- freesec = mystr |
1287 |
- subsec = None |
1288 |
- tail = "" |
1289 |
- elif mystr[0] == ")": |
1290 |
- return [mylist,mystr[1:]] |
1291 |
- elif has_left_paren and not has_right_paren: |
1292 |
- raise portage.exception.InvalidDependString( |
1293 |
- _("missing right parenthesis: '%s'") % mystr) |
1294 |
- elif has_left_paren and left_paren < right_paren: |
1295 |
- freesec,subsec = mystr.split("(",1) |
1296 |
- sublist = paren_reduce(subsec, tokenize=tokenize) |
1297 |
- if len(sublist) != 2: |
1298 |
- raise portage.exception.InvalidDependString( |
1299 |
- _("malformed syntax: '%s'") % mystr) |
1300 |
- subsec, tail = sublist |
1301 |
- else: |
1302 |
- subsec,tail = mystr.split(")",1) |
1303 |
- if tokenize: |
1304 |
- subsec = strip_empty(subsec.split(" ")) |
1305 |
- return [mylist+subsec,tail] |
1306 |
- return mylist+[subsec],tail |
1307 |
- if not isinstance(tail, basestring): |
1308 |
- raise portage.exception.InvalidDependString( |
1309 |
- _("malformed syntax: '%s'") % mystr) |
1310 |
- mystr = tail |
1311 |
- if freesec: |
1312 |
- if tokenize: |
1313 |
- mylist = mylist + strip_empty(freesec.split(" ")) |
1314 |
- else: |
1315 |
- mylist = mylist + [freesec] |
1316 |
- if subsec is not None: |
1317 |
- mylist = mylist + [subsec] |
1318 |
- return mylist |
1319 |
- |
1320 |
-class paren_normalize(list): |
1321 |
- """Take a dependency structure as returned by paren_reduce or use_reduce |
1322 |
- and generate an equivalent structure that has no redundant lists.""" |
1323 |
- def __init__(self, src): |
1324 |
- list.__init__(self) |
1325 |
- self._zap_parens(src, self) |
1326 |
- |
1327 |
- def _zap_parens(self, src, dest, disjunction=False): |
1328 |
- if not src: |
1329 |
- return dest |
1330 |
- i = iter(src) |
1331 |
- for x in i: |
1332 |
- if isinstance(x, basestring): |
1333 |
- if x == '||': |
1334 |
- x = self._zap_parens(next(i), [], disjunction=True) |
1335 |
- if len(x) == 1: |
1336 |
- dest.append(x[0]) |
1337 |
- else: |
1338 |
- dest.append("||") |
1339 |
- dest.append(x) |
1340 |
- elif x.endswith("?"): |
1341 |
- dest.append(x) |
1342 |
- dest.append(self._zap_parens(next(i), [])) |
1343 |
- else: |
1344 |
- dest.append(x) |
1345 |
- else: |
1346 |
- if disjunction: |
1347 |
- x = self._zap_parens(x, []) |
1348 |
- if len(x) == 1: |
1349 |
- dest.append(x[0]) |
1350 |
- else: |
1351 |
- dest.append(x) |
1352 |
- else: |
1353 |
- self._zap_parens(x, dest) |
1354 |
- return dest |
1355 |
- |
1356 |
-def paren_enclose(mylist): |
1357 |
- """ |
1358 |
- Convert a list to a string with sublists enclosed with parens. |
1359 |
- |
1360 |
- Example usage: |
1361 |
- >>> test = ['foobar','foo',['bar','baz']] |
1362 |
- >>> paren_enclose(test) |
1363 |
- 'foobar foo ( bar baz )' |
1364 |
- |
1365 |
- @param mylist: The list |
1366 |
- @type mylist: List |
1367 |
- @rtype: String |
1368 |
- @return: The paren enclosed string |
1369 |
- """ |
1370 |
- mystrparts = [] |
1371 |
- for x in mylist: |
1372 |
- if isinstance(x, list): |
1373 |
- mystrparts.append("( "+paren_enclose(x)+" )") |
1374 |
- else: |
1375 |
- mystrparts.append(x) |
1376 |
- return " ".join(mystrparts) |
1377 |
- |
1378 |
-# This is just for use by emerge so that it can enable a backward compatibility |
1379 |
-# mode in order to gracefully deal with installed packages that have invalid |
1380 |
-# atoms or dep syntax. For backward compatibility with api consumers, strict |
1381 |
-# behavior will be explicitly enabled as necessary. |
1382 |
-_dep_check_strict = False |
1383 |
- |
1384 |
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]): |
1385 |
- """ |
1386 |
- Takes a paren_reduce'd array and reduces the use? conditionals out |
1387 |
- leaving an array with subarrays |
1388 |
- |
1389 |
- @param deparray: paren_reduce'd list of deps |
1390 |
- @type deparray: List |
1391 |
- @param uselist: List of use flags |
1392 |
- @type uselist: List |
1393 |
- @param masklist: List of masked flags |
1394 |
- @type masklist: List |
1395 |
- @param matchall: Resolve all conditional deps unconditionally. Used by repoman |
1396 |
- @type matchall: Integer |
1397 |
- @rtype: List |
1398 |
- @return: The use reduced depend array |
1399 |
- """ |
1400 |
- # Quick validity checks |
1401 |
- for x, y in enumerate(deparray): |
1402 |
- if y == '||': |
1403 |
- if len(deparray) - 1 == x or not isinstance(deparray[x+1], list): |
1404 |
- raise portage.exception.InvalidDependString(_('%(dep)s missing atom list in "%(deparray)s"') % {"dep": deparray[x], "deparray": paren_enclose(deparray)}) |
1405 |
- if deparray and deparray[-1] and deparray[-1][-1] == "?": |
1406 |
- raise portage.exception.InvalidDependString(_('Conditional without target in "%s"') % paren_enclose(deparray)) |
1407 |
- |
1408 |
- global _dep_check_strict |
1409 |
- |
1410 |
- mydeparray = deparray[:] |
1411 |
- rlist = [] |
1412 |
- while mydeparray: |
1413 |
- head = mydeparray.pop(0) |
1414 |
- |
1415 |
- if not isinstance(head, basestring): |
1416 |
- additions = use_reduce(head, uselist, masklist, matchall, excludeall) |
1417 |
- if additions: |
1418 |
- rlist.append(additions) |
1419 |
- elif rlist and rlist[-1] == "||": |
1420 |
- #XXX: Currently some DEPEND strings have || lists without default atoms. |
1421 |
- # raise portage.exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"") |
1422 |
- rlist.append([]) |
1423 |
- |
1424 |
- else: |
1425 |
- if head[-1:] == "?": # Use reduce next group on fail. |
1426 |
- # Pull any other use conditions and the following atom or list into a separate array |
1427 |
- newdeparray = [head] |
1428 |
- while isinstance(newdeparray[-1], basestring) and \ |
1429 |
- newdeparray[-1][-1:] == "?": |
1430 |
- if mydeparray: |
1431 |
- newdeparray.append(mydeparray.pop(0)) |
1432 |
- else: |
1433 |
- raise ValueError(_("Conditional with no target.")) |
1434 |
- |
1435 |
- # Deprecation checks |
1436 |
- warned = 0 |
1437 |
- if len(newdeparray[-1]) == 0: |
1438 |
- sys.stderr.write(_("Note: Empty target in string. (Deprecated)\n")) |
1439 |
- warned = 1 |
1440 |
- if len(newdeparray) != 2: |
1441 |
- sys.stderr.write(_("Note: Nested use flags without parenthesis (Deprecated)\n")) |
1442 |
- warned = 1 |
1443 |
- if warned: |
1444 |
- sys.stderr.write(" --> "+" ".join(map(str,[head]+newdeparray))+"\n") |
1445 |
- |
1446 |
- # Check that each flag matches |
1447 |
- ismatch = True |
1448 |
- missing_flag = False |
1449 |
- for head in newdeparray[:-1]: |
1450 |
- head = head[:-1] |
1451 |
- if not head: |
1452 |
- missing_flag = True |
1453 |
- break |
1454 |
- if head.startswith("!"): |
1455 |
- head_key = head[1:] |
1456 |
- if not head_key: |
1457 |
- missing_flag = True |
1458 |
- break |
1459 |
- if not matchall and head_key in uselist or \ |
1460 |
- head_key in excludeall: |
1461 |
- ismatch = False |
1462 |
- break |
1463 |
- elif head not in masklist: |
1464 |
- if not matchall and head not in uselist: |
1465 |
- ismatch = False |
1466 |
- break |
1467 |
- else: |
1468 |
- ismatch = False |
1469 |
- if missing_flag: |
1470 |
- raise portage.exception.InvalidDependString( |
1471 |
- _('Conditional without flag: "') + \ |
1472 |
- paren_enclose([head+"?", newdeparray[-1]])+"\"") |
1473 |
- |
1474 |
- # If they all match, process the target |
1475 |
- if ismatch: |
1476 |
- target = newdeparray[-1] |
1477 |
- if isinstance(target, list): |
1478 |
- additions = use_reduce(target, uselist, masklist, matchall, excludeall) |
1479 |
- if additions: |
1480 |
- rlist.append(additions) |
1481 |
- elif not _dep_check_strict: |
1482 |
- # The old deprecated behavior. |
1483 |
- rlist.append(target) |
1484 |
- else: |
1485 |
- raise portage.exception.InvalidDependString( |
1486 |
- _("Conditional without parenthesis: '%s?'") % head) |
1487 |
- |
1488 |
- else: |
1489 |
- rlist += [head] |
1490 |
- |
1491 |
- return rlist |
1492 |
- |
1493 |
-def dep_opconvert(deplist): |
1494 |
- """ |
1495 |
- Iterate recursively through a list of deps, if the |
1496 |
- dep is a '||' or '&&' operator, combine it with the |
1497 |
- list of deps that follows.. |
1498 |
- |
1499 |
- Example usage: |
1500 |
- >>> test = ["blah", "||", ["foo", "bar", "baz"]] |
1501 |
- >>> dep_opconvert(test) |
1502 |
- ['blah', ['||', 'foo', 'bar', 'baz']] |
1503 |
- |
1504 |
- @param deplist: A list of deps to format |
1505 |
- @type mydep: List |
1506 |
- @rtype: List |
1507 |
- @return: |
1508 |
- The new list with the new ordering |
1509 |
- """ |
1510 |
- |
1511 |
- retlist = [] |
1512 |
- x = 0 |
1513 |
- while x != len(deplist): |
1514 |
- if isinstance(deplist[x], list): |
1515 |
- retlist.append(dep_opconvert(deplist[x])) |
1516 |
- elif deplist[x] == "||" or deplist[x] == "&&": |
1517 |
- retlist.append([deplist[x]] + dep_opconvert(deplist[x+1])) |
1518 |
- x += 1 |
1519 |
- else: |
1520 |
- retlist.append(deplist[x]) |
1521 |
- x += 1 |
1522 |
- return retlist |
1523 |
- |
1524 |
-def flatten(mylist): |
1525 |
- """ |
1526 |
- Recursively traverse nested lists and return a single list containing |
1527 |
- all non-list elements that are found. |
1528 |
- |
1529 |
- Example usage: |
1530 |
- >>> flatten([1, [2, 3, [4]]]) |
1531 |
- [1, 2, 3, 4] |
1532 |
- |
1533 |
- @param mylist: A list containing nested lists and non-list elements. |
1534 |
- @type mylist: List |
1535 |
- @rtype: List |
1536 |
- @return: A single list containing only non-list elements. |
1537 |
- """ |
1538 |
- newlist = [] |
1539 |
- for x in mylist: |
1540 |
- if isinstance(x, list): |
1541 |
- newlist.extend(flatten(x)) |
1542 |
- else: |
1543 |
- newlist.append(x) |
1544 |
- return newlist |
1545 |
- |
1546 |
-class _use_dep(object): |
1547 |
- |
1548 |
- __slots__ = ("__weakref__", "conditional", |
1549 |
- "disabled", "enabled", "tokens", "required") |
1550 |
- |
1551 |
- _conditionals_class = portage.cache.mappings.slot_dict_class( |
1552 |
- ("disabled", "enabled", "equal", "not_equal"), prefix="") |
1553 |
- |
1554 |
- _valid_use_re = re.compile(r'^[^-?!=][^?!=]*$') |
1555 |
- |
1556 |
- def __init__(self, use): |
1557 |
- enabled_flags = [] |
1558 |
- disabled_flags = [] |
1559 |
- conditional = self._conditionals_class() |
1560 |
- for k in conditional.allowed_keys: |
1561 |
- conditional[k] = [] |
1562 |
- |
1563 |
- for x in use: |
1564 |
- last_char = x[-1:] |
1565 |
- first_char = x[:1] |
1566 |
- |
1567 |
- if "?" == last_char: |
1568 |
- if "!" == first_char: |
1569 |
- conditional.disabled.append( |
1570 |
- self._validate_flag(x, x[1:-1])) |
1571 |
- else: |
1572 |
- conditional.enabled.append( |
1573 |
- self._validate_flag(x, x[:-1])) |
1574 |
- |
1575 |
- elif "=" == last_char: |
1576 |
- if "!" == first_char: |
1577 |
- conditional.not_equal.append( |
1578 |
- self._validate_flag(x, x[1:-1])) |
1579 |
- else: |
1580 |
- conditional.equal.append( |
1581 |
- self._validate_flag(x, x[:-1])) |
1582 |
- |
1583 |
- else: |
1584 |
- if "-" == first_char: |
1585 |
- disabled_flags.append(self._validate_flag(x, x[1:])) |
1586 |
- else: |
1587 |
- enabled_flags.append(self._validate_flag(x, x)) |
1588 |
- |
1589 |
- self.tokens = use |
1590 |
- if not isinstance(self.tokens, tuple): |
1591 |
- self.tokens = tuple(self.tokens) |
1592 |
- |
1593 |
- self.required = frozenset(chain( |
1594 |
- enabled_flags, |
1595 |
- disabled_flags, |
1596 |
- *conditional.values() |
1597 |
- )) |
1598 |
- |
1599 |
- self.enabled = frozenset(enabled_flags) |
1600 |
- self.disabled = frozenset(disabled_flags) |
1601 |
- self.conditional = None |
1602 |
- |
1603 |
- for v in conditional.values(): |
1604 |
- if v: |
1605 |
- for k, v in conditional.items(): |
1606 |
- conditional[k] = frozenset(v) |
1607 |
- self.conditional = conditional |
1608 |
- break |
1609 |
- |
1610 |
- def _validate_flag(self, token, flag): |
1611 |
- if self._valid_use_re.match(flag) is None: |
1612 |
- raise InvalidAtom(_("Invalid use dep: '%s'") % (token,)) |
1613 |
- return flag |
1614 |
- |
1615 |
- def __bool__(self): |
1616 |
- return bool(self.tokens) |
1617 |
- |
1618 |
- if sys.hexversion < 0x3000000: |
1619 |
- __nonzero__ = __bool__ |
1620 |
- |
1621 |
- def __str__(self): |
1622 |
- if not self.tokens: |
1623 |
- return "" |
1624 |
- return "[%s]" % (",".join(self.tokens),) |
1625 |
- |
1626 |
- def __repr__(self): |
1627 |
- return "portage.dep._use_dep(%s)" % repr(self.tokens) |
1628 |
- |
1629 |
- def evaluate_conditionals(self, use): |
1630 |
- """ |
1631 |
- Create a new instance with conditionals evaluated. |
1632 |
- |
1633 |
- Conditional evaluation behavior: |
1634 |
- |
1635 |
- parent state conditional result |
1636 |
- |
1637 |
- x x? x |
1638 |
- -x x? |
1639 |
- x !x? |
1640 |
- -x !x? -x |
1641 |
- |
1642 |
- x x= x |
1643 |
- -x x= -x |
1644 |
- x !x= -x |
1645 |
- -x !x= x |
1646 |
- |
1647 |
- Conditional syntax examples: |
1648 |
- |
1649 |
- Compact Form Equivalent Expanded Form |
1650 |
- |
1651 |
- foo[bar?] bar? ( foo[bar] ) !bar? ( foo ) |
1652 |
- foo[!bar?] bar? ( foo ) !bar? ( foo[-bar] ) |
1653 |
- foo[bar=] bar? ( foo[bar] ) !bar? ( foo[-bar] ) |
1654 |
- foo[!bar=] bar? ( foo[-bar] ) !bar? ( foo[bar] ) |
1655 |
- |
1656 |
- """ |
1657 |
- tokens = [] |
1658 |
- |
1659 |
- conditional = self.conditional |
1660 |
- tokens.extend(self.enabled) |
1661 |
- tokens.extend("-" + x for x in self.disabled) |
1662 |
- tokens.extend(x for x in conditional.enabled if x in use) |
1663 |
- tokens.extend("-" + x for x in conditional.disabled if x not in use) |
1664 |
- |
1665 |
- tokens.extend(x for x in conditional.equal if x in use) |
1666 |
- tokens.extend("-" + x for x in conditional.equal if x not in use) |
1667 |
- tokens.extend("-" + x for x in conditional.not_equal if x in use) |
1668 |
- tokens.extend(x for x in conditional.not_equal if x not in use) |
1669 |
- |
1670 |
- return _use_dep(tokens) |
1671 |
- |
1672 |
- def _eval_qa_conditionals(self, use_mask, use_force): |
1673 |
- """ |
1674 |
- For repoman, evaluate all possible combinations within the constraints |
1675 |
- of the given use.force and use.mask settings. The result may seem |
1676 |
- ambiguous in the sense that the same flag can be in both the enabled |
1677 |
- and disabled sets, but this is useful within the context of how its |
1678 |
- intended to be used by repoman. It is assumed that the caller has |
1679 |
- already ensured that there is no intersection between the given |
1680 |
- use_mask and use_force sets when necessary. |
1681 |
- """ |
1682 |
- tokens = [] |
1683 |
- |
1684 |
- conditional = self.conditional |
1685 |
- tokens.extend(self.enabled) |
1686 |
- tokens.extend("-" + x for x in self.disabled) |
1687 |
- tokens.extend(x for x in conditional.enabled if x not in use_mask) |
1688 |
- tokens.extend("-" + x for x in conditional.disabled if x not in use_force) |
1689 |
- |
1690 |
- tokens.extend(x for x in conditional.equal if x not in use_mask) |
1691 |
- tokens.extend("-" + x for x in conditional.equal if x not in use_force) |
1692 |
- tokens.extend("-" + x for x in conditional.not_equal if x not in use_mask) |
1693 |
- tokens.extend(x for x in conditional.not_equal if x not in use_force) |
1694 |
- |
1695 |
- return _use_dep(tokens) |
1696 |
- |
1697 |
-if sys.hexversion < 0x3000000: |
1698 |
- _atom_base = unicode |
1699 |
-else: |
1700 |
- _atom_base = str |
1701 |
- |
1702 |
-class Atom(_atom_base): |
1703 |
- |
1704 |
- """ |
1705 |
- For compatibility with existing atom string manipulation code, this |
1706 |
- class emulates most of the str methods that are useful with atoms. |
1707 |
- """ |
1708 |
- |
1709 |
- class _blocker(object): |
1710 |
- __slots__ = ("overlap",) |
1711 |
- |
1712 |
- class _overlap(object): |
1713 |
- __slots__ = ("forbid",) |
1714 |
- |
1715 |
- def __init__(self, forbid=False): |
1716 |
- self.forbid = forbid |
1717 |
- |
1718 |
- def __init__(self, forbid_overlap=False): |
1719 |
- self.overlap = self._overlap(forbid=forbid_overlap) |
1720 |
- |
1721 |
- def __init__(self, s): |
1722 |
- if isinstance(s, Atom): |
1723 |
- # This is an efficiency assertion, to ensure that the Atom |
1724 |
- # constructor is not called redundantly. |
1725 |
- raise TypeError(_("Expected %s, got %s") % \ |
1726 |
- (_atom_base, type(s))) |
1727 |
- |
1728 |
- _atom_base.__init__(s) |
1729 |
- |
1730 |
- if "!" == s[:1]: |
1731 |
- blocker = self._blocker(forbid_overlap=("!" == s[1:2])) |
1732 |
- if blocker.overlap.forbid: |
1733 |
- s = s[2:] |
1734 |
- else: |
1735 |
- s = s[1:] |
1736 |
- else: |
1737 |
- blocker = False |
1738 |
- self.__dict__['blocker'] = blocker |
1739 |
- m = _atom_re.match(s) |
1740 |
- if m is None: |
1741 |
- raise InvalidAtom(self) |
1742 |
- |
1743 |
- if m.group('op') is not None: |
1744 |
- base = _atom_re.groupindex['op'] |
1745 |
- op = m.group(base + 1) |
1746 |
- cpv = m.group(base + 2) |
1747 |
- cp = m.group(base + 3) |
1748 |
- if m.group(base + 4) is not None: |
1749 |
- raise InvalidAtom(self) |
1750 |
- elif m.group('star') is not None: |
1751 |
- base = _atom_re.groupindex['star'] |
1752 |
- op = '=*' |
1753 |
- cpv = m.group(base + 1) |
1754 |
- cp = m.group(base + 2) |
1755 |
- if m.group(base + 3) is not None: |
1756 |
- raise InvalidAtom(self) |
1757 |
- elif m.group('simple') is not None: |
1758 |
- op = None |
1759 |
- cpv = cp = m.group(_atom_re.groupindex['simple'] + 1) |
1760 |
- if m.group(_atom_re.groupindex['simple'] + 2) is not None: |
1761 |
- raise InvalidAtom(self) |
1762 |
- else: |
1763 |
- raise AssertionError(_("required group not found in atom: '%s'") % self) |
1764 |
- self.__dict__['cp'] = cp |
1765 |
- self.__dict__['cpv'] = cpv |
1766 |
- self.__dict__['slot'] = m.group(_atom_re.groups - 1) |
1767 |
- self.__dict__['operator'] = op |
1768 |
- |
1769 |
- use_str = m.group(_atom_re.groups) |
1770 |
- if use_str is not None: |
1771 |
- use = _use_dep(dep_getusedeps(s)) |
1772 |
- without_use = Atom(m.group('without_use')) |
1773 |
- else: |
1774 |
- use = None |
1775 |
- without_use = self |
1776 |
- |
1777 |
- self.__dict__['use'] = use |
1778 |
- self.__dict__['without_use'] = without_use |
1779 |
- |
1780 |
- def __setattr__(self, name, value): |
1781 |
- raise AttributeError("Atom instances are immutable", |
1782 |
- self.__class__, name, value) |
1783 |
- |
1784 |
- def intersects(self, other): |
1785 |
- """ |
1786 |
- Atoms with different cpv, operator or use attributes cause this method |
1787 |
- to return False even though there may actually be some intersection. |
1788 |
- TODO: Detect more forms of intersection. |
1789 |
- @param other: The package atom to match |
1790 |
- @type other: Atom |
1791 |
- @rtype: Boolean |
1792 |
- @return: True if this atom and the other atom intersect, |
1793 |
- False otherwise. |
1794 |
- """ |
1795 |
- if not isinstance(other, Atom): |
1796 |
- raise TypeError("expected %s, got %s" % \ |
1797 |
- (Atom, type(other))) |
1798 |
- |
1799 |
- if self == other: |
1800 |
- return True |
1801 |
- |
1802 |
- if self.cp != other.cp or \ |
1803 |
- self.use != other.use or \ |
1804 |
- self.operator != other.operator or \ |
1805 |
- self.cpv != other.cpv: |
1806 |
- return False |
1807 |
- |
1808 |
- if self.slot is None or \ |
1809 |
- other.slot is None or \ |
1810 |
- self.slot == other.slot: |
1811 |
- return True |
1812 |
- |
1813 |
- return False |
1814 |
- |
1815 |
- def evaluate_conditionals(self, use): |
1816 |
- """ |
1817 |
- Create an atom instance with any USE conditionals evaluated. |
1818 |
- @param use: The set of enabled USE flags |
1819 |
- @type use: set |
1820 |
- @rtype: Atom |
1821 |
- @return: an atom instance with any USE conditionals evaluated |
1822 |
- """ |
1823 |
- if not (self.use and self.use.conditional): |
1824 |
- return self |
1825 |
- atom = remove_slot(self) |
1826 |
- if self.slot: |
1827 |
- atom += ":%s" % self.slot |
1828 |
- atom += str(self.use.evaluate_conditionals(use)) |
1829 |
- return Atom(atom) |
1830 |
- |
1831 |
- def __copy__(self): |
1832 |
- """Immutable, so returns self.""" |
1833 |
- return self |
1834 |
- |
1835 |
- def __deepcopy__(self, memo=None): |
1836 |
- """Immutable, so returns self.""" |
1837 |
- memo[id(self)] = self |
1838 |
- return self |
1839 |
- |
1840 |
-def get_operator(mydep): |
1841 |
- """ |
1842 |
- Return the operator used in a depstring. |
1843 |
- |
1844 |
- Example usage: |
1845 |
- >>> from portage.dep import * |
1846 |
- >>> get_operator(">=test-1.0") |
1847 |
- '>=' |
1848 |
- |
1849 |
- @param mydep: The dep string to check |
1850 |
- @type mydep: String |
1851 |
- @rtype: String |
1852 |
- @return: The operator. One of: |
1853 |
- '~', '=', '>', '<', '=*', '>=', or '<=' |
1854 |
- """ |
1855 |
- if isinstance(mydep, Atom): |
1856 |
- return mydep.operator |
1857 |
- try: |
1858 |
- return Atom(mydep).operator |
1859 |
- except InvalidAtom: |
1860 |
- pass |
1861 |
- |
1862 |
- # Fall back to legacy code for backward compatibility. |
1863 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
1864 |
- ('portage.dep.get_operator()', 'portage.dep.Atom.operator'), |
1865 |
- DeprecationWarning) |
1866 |
- operator = None |
1867 |
- if mydep: |
1868 |
- mydep = remove_slot(mydep) |
1869 |
- if not mydep: |
1870 |
- return None |
1871 |
- if mydep[0] == "~": |
1872 |
- operator = "~" |
1873 |
- elif mydep[0] == "=": |
1874 |
- if mydep[-1] == "*": |
1875 |
- operator = "=*" |
1876 |
- else: |
1877 |
- operator = "=" |
1878 |
- elif mydep[0] in "><": |
1879 |
- if len(mydep) > 1 and mydep[1] == "=": |
1880 |
- operator = mydep[0:2] |
1881 |
- else: |
1882 |
- operator = mydep[0] |
1883 |
- else: |
1884 |
- operator = None |
1885 |
- |
1886 |
- return operator |
1887 |
- |
1888 |
-def dep_getcpv(mydep): |
1889 |
- """ |
1890 |
- Return the category-package-version with any operators/slot specifications stripped off |
1891 |
- |
1892 |
- Example usage: |
1893 |
- >>> dep_getcpv('>=media-libs/test-3.0') |
1894 |
- 'media-libs/test-3.0' |
1895 |
- |
1896 |
- @param mydep: The depstring |
1897 |
- @type mydep: String |
1898 |
- @rtype: String |
1899 |
- @return: The depstring with the operator removed |
1900 |
- """ |
1901 |
- if isinstance(mydep, Atom): |
1902 |
- return mydep.cpv |
1903 |
- try: |
1904 |
- return Atom(mydep).cpv |
1905 |
- except InvalidAtom: |
1906 |
- pass |
1907 |
- |
1908 |
- # Fall back to legacy code for backward compatibility. |
1909 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
1910 |
- ('portage.dep.dep_getcpv()', 'portage.dep.Atom.cpv'), |
1911 |
- DeprecationWarning, stacklevel=2) |
1912 |
- mydep_orig = mydep |
1913 |
- if mydep: |
1914 |
- mydep = remove_slot(mydep) |
1915 |
- if mydep and mydep[0] == "*": |
1916 |
- mydep = mydep[1:] |
1917 |
- if mydep and mydep[-1] == "*": |
1918 |
- mydep = mydep[:-1] |
1919 |
- if mydep and mydep[0] == "!": |
1920 |
- if mydep[1:2] == "!": |
1921 |
- mydep = mydep[2:] |
1922 |
- else: |
1923 |
- mydep = mydep[1:] |
1924 |
- if mydep[:2] in [">=", "<="]: |
1925 |
- mydep = mydep[2:] |
1926 |
- elif mydep[:1] in "=<>~": |
1927 |
- mydep = mydep[1:] |
1928 |
- return mydep |
1929 |
- |
1930 |
-def dep_getslot(mydep): |
1931 |
- """ |
1932 |
- Retrieve the slot on a depend. |
1933 |
- |
1934 |
- Example usage: |
1935 |
- >>> dep_getslot('app-misc/test:3') |
1936 |
- '3' |
1937 |
- |
1938 |
- @param mydep: The depstring to retrieve the slot of |
1939 |
- @type mydep: String |
1940 |
- @rtype: String |
1941 |
- @return: The slot |
1942 |
- """ |
1943 |
- slot = getattr(mydep, "slot", False) |
1944 |
- if slot is not False: |
1945 |
- return slot |
1946 |
- colon = mydep.find(":") |
1947 |
- if colon != -1: |
1948 |
- bracket = mydep.find("[", colon) |
1949 |
- if bracket == -1: |
1950 |
- return mydep[colon+1:] |
1951 |
- else: |
1952 |
- return mydep[colon+1:bracket] |
1953 |
- return None |
1954 |
- |
1955 |
-def remove_slot(mydep): |
1956 |
- """ |
1957 |
- Removes dep components from the right side of an atom: |
1958 |
- * slot |
1959 |
- * use |
1960 |
- * repo |
1961 |
- """ |
1962 |
- colon = mydep.find(":") |
1963 |
- if colon != -1: |
1964 |
- mydep = mydep[:colon] |
1965 |
- else: |
1966 |
- bracket = mydep.find("[") |
1967 |
- if bracket != -1: |
1968 |
- mydep = mydep[:bracket] |
1969 |
- return mydep |
1970 |
- |
1971 |
-def dep_getusedeps( depend ): |
1972 |
- """ |
1973 |
- Pull a listing of USE Dependencies out of a dep atom. |
1974 |
- |
1975 |
- Example usage: |
1976 |
- >>> dep_getusedeps('app-misc/test:3[foo,-bar]') |
1977 |
- ('foo', '-bar') |
1978 |
- |
1979 |
- @param depend: The depstring to process |
1980 |
- @type depend: String |
1981 |
- @rtype: List |
1982 |
- @return: List of use flags ( or [] if no flags exist ) |
1983 |
- """ |
1984 |
- use_list = [] |
1985 |
- open_bracket = depend.find('[') |
1986 |
- # -1 = failure (think c++ string::npos) |
1987 |
- comma_separated = False |
1988 |
- bracket_count = 0 |
1989 |
- while( open_bracket != -1 ): |
1990 |
- bracket_count += 1 |
1991 |
- if bracket_count > 1: |
1992 |
- raise InvalidAtom(_("USE Dependency with more " |
1993 |
- "than one set of brackets: %s") % (depend,)) |
1994 |
- close_bracket = depend.find(']', open_bracket ) |
1995 |
- if close_bracket == -1: |
1996 |
- raise InvalidAtom(_("USE Dependency with no closing bracket: %s") % depend ) |
1997 |
- use = depend[open_bracket + 1: close_bracket] |
1998 |
- # foo[1:1] may return '' instead of None, we don't want '' in the result |
1999 |
- if not use: |
2000 |
- raise InvalidAtom(_("USE Dependency with " |
2001 |
- "no use flag ([]): %s") % depend ) |
2002 |
- if not comma_separated: |
2003 |
- comma_separated = "," in use |
2004 |
- |
2005 |
- if comma_separated and bracket_count > 1: |
2006 |
- raise InvalidAtom(_("USE Dependency contains a mixture of " |
2007 |
- "comma and bracket separators: %s") % depend ) |
2008 |
- |
2009 |
- if comma_separated: |
2010 |
- for x in use.split(","): |
2011 |
- if x: |
2012 |
- use_list.append(x) |
2013 |
- else: |
2014 |
- raise InvalidAtom(_("USE Dependency with no use " |
2015 |
- "flag next to comma: %s") % depend ) |
2016 |
- else: |
2017 |
- use_list.append(use) |
2018 |
- |
2019 |
- # Find next use flag |
2020 |
- open_bracket = depend.find( '[', open_bracket+1 ) |
2021 |
- return tuple(use_list) |
2022 |
- |
2023 |
-# \w is [a-zA-Z0-9_] |
2024 |
- |
2025 |
-# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-]. |
2026 |
-# It must not begin with a hyphen or a dot. |
2027 |
-_slot = r'([\w+][\w+.-]*)' |
2028 |
-_slot_re = re.compile('^' + _slot + '$', re.VERBOSE) |
2029 |
- |
2030 |
-_use = r'\[.*\]' |
2031 |
-_op = r'([=~]|[><]=?)' |
2032 |
- |
2033 |
-_atom_re = re.compile('^(?P<without_use>(?:' + |
2034 |
- '(?P<op>' + _op + _cpv + ')|' + |
2035 |
- '(?P<star>=' + _cpv + r'\*)|' + |
2036 |
- '(?P<simple>' + _cp + '))(:' + _slot + ')?)(' + _use + ')?$', re.VERBOSE) |
2037 |
- |
2038 |
-def isvalidatom(atom, allow_blockers=False): |
2039 |
- """ |
2040 |
- Check to see if a depend atom is valid |
2041 |
- |
2042 |
- Example usage: |
2043 |
- >>> isvalidatom('media-libs/test-3.0') |
2044 |
- False |
2045 |
- >>> isvalidatom('>=media-libs/test-3.0') |
2046 |
- True |
2047 |
- |
2048 |
- @param atom: The depend atom to check against |
2049 |
- @type atom: String or Atom |
2050 |
- @rtype: Boolean |
2051 |
- @return: One of the following: |
2052 |
- 1) False if the atom is invalid |
2053 |
- 2) True if the atom is valid |
2054 |
- """ |
2055 |
- try: |
2056 |
- if not isinstance(atom, Atom): |
2057 |
- atom = Atom(atom) |
2058 |
- if not allow_blockers and atom.blocker: |
2059 |
- return False |
2060 |
- return True |
2061 |
- except InvalidAtom: |
2062 |
- return False |
2063 |
- |
2064 |
-def isjustname(mypkg): |
2065 |
- """ |
2066 |
- Checks to see if the atom is only the package name (no version parts). |
2067 |
- |
2068 |
- Example usage: |
2069 |
- >>> isjustname('=media-libs/test-3.0') |
2070 |
- False |
2071 |
- >>> isjustname('media-libs/test') |
2072 |
- True |
2073 |
- |
2074 |
- @param mypkg: The package atom to check |
2075 |
- @param mypkg: String or Atom |
2076 |
- @rtype: Integer |
2077 |
- @return: One of the following: |
2078 |
- 1) False if the package string is not just the package name |
2079 |
- 2) True if it is |
2080 |
- """ |
2081 |
- try: |
2082 |
- if not isinstance(mypkg, Atom): |
2083 |
- mypkg = Atom(mypkg) |
2084 |
- return mypkg == mypkg.cp |
2085 |
- except InvalidAtom: |
2086 |
- pass |
2087 |
- |
2088 |
- for x in mypkg.split('-')[-2:]: |
2089 |
- if ververify(x): |
2090 |
- return False |
2091 |
- return True |
2092 |
- |
2093 |
-def isspecific(mypkg): |
2094 |
- """ |
2095 |
- Checks to see if a package is in =category/package-version or |
2096 |
- package-version format. |
2097 |
- |
2098 |
- Example usage: |
2099 |
- >>> isspecific('media-libs/test') |
2100 |
- False |
2101 |
- >>> isspecific('=media-libs/test-3.0') |
2102 |
- True |
2103 |
- |
2104 |
- @param mypkg: The package depstring to check against |
2105 |
- @type mypkg: String |
2106 |
- @rtype: Boolean |
2107 |
- @return: One of the following: |
2108 |
- 1) False if the package string is not specific |
2109 |
- 2) True if it is |
2110 |
- """ |
2111 |
- try: |
2112 |
- if not isinstance(mypkg, Atom): |
2113 |
- mypkg = Atom(mypkg) |
2114 |
- return mypkg != mypkg.cp |
2115 |
- except InvalidAtom: |
2116 |
- pass |
2117 |
- |
2118 |
- # Fall back to legacy code for backward compatibility. |
2119 |
- return not isjustname(mypkg) |
2120 |
- |
2121 |
-def dep_getkey(mydep): |
2122 |
- """ |
2123 |
- Return the category/package-name of a depstring. |
2124 |
- |
2125 |
- Example usage: |
2126 |
- >>> dep_getkey('=media-libs/test-3.0') |
2127 |
- 'media-libs/test' |
2128 |
- |
2129 |
- @param mydep: The depstring to retrieve the category/package-name of |
2130 |
- @type mydep: String |
2131 |
- @rtype: String |
2132 |
- @return: The package category/package-name |
2133 |
- """ |
2134 |
- if isinstance(mydep, Atom): |
2135 |
- return mydep.cp |
2136 |
- try: |
2137 |
- return Atom(mydep).cp |
2138 |
- except InvalidAtom: |
2139 |
- try: |
2140 |
- atom = Atom('=' + mydep) |
2141 |
- except InvalidAtom: |
2142 |
- pass |
2143 |
- else: |
2144 |
- warnings.warn(_("invalid input to %s: '%s', use %s instead") % \ |
2145 |
- ('portage.dep.dep_getkey()', mydep, 'portage.cpv_getkey()'), |
2146 |
- DeprecationWarning, stacklevel=2) |
2147 |
- return atom.cp |
2148 |
- |
2149 |
- # Fall back to legacy code for backward compatibility. |
2150 |
- warnings.warn(_("%s is deprecated, use %s instead") % \ |
2151 |
- ('portage.dep.dep_getkey()', 'portage.dep.Atom.cp'), |
2152 |
- DeprecationWarning, stacklevel=2) |
2153 |
- mydep = dep_getcpv(mydep) |
2154 |
- if mydep and isspecific(mydep): |
2155 |
- mysplit = catpkgsplit(mydep) |
2156 |
- if not mysplit: |
2157 |
- return mydep |
2158 |
- return mysplit[0] + "/" + mysplit[1] |
2159 |
- else: |
2160 |
- return mydep |
2161 |
- |
2162 |
-def match_to_list(mypkg, mylist): |
2163 |
- """ |
2164 |
- Searches list for entries that matches the package. |
2165 |
- |
2166 |
- @param mypkg: The package atom to match |
2167 |
- @type mypkg: String |
2168 |
- @param mylist: The list of package atoms to compare against |
2169 |
- @param mylist: List |
2170 |
- @rtype: List |
2171 |
- @return: A unique list of package atoms that match the given package atom |
2172 |
- """ |
2173 |
- return [ x for x in set(mylist) if match_from_list(x, [mypkg]) ] |
2174 |
- |
2175 |
-def best_match_to_list(mypkg, mylist): |
2176 |
- """ |
2177 |
- Returns the most specific entry that matches the package given. |
2178 |
- |
2179 |
- @param mypkg: The package atom to check |
2180 |
- @type mypkg: String |
2181 |
- @param mylist: The list of package atoms to check against |
2182 |
- @type mylist: List |
2183 |
- @rtype: String |
2184 |
- @return: The package atom which best matches given the following ordering: |
2185 |
- - =cpv 6 |
2186 |
- - ~cpv 5 |
2187 |
- - =cpv* 4 |
2188 |
- - cp:slot 3 |
2189 |
- - >cpv 2 |
2190 |
- - <cpv 2 |
2191 |
- - >=cpv 2 |
2192 |
- - <=cpv 2 |
2193 |
- - cp 1 |
2194 |
- """ |
2195 |
- operator_values = {'=':6, '~':5, '=*':4, |
2196 |
- '>':2, '<':2, '>=':2, '<=':2, None:1} |
2197 |
- maxvalue = 0 |
2198 |
- bestm = None |
2199 |
- for x in match_to_list(mypkg, mylist): |
2200 |
- if dep_getslot(x) is not None: |
2201 |
- if maxvalue < 3: |
2202 |
- maxvalue = 3 |
2203 |
- bestm = x |
2204 |
- op_val = operator_values[x.operator] |
2205 |
- if op_val > maxvalue: |
2206 |
- maxvalue = op_val |
2207 |
- bestm = x |
2208 |
- return bestm |
2209 |
- |
2210 |
-def match_from_list(mydep, candidate_list): |
2211 |
- """ |
2212 |
- Searches list for entries that matches the package. |
2213 |
- |
2214 |
- @param mydep: The package atom to match |
2215 |
- @type mydep: String |
2216 |
- @param candidate_list: The list of package atoms to compare against |
2217 |
- @param candidate_list: List |
2218 |
- @rtype: List |
2219 |
- @return: A list of package atoms that match the given package atom |
2220 |
- """ |
2221 |
- |
2222 |
- if not candidate_list: |
2223 |
- return [] |
2224 |
- |
2225 |
- from portage.util import writemsg |
2226 |
- if "!" == mydep[:1]: |
2227 |
- mydep = mydep[1:] |
2228 |
- if not isinstance(mydep, Atom): |
2229 |
- mydep = Atom(mydep) |
2230 |
- |
2231 |
- mycpv = mydep.cpv |
2232 |
- mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific |
2233 |
- slot = mydep.slot |
2234 |
- |
2235 |
- if not mycpv_cps: |
2236 |
- cat, pkg = catsplit(mycpv) |
2237 |
- ver = None |
2238 |
- rev = None |
2239 |
- else: |
2240 |
- cat, pkg, ver, rev = mycpv_cps |
2241 |
- if mydep == mycpv: |
2242 |
- raise KeyError(_("Specific key requires an operator" |
2243 |
- " (%s) (try adding an '=')") % (mydep)) |
2244 |
- |
2245 |
- if ver and rev: |
2246 |
- operator = mydep.operator |
2247 |
- if not operator: |
2248 |
- writemsg(_("!!! Invalid atom: %s\n") % mydep, noiselevel=-1) |
2249 |
- return [] |
2250 |
- else: |
2251 |
- operator = None |
2252 |
- |
2253 |
- mylist = [] |
2254 |
- |
2255 |
- if operator is None: |
2256 |
- for x in candidate_list: |
2257 |
- cp = getattr(x, "cp", None) |
2258 |
- if cp is None: |
2259 |
- mysplit = catpkgsplit(remove_slot(x)) |
2260 |
- if mysplit is not None: |
2261 |
- cp = mysplit[0] + '/' + mysplit[1] |
2262 |
- if cp != mycpv: |
2263 |
- continue |
2264 |
- mylist.append(x) |
2265 |
- |
2266 |
- elif operator == "=": # Exact match |
2267 |
- for x in candidate_list: |
2268 |
- xcpv = getattr(x, "cpv", None) |
2269 |
- if xcpv is None: |
2270 |
- xcpv = remove_slot(x) |
2271 |
- if not cpvequal(xcpv, mycpv): |
2272 |
- continue |
2273 |
- mylist.append(x) |
2274 |
- |
2275 |
- elif operator == "=*": # glob match |
2276 |
- # XXX: Nasty special casing for leading zeros |
2277 |
- # Required as =* is a literal prefix match, so can't |
2278 |
- # use vercmp |
2279 |
- mysplit = catpkgsplit(mycpv) |
2280 |
- myver = mysplit[2].lstrip("0") |
2281 |
- if not myver or not myver[0].isdigit(): |
2282 |
- myver = "0"+myver |
2283 |
- mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver |
2284 |
- for x in candidate_list: |
2285 |
- xs = getattr(x, "cpv_split", None) |
2286 |
- if xs is None: |
2287 |
- xs = catpkgsplit(remove_slot(x)) |
2288 |
- myver = xs[2].lstrip("0") |
2289 |
- if not myver or not myver[0].isdigit(): |
2290 |
- myver = "0"+myver |
2291 |
- xcpv = xs[0]+"/"+xs[1]+"-"+myver |
2292 |
- if xcpv.startswith(mycpv): |
2293 |
- mylist.append(x) |
2294 |
- |
2295 |
- elif operator == "~": # version, any revision, match |
2296 |
- for x in candidate_list: |
2297 |
- xs = getattr(x, "cpv_split", None) |
2298 |
- if xs is None: |
2299 |
- xs = catpkgsplit(remove_slot(x)) |
2300 |
- if xs is None: |
2301 |
- raise InvalidData(x) |
2302 |
- if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]): |
2303 |
- continue |
2304 |
- if xs[2] != ver: |
2305 |
- continue |
2306 |
- mylist.append(x) |
2307 |
- |
2308 |
- elif operator in [">", ">=", "<", "<="]: |
2309 |
- mysplit = ["%s/%s" % (cat, pkg), ver, rev] |
2310 |
- for x in candidate_list: |
2311 |
- xs = getattr(x, "cpv_split", None) |
2312 |
- if xs is None: |
2313 |
- xs = catpkgsplit(remove_slot(x)) |
2314 |
- xcat, xpkg, xver, xrev = xs |
2315 |
- xs = ["%s/%s" % (xcat, xpkg), xver, xrev] |
2316 |
- try: |
2317 |
- result = pkgcmp(xs, mysplit) |
2318 |
- except ValueError: # pkgcmp may return ValueError during int() conversion |
2319 |
- writemsg(_("\nInvalid package name: %s\n") % x, noiselevel=-1) |
2320 |
- raise |
2321 |
- if result is None: |
2322 |
- continue |
2323 |
- elif operator == ">": |
2324 |
- if result > 0: |
2325 |
- mylist.append(x) |
2326 |
- elif operator == ">=": |
2327 |
- if result >= 0: |
2328 |
- mylist.append(x) |
2329 |
- elif operator == "<": |
2330 |
- if result < 0: |
2331 |
- mylist.append(x) |
2332 |
- elif operator == "<=": |
2333 |
- if result <= 0: |
2334 |
- mylist.append(x) |
2335 |
- else: |
2336 |
- raise KeyError(_("Unknown operator: %s") % mydep) |
2337 |
- else: |
2338 |
- raise KeyError(_("Unknown operator: %s") % mydep) |
2339 |
- |
2340 |
- if slot is not None: |
2341 |
- candidate_list = mylist |
2342 |
- mylist = [] |
2343 |
- for x in candidate_list: |
2344 |
- xslot = getattr(x, "slot", False) |
2345 |
- if xslot is False: |
2346 |
- xslot = dep_getslot(x) |
2347 |
- if xslot is not None and xslot != slot: |
2348 |
- continue |
2349 |
- mylist.append(x) |
2350 |
- |
2351 |
- if mydep.use: |
2352 |
- candidate_list = mylist |
2353 |
- mylist = [] |
2354 |
- for x in candidate_list: |
2355 |
- use = getattr(x, "use", None) |
2356 |
- if use is not None: |
2357 |
- regex = x.iuse.regex |
2358 |
- missing_iuse = False |
2359 |
- for y in mydep.use.required: |
2360 |
- if regex.match(y) is None: |
2361 |
- missing_iuse = True |
2362 |
- break |
2363 |
- if missing_iuse: |
2364 |
- continue |
2365 |
- if mydep.use.enabled.difference(use.enabled): |
2366 |
- continue |
2367 |
- if mydep.use.disabled.intersection(use.enabled): |
2368 |
- continue |
2369 |
- mylist.append(x) |
2370 |
- |
2371 |
- return mylist |
2372 |
|
2373 |
Copied: main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py (from rev 15465, main/trunk/pym/portage/package/ebuild/getmaskingreason.py) |
2374 |
=================================================================== |
2375 |
--- main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py (rev 0) |
2376 |
+++ main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py 2010-02-27 19:32:48 UTC (rev 15483) |
2377 |
@@ -0,0 +1,78 @@ |
2378 |
+# Copyright 2010 Gentoo Foundation |
2379 |
+# Distributed under the terms of the GNU General Public License v2 |
2380 |
+# $Id$ |
2381 |
+ |
2382 |
+__all__ = ['getmaskingreason'] |
2383 |
+ |
2384 |
+import portage |
2385 |
+from portage import os |
2386 |
+from portage.const import USER_CONFIG_PATH |
2387 |
+from portage.dep import match_from_list |
2388 |
+from portage.localization import _ |
2389 |
+from portage.util import grablines, normalize_path |
2390 |
+from portage.versions import catpkgsplit |
2391 |
+ |
2392 |
+def getmaskingreason(mycpv, metadata=None, settings=None, portdb=None, return_location=False): |
2393 |
+ if settings is None: |
2394 |
+ settings = portage.settings |
2395 |
+ if portdb is None: |
2396 |
+ portdb = portage.portdb |
2397 |
+ mysplit = catpkgsplit(mycpv) |
2398 |
+ if not mysplit: |
2399 |
+ raise ValueError(_("invalid CPV: %s") % mycpv) |
2400 |
+ if metadata is None: |
2401 |
+ db_keys = list(portdb._aux_cache_keys) |
2402 |
+ try: |
2403 |
+ metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) |
2404 |
+ except KeyError: |
2405 |
+ if not portdb.cpv_exists(mycpv): |
2406 |
+ raise |
2407 |
+ if metadata is None: |
2408 |
+ # Can't access SLOT due to corruption. |
2409 |
+ cpv_slot_list = [mycpv] |
2410 |
+ else: |
2411 |
+ cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] |
2412 |
+ mycp=mysplit[0]+"/"+mysplit[1] |
2413 |
+ |
2414 |
+ # XXX- This is a temporary duplicate of code from the config constructor. |
2415 |
+ locations = [os.path.join(settings["PORTDIR"], "profiles")] |
2416 |
+ locations.extend(settings.profiles) |
2417 |
+ for ov in settings["PORTDIR_OVERLAY"].split(): |
2418 |
+ profdir = os.path.join(normalize_path(ov), "profiles") |
2419 |
+ if os.path.isdir(profdir): |
2420 |
+ locations.append(profdir) |
2421 |
+ locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"], |
2422 |
+ USER_CONFIG_PATH)) |
2423 |
+ locations.reverse() |
2424 |
+ pmasklists = [(x, grablines(os.path.join(x, "package.mask"), recursive=1)) for x in locations] |
2425 |
+ |
2426 |
+ if mycp in settings.pmaskdict: |
2427 |
+ for x in settings.pmaskdict[mycp]: |
2428 |
+ if match_from_list(x, cpv_slot_list): |
2429 |
+ for pmask in pmasklists: |
2430 |
+ comment = "" |
2431 |
+ comment_valid = -1 |
2432 |
+ pmask_filename = os.path.join(pmask[0], "package.mask") |
2433 |
+ for i in range(len(pmask[1])): |
2434 |
+ l = pmask[1][i].strip() |
2435 |
+ if l == "": |
2436 |
+ comment = "" |
2437 |
+ comment_valid = -1 |
2438 |
+ elif l[0] == "#": |
2439 |
+ comment += (l+"\n") |
2440 |
+ comment_valid = i + 1 |
2441 |
+ elif l == x: |
2442 |
+ if comment_valid != i: |
2443 |
+ comment = "" |
2444 |
+ if return_location: |
2445 |
+ return (comment, pmask_filename) |
2446 |
+ else: |
2447 |
+ return comment |
2448 |
+ elif comment_valid != -1: |
2449 |
+ # Apparently this comment applies to muliple masks, so |
2450 |
+ # it remains valid until a blank line is encountered. |
2451 |
+ comment_valid += 1 |
2452 |
+ if return_location: |
2453 |
+ return (None, None) |
2454 |
+ else: |
2455 |
+ return None |
2456 |
|
2457 |
Copied: main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py (from rev 15465, main/trunk/pym/portage/package/ebuild/getmaskingstatus.py) |
2458 |
=================================================================== |
2459 |
--- main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py (rev 0) |
2460 |
+++ main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py 2010-02-27 19:32:48 UTC (rev 15483) |
2461 |
@@ -0,0 +1,154 @@ |
2462 |
+# Copyright 2010 Gentoo Foundation |
2463 |
+# Distributed under the terms of the GNU General Public License v2 |
2464 |
+# $Id$ |
2465 |
+ |
2466 |
+__all__ = ['getmaskingstatus'] |
2467 |
+ |
2468 |
+import portage |
2469 |
+from portage import eapi_is_supported, _eapi_is_deprecated |
2470 |
+from portage.dep import match_from_list |
2471 |
+from portage.localization import _ |
2472 |
+from portage.package.ebuild.config import config |
2473 |
+from portage.versions import catpkgsplit, cpv_getkey |
2474 |
+ |
2475 |
+def getmaskingstatus(mycpv, settings=None, portdb=None): |
2476 |
+ if settings is None: |
2477 |
+ settings = config(clone=portage.settings) |
2478 |
+ if portdb is None: |
2479 |
+ portdb = portage.portdb |
2480 |
+ |
2481 |
+ metadata = None |
2482 |
+ installed = False |
2483 |
+ if not isinstance(mycpv, basestring): |
2484 |
+ # emerge passed in a Package instance |
2485 |
+ pkg = mycpv |
2486 |
+ mycpv = pkg.cpv |
2487 |
+ metadata = pkg.metadata |
2488 |
+ installed = pkg.installed |
2489 |
+ |
2490 |
+ mysplit = catpkgsplit(mycpv) |
2491 |
+ if not mysplit: |
2492 |
+ raise ValueError(_("invalid CPV: %s") % mycpv) |
2493 |
+ if metadata is None: |
2494 |
+ db_keys = list(portdb._aux_cache_keys) |
2495 |
+ try: |
2496 |
+ metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys))) |
2497 |
+ except KeyError: |
2498 |
+ if not portdb.cpv_exists(mycpv): |
2499 |
+ raise |
2500 |
+ return ["corruption"] |
2501 |
+ if "?" in metadata["LICENSE"]: |
2502 |
+ settings.setcpv(mycpv, mydb=metadata) |
2503 |
+ metadata["USE"] = settings["PORTAGE_USE"] |
2504 |
+ else: |
2505 |
+ metadata["USE"] = "" |
2506 |
+ |
2507 |
+ rValue = [] |
2508 |
+ |
2509 |
+ # profile checking |
2510 |
+ if settings._getProfileMaskAtom(mycpv, metadata): |
2511 |
+ rValue.append("profile") |
2512 |
+ |
2513 |
+ # package.mask checking |
2514 |
+ if settings._getMaskAtom(mycpv, metadata): |
2515 |
+ rValue.append("package.mask") |
2516 |
+ |
2517 |
+ # keywords checking |
2518 |
+ eapi = metadata["EAPI"] |
2519 |
+ mygroups = settings._getKeywords(mycpv, metadata) |
2520 |
+ licenses = metadata["LICENSE"] |
2521 |
+ properties = metadata["PROPERTIES"] |
2522 |
+ if eapi.startswith("-"): |
2523 |
+ eapi = eapi[1:] |
2524 |
+ if not eapi_is_supported(eapi): |
2525 |
+ return ["EAPI %s" % eapi] |
2526 |
+ elif _eapi_is_deprecated(eapi) and not installed: |
2527 |
+ return ["EAPI %s" % eapi] |
2528 |
+ egroups = settings.configdict["backupenv"].get( |
2529 |
+ "ACCEPT_KEYWORDS", "").split() |
2530 |
+ pgroups = settings["ACCEPT_KEYWORDS"].split() |
2531 |
+ myarch = settings["ARCH"] |
2532 |
+ if pgroups and myarch not in pgroups: |
2533 |
+ """For operating systems other than Linux, ARCH is not necessarily a |
2534 |
+ valid keyword.""" |
2535 |
+ myarch = pgroups[0].lstrip("~") |
2536 |
+ |
2537 |
+ cp = cpv_getkey(mycpv) |
2538 |
+ pkgdict = settings.pkeywordsdict.get(cp) |
2539 |
+ matches = False |
2540 |
+ if pkgdict: |
2541 |
+ cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])] |
2542 |
+ for atom, pkgkeywords in pkgdict.items(): |
2543 |
+ if match_from_list(atom, cpv_slot_list): |
2544 |
+ matches = True |
2545 |
+ pgroups.extend(pkgkeywords) |
2546 |
+ if matches or egroups: |
2547 |
+ pgroups.extend(egroups) |
2548 |
+ inc_pgroups = set() |
2549 |
+ for x in pgroups: |
2550 |
+ if x.startswith("-"): |
2551 |
+ if x == "-*": |
2552 |
+ inc_pgroups.clear() |
2553 |
+ else: |
2554 |
+ inc_pgroups.discard(x[1:]) |
2555 |
+ else: |
2556 |
+ inc_pgroups.add(x) |
2557 |
+ pgroups = inc_pgroups |
2558 |
+ del inc_pgroups |
2559 |
+ |
2560 |
+ kmask = "missing" |
2561 |
+ |
2562 |
+ if '**' in pgroups: |
2563 |
+ kmask = None |
2564 |
+ else: |
2565 |
+ for keyword in pgroups: |
2566 |
+ if keyword in mygroups: |
2567 |
+ kmask = None |
2568 |
+ break |
2569 |
+ |
2570 |
+ if kmask: |
2571 |
+ for gp in mygroups: |
2572 |
+ if gp=="*": |
2573 |
+ kmask=None |
2574 |
+ break |
2575 |
+ elif gp=="-"+myarch and myarch in pgroups: |
2576 |
+ kmask="-"+myarch |
2577 |
+ break |
2578 |
+ elif gp=="~"+myarch and myarch in pgroups: |
2579 |
+ kmask="~"+myarch |
2580 |
+ break |
2581 |
+ |
2582 |
+ try: |
2583 |
+ missing_licenses = settings._getMissingLicenses(mycpv, metadata) |
2584 |
+ if missing_licenses: |
2585 |
+ allowed_tokens = set(["||", "(", ")"]) |
2586 |
+ allowed_tokens.update(missing_licenses) |
2587 |
+ license_split = licenses.split() |
2588 |
+ license_split = [x for x in license_split \ |
2589 |
+ if x in allowed_tokens] |
2590 |
+ msg = license_split[:] |
2591 |
+ msg.append("license(s)") |
2592 |
+ rValue.append(" ".join(msg)) |
2593 |
+ except portage.exception.InvalidDependString as e: |
2594 |
+ rValue.append("LICENSE: "+str(e)) |
2595 |
+ |
2596 |
+ try: |
2597 |
+ missing_properties = settings._getMissingProperties(mycpv, metadata) |
2598 |
+ if missing_properties: |
2599 |
+ allowed_tokens = set(["||", "(", ")"]) |
2600 |
+ allowed_tokens.update(missing_properties) |
2601 |
+ properties_split = properties.split() |
2602 |
+ properties_split = [x for x in properties_split \ |
2603 |
+ if x in allowed_tokens] |
2604 |
+ msg = properties_split[:] |
2605 |
+ msg.append("properties") |
2606 |
+ rValue.append(" ".join(msg)) |
2607 |
+ except portage.exception.InvalidDependString as e: |
2608 |
+ rValue.append("PROPERTIES: "+str(e)) |
2609 |
+ |
2610 |
+ # Only show KEYWORDS masks for installed packages |
2611 |
+ # if they're not masked for any other reason. |
2612 |
+ if kmask and (not installed or not rValue): |
2613 |
+ rValue.append(kmask+" keyword") |
2614 |
+ |
2615 |
+ return rValue |
2616 |
|
2617 |
Copied: main/branches/prefix/pym/portage/util/movefile.py (from rev 15465, main/trunk/pym/portage/util/movefile.py) |
2618 |
=================================================================== |
2619 |
--- main/branches/prefix/pym/portage/util/movefile.py (rev 0) |
2620 |
+++ main/branches/prefix/pym/portage/util/movefile.py 2010-02-27 19:32:48 UTC (rev 15483) |
2621 |
@@ -0,0 +1,234 @@ |
2622 |
+# Copyright 2010 Gentoo Foundation |
2623 |
+# Distributed under the terms of the GNU General Public License v2 |
2624 |
+# $Id$ |
2625 |
+ |
2626 |
+__all__ = ['movefile'] |
2627 |
+ |
2628 |
+import errno |
2629 |
+import os as _os |
2630 |
+import shutil as _shutil |
2631 |
+import stat |
2632 |
+ |
2633 |
+import portage |
2634 |
+from portage import bsd_chflags, _encodings, _os_overrides, _selinux, \ |
2635 |
+ _unicode_decode, _unicode_func_wrapper, _unicode_module_wrapper |
2636 |
+from portage.const import MOVE_BINARY |
2637 |
+from portage.localization import _ |
2638 |
+from portage.process import spawn |
2639 |
+from portage.util import writemsg |
2640 |
+ |
2641 |
+def movefile(src, dest, newmtime=None, sstat=None, mysettings=None, |
2642 |
+ hardlink_candidates=None, encoding=_encodings['fs']): |
2643 |
+ """moves a file from src to dest, preserving all permissions and attributes; mtime will |
2644 |
+ be preserved even when moving across filesystems. Returns true on success and false on |
2645 |
+ failure. Move is atomic.""" |
2646 |
+ #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")" |
2647 |
+ |
2648 |
+ if mysettings is None: |
2649 |
+ mysettings = portage.settings |
2650 |
+ |
2651 |
+ selinux_enabled = mysettings.selinux_enabled() |
2652 |
+ if selinux_enabled: |
2653 |
+ selinux = _unicode_module_wrapper(_selinux, encoding=encoding) |
2654 |
+ |
2655 |
+ lchown = _unicode_func_wrapper(portage.data.lchown, encoding=encoding) |
2656 |
+ os = _unicode_module_wrapper(_os, |
2657 |
+ encoding=encoding, overrides=_os_overrides) |
2658 |
+ shutil = _unicode_module_wrapper(_shutil, encoding=encoding) |
2659 |
+ |
2660 |
+ try: |
2661 |
+ if not sstat: |
2662 |
+ sstat=os.lstat(src) |
2663 |
+ |
2664 |
+ except SystemExit as e: |
2665 |
+ raise |
2666 |
+ except Exception as e: |
2667 |
+ print(_("!!! Stating source file failed... movefile()")) |
2668 |
+ print("!!!",e) |
2669 |
+ return None |
2670 |
+ |
2671 |
+ destexists=1 |
2672 |
+ try: |
2673 |
+ dstat=os.lstat(dest) |
2674 |
+ except (OSError, IOError): |
2675 |
+ dstat=os.lstat(os.path.dirname(dest)) |
2676 |
+ destexists=0 |
2677 |
+ |
2678 |
+ if bsd_chflags: |
2679 |
+ if destexists and dstat.st_flags != 0: |
2680 |
+ bsd_chflags.lchflags(dest, 0) |
2681 |
+ # Use normal stat/chflags for the parent since we want to |
2682 |
+ # follow any symlinks to the real parent directory. |
2683 |
+ pflags = os.stat(os.path.dirname(dest)).st_flags |
2684 |
+ if pflags != 0: |
2685 |
+ bsd_chflags.chflags(os.path.dirname(dest), 0) |
2686 |
+ |
2687 |
+ if destexists: |
2688 |
+ if stat.S_ISLNK(dstat[stat.ST_MODE]): |
2689 |
+ try: |
2690 |
+ os.unlink(dest) |
2691 |
+ destexists=0 |
2692 |
+ except SystemExit as e: |
2693 |
+ raise |
2694 |
+ except Exception as e: |
2695 |
+ pass |
2696 |
+ |
2697 |
+ if stat.S_ISLNK(sstat[stat.ST_MODE]): |
2698 |
+ try: |
2699 |
+ target=os.readlink(src) |
2700 |
+ if mysettings and mysettings["D"]: |
2701 |
+ if target.find(mysettings["D"])==0: |
2702 |
+ target=target[len(mysettings["D"]):] |
2703 |
+ if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): |
2704 |
+ os.unlink(dest) |
2705 |
+ if selinux_enabled: |
2706 |
+ selinux.symlink(target, dest, src) |
2707 |
+ else: |
2708 |
+ os.symlink(target,dest) |
2709 |
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
2710 |
+ # utime() only works on the target of a symlink, so it's not |
2711 |
+ # possible to perserve mtime on symlinks. |
2712 |
+ return os.lstat(dest)[stat.ST_MTIME] |
2713 |
+ except SystemExit as e: |
2714 |
+ raise |
2715 |
+ except Exception as e: |
2716 |
+ print(_("!!! failed to properly create symlink:")) |
2717 |
+ print("!!!",dest,"->",target) |
2718 |
+ print("!!!",e) |
2719 |
+ return None |
2720 |
+ |
2721 |
+ hardlinked = False |
2722 |
+ # Since identical files might be merged to multiple filesystems, |
2723 |
+ # so os.link() calls might fail for some paths, so try them all. |
2724 |
+ # For atomic replacement, first create the link as a temp file |
2725 |
+ # and them use os.rename() to replace the destination. |
2726 |
+ if hardlink_candidates: |
2727 |
+ head, tail = os.path.split(dest) |
2728 |
+ hardlink_tmp = os.path.join(head, ".%s._portage_merge_.%s" % \ |
2729 |
+ (tail, os.getpid())) |
2730 |
+ try: |
2731 |
+ os.unlink(hardlink_tmp) |
2732 |
+ except OSError as e: |
2733 |
+ if e.errno != errno.ENOENT: |
2734 |
+ writemsg(_("!!! Failed to remove hardlink temp file: %s\n") % \ |
2735 |
+ (hardlink_tmp,), noiselevel=-1) |
2736 |
+ writemsg("!!! %s\n" % (e,), noiselevel=-1) |
2737 |
+ return None |
2738 |
+ del e |
2739 |
+ for hardlink_src in hardlink_candidates: |
2740 |
+ try: |
2741 |
+ os.link(hardlink_src, hardlink_tmp) |
2742 |
+ except OSError: |
2743 |
+ continue |
2744 |
+ else: |
2745 |
+ try: |
2746 |
+ os.rename(hardlink_tmp, dest) |
2747 |
+ except OSError as e: |
2748 |
+ writemsg(_("!!! Failed to rename %s to %s\n") % \ |
2749 |
+ (hardlink_tmp, dest), noiselevel=-1) |
2750 |
+ writemsg("!!! %s\n" % (e,), noiselevel=-1) |
2751 |
+ return None |
2752 |
+ hardlinked = True |
2753 |
+ break |
2754 |
+ |
2755 |
+ renamefailed=1 |
2756 |
+ if hardlinked: |
2757 |
+ renamefailed = False |
2758 |
+ if not hardlinked and (selinux_enabled or sstat.st_dev == dstat.st_dev): |
2759 |
+ try: |
2760 |
+ if selinux_enabled: |
2761 |
+ selinux.rename(src, dest) |
2762 |
+ else: |
2763 |
+ os.rename(src,dest) |
2764 |
+ renamefailed=0 |
2765 |
+ except OSError as e: |
2766 |
+ if e.errno != errno.EXDEV: |
2767 |
+ # Some random error. |
2768 |
+ print(_("!!! Failed to move %(src)s to %(dest)s") % {"src": src, "dest": dest}) |
2769 |
+ print("!!!",e) |
2770 |
+ return None |
2771 |
+ # Invalid cross-device-link 'bind' mounted or actually Cross-Device |
2772 |
+ if renamefailed: |
2773 |
+ didcopy=0 |
2774 |
+ if stat.S_ISREG(sstat[stat.ST_MODE]): |
2775 |
+ try: # For safety copy then move it over. |
2776 |
+ if selinux_enabled: |
2777 |
+ selinux.copyfile(src, dest + "#new") |
2778 |
+ selinux.rename(dest + "#new", dest) |
2779 |
+ else: |
2780 |
+ shutil.copyfile(src,dest+"#new") |
2781 |
+ os.rename(dest+"#new",dest) |
2782 |
+ didcopy=1 |
2783 |
+ except SystemExit as e: |
2784 |
+ raise |
2785 |
+ except Exception as e: |
2786 |
+ print(_('!!! copy %(src)s -> %(dest)s failed.') % {"src": src, "dest": dest}) |
2787 |
+ print("!!!",e) |
2788 |
+ return None |
2789 |
+ else: |
2790 |
+ #we don't yet handle special, so we need to fall back to /bin/mv |
2791 |
+ a = spawn([MOVE_BINARY, '-f', src, dest], env=os.environ) |
2792 |
+ if a != os.EX_OK: |
2793 |
+ writemsg(_("!!! Failed to move special file:\n"), noiselevel=-1) |
2794 |
+ writemsg(_("!!! '%(src)s' to '%(dest)s'\n") % \ |
2795 |
+ {"src": _unicode_decode(src, encoding=encoding), |
2796 |
+ "dest": _unicode_decode(dest, encoding=encoding)}, noiselevel=-1) |
2797 |
+ writemsg("!!! %s\n" % a, noiselevel=-1) |
2798 |
+ return None # failure |
2799 |
+ try: |
2800 |
+ if didcopy: |
2801 |
+ if stat.S_ISLNK(sstat[stat.ST_MODE]): |
2802 |
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
2803 |
+ else: |
2804 |
+ os.chown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) |
2805 |
+ os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown |
2806 |
+ os.unlink(src) |
2807 |
+ except SystemExit as e: |
2808 |
+ raise |
2809 |
+ except Exception as e: |
2810 |
+ print(_("!!! Failed to chown/chmod/unlink in movefile()")) |
2811 |
+ print("!!!",dest) |
2812 |
+ print("!!!",e) |
2813 |
+ return None |
2814 |
+ |
2815 |
+ # Always use stat_obj[stat.ST_MTIME] for the integral timestamp which |
2816 |
+ # is returned, since the stat_obj.st_mtime float attribute rounds *up* |
2817 |
+ # if the nanosecond part of the timestamp is 999999881 ns or greater. |
2818 |
+ try: |
2819 |
+ if hardlinked: |
2820 |
+ newmtime = os.stat(dest)[stat.ST_MTIME] |
2821 |
+ else: |
2822 |
+ # Note: It is not possible to preserve nanosecond precision |
2823 |
+ # (supported in POSIX.1-2008 via utimensat) with the IEEE 754 |
2824 |
+ # double precision float which only has a 53 bit significand. |
2825 |
+ if newmtime is not None: |
2826 |
+ os.utime(dest, (newmtime, newmtime)) |
2827 |
+ else: |
2828 |
+ newmtime = sstat[stat.ST_MTIME] |
2829 |
+ if renamefailed: |
2830 |
+ # If rename succeeded then timestamps are automatically |
2831 |
+ # preserved with complete precision because the source |
2832 |
+ # and destination inode are the same. Otherwise, round |
2833 |
+ # down to the nearest whole second since python's float |
2834 |
+ # st_mtime cannot be used to preserve the st_mtim.tv_nsec |
2835 |
+ # field with complete precision. Note that we have to use |
2836 |
+ # stat_obj[stat.ST_MTIME] here because the float |
2837 |
+ # stat_obj.st_mtime rounds *up* sometimes. |
2838 |
+ os.utime(dest, (newmtime, newmtime)) |
2839 |
+ except OSError: |
2840 |
+ # The utime can fail here with EPERM even though the move succeeded. |
2841 |
+ # Instead of failing, use stat to return the mtime if possible. |
2842 |
+ try: |
2843 |
+ newmtime = os.stat(dest)[stat.ST_MTIME] |
2844 |
+ except OSError as e: |
2845 |
+ writemsg(_("!!! Failed to stat in movefile()\n"), noiselevel=-1) |
2846 |
+ writemsg("!!! %s\n" % dest, noiselevel=-1) |
2847 |
+ writemsg("!!! %s\n" % str(e), noiselevel=-1) |
2848 |
+ return None |
2849 |
+ |
2850 |
+ if bsd_chflags: |
2851 |
+ # Restore the flags we saved before moving |
2852 |
+ if pflags: |
2853 |
+ bsd_chflags.chflags(os.path.dirname(dest), pflags) |
2854 |
+ |
2855 |
+ return newmtime |