1 # Copyright 1998-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 from __future__
import unicode_literals
6 __all__
= ["bindbapi", "binarytree"]
9 portage
.proxy
.lazyimport
.lazyimport(globals(),
10 'portage.checksum:hashfunc_map,perform_multiple_checksums,' + \
11 'verify_all,_apply_hash_filter,_hash_filter',
12 'portage.dbapi.dep_expand:dep_expand',
13 'portage.dep:dep_getkey,isjustname,isvalidatom,match_from_list',
14 'portage.output:EOutput,colorize',
15 'portage.locks:lockfile,unlockfile',
16 'portage.package.ebuild.fetch:_check_distfile,_hide_url_passwd',
17 'portage.update:update_dbentries',
18 'portage.util:atomic_ofstream,ensure_dirs,normalize_path,' + \
19 'writemsg,writemsg_stdout',
20 'portage.util.listdir:listdir',
21 'portage.util._urlopen:urlopen@_urlopen',
22 'portage.versions:best,catpkgsplit,catsplit,_pkg_str',
25 from portage
.cache
.mappings
import slot_dict_class
26 from portage
.const
import CACHE_PATH
27 from portage
.dbapi
.virtual
import fakedbapi
28 from portage
.dep
import Atom
, use_reduce
, paren_enclose
29 from portage
.exception
import AlarmSignal
, InvalidData
, InvalidPackageName
, \
30 PermissionDenied
, PortageException
31 from portage
.localization
import _
32 from portage
import _movefile
33 from portage
import os
34 from portage
import _encodings
35 from portage
import _unicode_decode
36 from portage
import _unicode_encode
48 from gzip
import GzipFile
49 from itertools
import chain
51 from urllib
.parse
import urlparse
53 from urlparse
import urlparse
55 if sys
.hexversion
>= 0x3000000:
62 class UseCachedCopyOfRemoteIndex(Exception):
63 # If the local copy is recent enough
64 # then fetching the remote index can be skipped.
67 class bindbapi(fakedbapi
):
68 _known_keys
= frozenset(list(fakedbapi
._known_keys
) + \
69 ["CHOST", "repository", "USE"])
70 def __init__(self
, mybintree
=None, **kwargs
):
71 fakedbapi
.__init__(self
, **kwargs
)
72 self
.bintree
= mybintree
73 self
.move_ent
= mybintree
.move_ent
76 # Selectively cache metadata in order to optimize dep matching.
77 self
._aux_cache_keys
= set(
78 ["BUILD_TIME", "CHOST", "DEPEND", "EAPI",
79 "HDEPEND", "IUSE", "KEYWORDS",
80 "LICENSE", "PDEPEND", "PROPERTIES", "PROVIDE",
81 "RDEPEND", "repository", "RESTRICT", "SLOT", "USE", "DEFINED_PHASES"
83 self
._aux_cache_slot_dict
= slot_dict_class(self
._aux_cache_keys
)
86 def match(self
, *pargs
, **kwargs
):
87 if self
.bintree
and not self
.bintree
.populated
:
88 self
.bintree
.populate()
89 return fakedbapi
.match(self
, *pargs
, **kwargs
)
91 def cpv_exists(self
, cpv
, myrepo
=None):
92 if self
.bintree
and not self
.bintree
.populated
:
93 self
.bintree
.populate()
94 return fakedbapi
.cpv_exists(self
, cpv
)
96 def cpv_inject(self
, cpv
, **kwargs
):
97 self
._aux_cache
.pop(cpv
, None)
98 fakedbapi
.cpv_inject(self
, cpv
, **kwargs
)
100 def cpv_remove(self
, cpv
):
101 self
._aux_cache
.pop(cpv
, None)
102 fakedbapi
.cpv_remove(self
, cpv
)
104 def aux_get(self
, mycpv
, wants
, myrepo
=None):
105 if self
.bintree
and not self
.bintree
.populated
:
106 self
.bintree
.populate()
108 if not self
._known_keys
.intersection(
109 wants
).difference(self
._aux_cache_keys
):
110 aux_cache
= self
._aux_cache
.get(mycpv
)
111 if aux_cache
is not None:
112 return [aux_cache
.get(x
, "") for x
in wants
]
114 mysplit
= mycpv
.split("/")
116 tbz2name
= mysplit
[1]+".tbz2"
117 if not self
.bintree
._remotepkgs
or \
118 not self
.bintree
.isremote(mycpv
):
119 tbz2_path
= self
.bintree
.getname(mycpv
)
120 if not os
.path
.exists(tbz2_path
):
121 raise KeyError(mycpv
)
122 metadata_bytes
= portage
.xpak
.tbz2(tbz2_path
).get_data()
124 v
= metadata_bytes
.get(_unicode_encode(k
,
125 encoding
=_encodings
['repo.content'],
126 errors
='backslashreplace'))
128 v
= _unicode_decode(v
,
129 encoding
=_encodings
['repo.content'], errors
='replace')
132 getitem
= self
.bintree
._remotepkgs
[mycpv
].get
136 mykeys
= self
._aux_cache_keys
.union(wants
)
139 # myval is None if the key doesn't exist
140 # or the tbz2 is corrupt.
142 mydata
[x
] = " ".join(myval
.split())
144 if not mydata
.setdefault('EAPI', '0'):
148 aux_cache
= self
._aux_cache_slot_dict()
149 for x
in self
._aux_cache_keys
:
150 aux_cache
[x
] = mydata
.get(x
, '')
151 self
._aux_cache
[mycpv
] = aux_cache
152 return [mydata
.get(x
, '') for x
in wants
]
154 def aux_update(self
, cpv
, values
):
155 if not self
.bintree
.populated
:
156 self
.bintree
.populate()
157 tbz2path
= self
.bintree
.getname(cpv
)
158 if not os
.path
.exists(tbz2path
):
160 mytbz2
= portage
.xpak
.tbz2(tbz2path
)
161 mydata
= mytbz2
.get_data()
163 for k
, v
in values
.items():
164 k
= _unicode_encode(k
,
165 encoding
=_encodings
['repo.content'], errors
='backslashreplace')
166 v
= _unicode_encode(v
,
167 encoding
=_encodings
['repo.content'], errors
='backslashreplace')
170 for k
, v
in list(mydata
.items()):
173 mytbz2
.recompose_mem(portage
.xpak
.xpak_mem(mydata
))
174 # inject will clear stale caches via cpv_inject.
175 self
.bintree
.inject(cpv
)
177 def cp_list(self
, *pargs
, **kwargs
):
178 if not self
.bintree
.populated
:
179 self
.bintree
.populate()
180 return fakedbapi
.cp_list(self
, *pargs
, **kwargs
)
183 if not self
.bintree
.populated
:
184 self
.bintree
.populate()
185 return fakedbapi
.cp_all(self
)
188 if not self
.bintree
.populated
:
189 self
.bintree
.populate()
190 return fakedbapi
.cpv_all(self
)
192 def getfetchsizes(self
, pkg
):
194 This will raise MissingSignature if SIZE signature is not available,
195 or InvalidSignature if SIZE signature is invalid.
198 if not self
.bintree
.populated
:
199 self
.bintree
.populate()
201 pkg
= getattr(pkg
, 'cpv', pkg
)
204 if not self
.bintree
.isremote(pkg
):
207 metadata
= self
.bintree
._remotepkgs
[pkg
]
209 size
= int(metadata
["SIZE"])
211 raise portage
.exception
.MissingSignature("SIZE")
213 raise portage
.exception
.InvalidSignature(
214 "SIZE: %s" % metadata
["SIZE"])
216 filesdict
[os
.path
.basename(self
.bintree
.getname(pkg
))] = size
220 def _pkgindex_cpv_map_latest_build(pkgindex
):
222 Given a PackageIndex instance, create a dict of cpv -> metadata map.
223 If multiple packages have identical CPV values, prefer the package
224 with latest BUILD_TIME value.
225 @param pkgindex: A PackageIndex instance.
226 @type pkgindex: PackageIndex
228 @return: a dict containing entry for the give cpv.
232 for d
in pkgindex
.packages
:
238 writemsg(_("!!! Invalid remote binary package: %s\n") % cpv
,
242 btime
= d
.get('BUILD_TIME', '')
248 other_d
= cpv_map
.get(cpv
)
249 if other_d
is not None:
250 other_btime
= other_d
.get('BUILD_TIME', '')
252 other_btime
= int(other_btime
)
255 if other_btime
and (not btime
or other_btime
> btime
):
258 cpv_map
[_pkg_str(cpv
)] = d
262 class binarytree(object):
263 "this tree scans for a list of all packages available in PKGDIR"
264 def __init__(self
, _unused
=DeprecationWarning, pkgdir
=None,
265 virtual
=DeprecationWarning, settings
=None):
268 raise TypeError("pkgdir parameter is required")
271 raise TypeError("settings parameter is required")
273 if _unused
is not DeprecationWarning:
274 warnings
.warn("The first parameter of the "
275 "portage.dbapi.bintree.binarytree"
276 " constructor is now unused. Instead "
277 "settings['ROOT'] is used.",
278 DeprecationWarning, stacklevel
=2)
280 if virtual
is not DeprecationWarning:
281 warnings
.warn("The 'virtual' parameter of the "
282 "portage.dbapi.bintree.binarytree"
283 " constructor is unused",
284 DeprecationWarning, stacklevel
=2)
287 self
.pkgdir
= normalize_path(pkgdir
)
288 self
.dbapi
= bindbapi(self
, settings
=settings
)
289 self
.update_ents
= self
.dbapi
.update_ents
290 self
.move_slot_ent
= self
.dbapi
.move_slot_ent
293 self
._remote_has_index
= False
294 self
._remotepkgs
= None # remote metadata indexed by cpv
296 self
.settings
= settings
298 self
._pkgindex_uri
= {}
299 self
._populating
= False
300 self
._all_directory
= os
.path
.isdir(
301 os
.path
.join(self
.pkgdir
, "All"))
302 self
._pkgindex_version
= 0
303 self
._pkgindex_hashes
= ["MD5","SHA1"]
304 self
._pkgindex_file
= os
.path
.join(self
.pkgdir
, "Packages")
305 self
._pkgindex_keys
= self
.dbapi
._aux_cache_keys
.copy()
306 self
._pkgindex_keys
.update(["CPV", "MTIME", "SIZE"])
307 self
._pkgindex_aux_keys
= \
308 ["BUILD_TIME", "CHOST", "DEPEND", "DESCRIPTION", "EAPI",
309 "HDEPEND", "IUSE", "KEYWORDS", "LICENSE", "PDEPEND", "PROPERTIES",
310 "PROVIDE", "RESTRICT", "RDEPEND", "repository", "SLOT", "USE", "DEFINED_PHASES",
312 self
._pkgindex_aux_keys
= list(self
._pkgindex_aux_keys
)
313 self
._pkgindex_use_evaluated_keys
= \
314 ("DEPEND", "HDEPEND", "LICENSE", "RDEPEND",
315 "PDEPEND", "PROPERTIES", "PROVIDE", "RESTRICT")
316 self
._pkgindex_header_keys
= set([
317 "ACCEPT_KEYWORDS", "ACCEPT_LICENSE",
318 "ACCEPT_PROPERTIES", "ACCEPT_RESTRICT", "CBUILD",
319 "CONFIG_PROTECT", "CONFIG_PROTECT_MASK", "FEATURES",
320 "GENTOO_MIRRORS", "INSTALL_MASK", "SYNC", "USE"])
321 self
._pkgindex_default_pkg_data
= {
323 "DEFINED_PHASES" : "",
339 self
._pkgindex_inherited_keys
= ["CHOST", "repository"]
341 # Populate the header with appropriate defaults.
342 self
._pkgindex_default_header_data
= {
343 "CHOST" : self
.settings
.get("CHOST", ""),
347 # It is especially important to populate keys like
348 # "repository" that save space when entries can
349 # inherit them from the header. If an existing
350 # pkgindex header already defines these keys, then
351 # they will appropriately override our defaults.
352 main_repo
= self
.settings
.repositories
.mainRepo()
353 if main_repo
is not None and not main_repo
.missing_repo_name
:
354 self
._pkgindex_default_header_data
["repository"] = \
357 self
._pkgindex_translated_keys
= (
358 ("DESCRIPTION" , "DESC"),
359 ("repository" , "REPO"),
362 self
._pkgindex_allowed_pkg_keys
= set(chain(
364 self
._pkgindex_aux_keys
,
365 self
._pkgindex_hashes
,
366 self
._pkgindex_default_pkg_data
,
367 self
._pkgindex_inherited_keys
,
368 chain(*self
._pkgindex_translated_keys
)
373 warnings
.warn("The root attribute of "
374 "portage.dbapi.bintree.binarytree"
375 " is deprecated. Use "
376 "settings['ROOT'] instead.",
377 DeprecationWarning, stacklevel
=3)
378 return self
.settings
['ROOT']
380 def move_ent(self
, mylist
, repo_match
=None):
381 if not self
.populated
:
386 for atom
in (origcp
, newcp
):
387 if not isjustname(atom
):
388 raise InvalidPackageName(str(atom
))
389 mynewcat
= catsplit(newcp
)[0]
390 origmatches
=self
.dbapi
.cp_list(origcp
)
394 for mycpv
in origmatches
:
396 mycpv
= self
.dbapi
._pkg_str(mycpv
, None)
397 except (KeyError, InvalidData
):
399 mycpv_cp
= portage
.cpv_getkey(mycpv
)
400 if mycpv_cp
!= origcp
:
401 # Ignore PROVIDE virtual match.
403 if repo_match
is not None \
404 and not repo_match(mycpv
.repo
):
407 # Use isvalidatom() to check if this move is valid for the
408 # EAPI (characters allowed in package names may vary).
409 if not isvalidatom(newcp
, eapi
=mycpv
.eapi
):
412 mynewcpv
= mycpv
.replace(mycpv_cp
, _unicode(newcp
), 1)
413 myoldpkg
= catsplit(mycpv
)[1]
414 mynewpkg
= catsplit(mynewcpv
)[1]
416 if (mynewpkg
!= myoldpkg
) and os
.path
.exists(self
.getname(mynewcpv
)):
417 writemsg(_("!!! Cannot update binary: Destination exists.\n"),
419 writemsg("!!! "+mycpv
+" -> "+mynewcpv
+"\n", noiselevel
=-1)
422 tbz2path
= self
.getname(mycpv
)
423 if os
.path
.exists(tbz2path
) and not os
.access(tbz2path
,os
.W_OK
):
424 writemsg(_("!!! Cannot update readonly binary: %s\n") % mycpv
,
429 mytbz2
= portage
.xpak
.tbz2(tbz2path
)
430 mydata
= mytbz2
.get_data()
431 updated_items
= update_dbentries([mylist
], mydata
, parent
=mycpv
)
432 mydata
.update(updated_items
)
434 _unicode_encode(mynewpkg
+ "\n",
435 encoding
=_encodings
['repo.content'])
436 mydata
[b
'CATEGORY'] = \
437 _unicode_encode(mynewcat
+ "\n",
438 encoding
=_encodings
['repo.content'])
439 if mynewpkg
!= myoldpkg
:
440 ebuild_data
= mydata
.pop(_unicode_encode(myoldpkg
+ '.ebuild',
441 encoding
=_encodings
['repo.content']), None)
442 if ebuild_data
is not None:
443 mydata
[_unicode_encode(mynewpkg
+ '.ebuild',
444 encoding
=_encodings
['repo.content'])] = ebuild_data
446 mytbz2
.recompose_mem(portage
.xpak
.xpak_mem(mydata
))
448 self
.dbapi
.cpv_remove(mycpv
)
449 del self
._pkg_paths
[mycpv
]
450 new_path
= self
.getname(mynewcpv
)
451 self
._pkg_paths
[mynewcpv
] = os
.path
.join(
452 *new_path
.split(os
.path
.sep
)[-2:])
453 if new_path
!= mytbz2
:
454 self
._ensure_dir(os
.path
.dirname(new_path
))
455 _movefile(tbz2path
, new_path
, mysettings
=self
.settings
)
456 self
._remove_symlink(mycpv
)
457 if new_path
.split(os
.path
.sep
)[-2] == "All":
458 self
._create_symlink(mynewcpv
)
459 self
.inject(mynewcpv
)
463 def _remove_symlink(self
, cpv
):
464 """Remove a ${PKGDIR}/${CATEGORY}/${PF}.tbz2 symlink and also remove
465 the ${PKGDIR}/${CATEGORY} directory if empty. The file will not be
466 removed if os.path.islink() returns False."""
467 mycat
, mypkg
= catsplit(cpv
)
468 mylink
= os
.path
.join(self
.pkgdir
, mycat
, mypkg
+ ".tbz2")
469 if os
.path
.islink(mylink
):
470 """Only remove it if it's really a link so that this method never
471 removes a real package that was placed here to avoid a collision."""
474 os
.rmdir(os
.path
.join(self
.pkgdir
, mycat
))
476 if e
.errno
not in (errno
.ENOENT
,
477 errno
.ENOTEMPTY
, errno
.EEXIST
):
481 def _create_symlink(self
, cpv
):
482 """Create a ${PKGDIR}/${CATEGORY}/${PF}.tbz2 symlink (and
483 ${PKGDIR}/${CATEGORY} directory, if necessary). Any file that may
484 exist in the location of the symlink will first be removed."""
485 mycat
, mypkg
= catsplit(cpv
)
486 full_path
= os
.path
.join(self
.pkgdir
, mycat
, mypkg
+ ".tbz2")
487 self
._ensure_dir(os
.path
.dirname(full_path
))
491 if e
.errno
!= errno
.ENOENT
:
494 os
.symlink(os
.path
.join("..", "All", mypkg
+ ".tbz2"), full_path
)
496 def prevent_collision(self
, cpv
):
497 """Make sure that the file location ${PKGDIR}/All/${PF}.tbz2 is safe to
498 use for a given cpv. If a collision will occur with an existing
499 package from another category, the existing package will be bumped to
500 ${PKGDIR}/${CATEGORY}/${PF}.tbz2 so that both can coexist."""
501 if not self
._all_directory
:
504 # Copy group permissions for new directories that
505 # may have been created.
506 for path
in ("All", catsplit(cpv
)[0]):
507 path
= os
.path
.join(self
.pkgdir
, path
)
508 self
._ensure_dir(path
)
509 if not os
.access(path
, os
.W_OK
):
510 raise PermissionDenied("access('%s', W_OK)" % path
)
512 full_path
= self
.getname(cpv
)
513 if "All" == full_path
.split(os
.path
.sep
)[-2]:
515 """Move a colliding package if it exists. Code below this point only
516 executes in rare cases."""
517 mycat
, mypkg
= catsplit(cpv
)
518 myfile
= mypkg
+ ".tbz2"
519 mypath
= os
.path
.join("All", myfile
)
520 dest_path
= os
.path
.join(self
.pkgdir
, mypath
)
523 st
= os
.lstat(dest_path
)
527 if stat
.S_ISLNK(st
.st_mode
):
532 if os
.path
.exists(dest_path
):
536 # For invalid packages, other_cat could be None.
537 other_cat
= portage
.xpak
.tbz2(dest_path
).getfile(b
"CATEGORY")
539 other_cat
= _unicode_decode(other_cat
,
540 encoding
=_encodings
['repo.content'], errors
='replace')
541 other_cat
= other_cat
.strip()
542 other_cpv
= other_cat
+ "/" + mypkg
543 self
._move_from_all(other_cpv
)
544 self
.inject(other_cpv
)
545 self
._move_to_all(cpv
)
547 def _ensure_dir(self
, path
):
549 Create the specified directory. Also, copy gid and group mode
550 bits from self.pkgdir if possible.
551 @param cat_dir: Absolute path of the directory to be created.
552 @type cat_dir: String
555 pkgdir_st
= os
.stat(self
.pkgdir
)
559 pkgdir_gid
= pkgdir_st
.st_gid
560 pkgdir_grp_mode
= 0o2070
& pkgdir_st
.st_mode
562 ensure_dirs(path
, gid
=pkgdir_gid
, mode
=pkgdir_grp_mode
, mask
=0)
563 except PortageException
:
564 if not os
.path
.isdir(path
):
567 def _file_permissions(self
, path
):
569 pkgdir_st
= os
.stat(self
.pkgdir
)
573 pkgdir_gid
= pkgdir_st
.st_gid
574 pkgdir_grp_mode
= 0o0060
& pkgdir_st
.st_mode
576 portage
.util
.apply_permissions(path
, gid
=pkgdir_gid
,
577 mode
=pkgdir_grp_mode
, mask
=0)
578 except PortageException
:
581 def _move_to_all(self
, cpv
):
582 """If the file exists, move it. Whether or not it exists, update state
583 for future getname() calls."""
584 mycat
, mypkg
= catsplit(cpv
)
585 myfile
= mypkg
+ ".tbz2"
586 self
._pkg_paths
[cpv
] = os
.path
.join("All", myfile
)
587 src_path
= os
.path
.join(self
.pkgdir
, mycat
, myfile
)
589 mystat
= os
.lstat(src_path
)
592 if mystat
and stat
.S_ISREG(mystat
.st_mode
):
593 self
._ensure_dir(os
.path
.join(self
.pkgdir
, "All"))
594 dest_path
= os
.path
.join(self
.pkgdir
, "All", myfile
)
595 _movefile(src_path
, dest_path
, mysettings
=self
.settings
)
596 self
._create_symlink(cpv
)
599 def _move_from_all(self
, cpv
):
600 """Move a package from ${PKGDIR}/All/${PF}.tbz2 to
601 ${PKGDIR}/${CATEGORY}/${PF}.tbz2 and update state from getname calls."""
602 self
._remove_symlink(cpv
)
603 mycat
, mypkg
= catsplit(cpv
)
604 myfile
= mypkg
+ ".tbz2"
605 mypath
= os
.path
.join(mycat
, myfile
)
606 dest_path
= os
.path
.join(self
.pkgdir
, mypath
)
607 self
._ensure_dir(os
.path
.dirname(dest_path
))
608 src_path
= os
.path
.join(self
.pkgdir
, "All", myfile
)
609 _movefile(src_path
, dest_path
, mysettings
=self
.settings
)
610 self
._pkg_paths
[cpv
] = mypath
612 def populate(self
, getbinpkgs
=0):
613 "populates the binarytree"
620 if os
.access(self
.pkgdir
, os
.W_OK
):
621 pkgindex_lock
= lockfile(self
._pkgindex_file
,
623 self
._populating
= True
624 self
._populate(getbinpkgs
)
627 unlockfile(pkgindex_lock
)
628 self
._populating
= False
630 def _populate(self
, getbinpkgs
=0):
631 if (not os
.path
.isdir(self
.pkgdir
) and not getbinpkgs
):
634 # Clear all caches in case populate is called multiple times
635 # as may be the case when _global_updates calls populate()
636 # prior to performing package moves since it only wants to
637 # operate on local packages (getbinpkgs=0).
638 self
._remotepkgs
= None
639 self
.dbapi
._clear_cache()
640 self
.dbapi
._aux_cache
.clear()
643 self
._pkg_paths
= pkg_paths
644 dirs
= listdir(self
.pkgdir
, dirsonly
=True, EmptyOnError
=True)
648 dirs
.insert(0, "All")
649 pkgindex
= self
._load_pkgindex()
651 if not self
._pkgindex_version_supported(pkgindex
):
652 pkgindex
= self
._new_pkgindex()
653 header
= pkgindex
.header
655 for d
in pkgindex
.packages
:
656 metadata
[d
["CPV"]] = d
657 update_pkgindex
= False
659 for myfile
in listdir(os
.path
.join(self
.pkgdir
, mydir
)):
660 if not myfile
.endswith(".tbz2"):
662 mypath
= os
.path
.join(mydir
, myfile
)
663 full_path
= os
.path
.join(self
.pkgdir
, mypath
)
664 s
= os
.lstat(full_path
)
665 if stat
.S_ISLNK(s
.st_mode
):
668 # Validate data from the package index and try to avoid
669 # reading the xpak if possible.
672 d
= metadata
.get(mydir
+"/"+myfile
[:-5])
678 for mycpv
in metadata
:
679 mycat
, mypf
= catsplit(mycpv
)
681 mypf
, []).append(metadata
[mycpv
])
682 possibilities
= pf_index
.get(myfile
[:-5])
685 for d
in possibilities
:
687 if long(d
["MTIME"]) != s
[stat
.ST_MTIME
]:
689 except (KeyError, ValueError):
692 if long(d
["SIZE"]) != long(s
.st_size
):
694 except (KeyError, ValueError):
696 if not self
._pkgindex_keys
.difference(d
):
701 if mycpv
in pkg_paths
:
702 # discard duplicates (All/ is preferred)
704 mycpv
= _pkg_str(mycpv
)
705 pkg_paths
[mycpv
] = mypath
706 # update the path if the package has been moved
707 oldpath
= d
.get("PATH")
708 if oldpath
and oldpath
!= mypath
:
709 update_pkgindex
= True
710 if mypath
!= mycpv
+ ".tbz2":
713 update_pkgindex
= True
717 update_pkgindex
= True
718 self
.dbapi
.cpv_inject(mycpv
)
719 if not self
.dbapi
._aux_cache_keys
.difference(d
):
720 aux_cache
= self
.dbapi
._aux_cache_slot_dict()
721 for k
in self
.dbapi
._aux_cache_keys
:
723 self
.dbapi
._aux_cache
[mycpv
] = aux_cache
725 if not os
.access(full_path
, os
.R_OK
):
726 writemsg(_("!!! Permission denied to read " \
727 "binary package: '%s'\n") % full_path
,
729 self
.invalids
.append(myfile
[:-5])
731 metadata_bytes
= portage
.xpak
.tbz2(full_path
).get_data()
732 mycat
= _unicode_decode(metadata_bytes
.get(b
"CATEGORY", ""),
733 encoding
=_encodings
['repo.content'], errors
='replace')
734 mypf
= _unicode_decode(metadata_bytes
.get(b
"PF", ""),
735 encoding
=_encodings
['repo.content'], errors
='replace')
736 slot
= _unicode_decode(metadata_bytes
.get(b
"SLOT", ""),
737 encoding
=_encodings
['repo.content'], errors
='replace')
739 if not mycat
or not mypf
or not slot
:
740 #old-style or corrupt package
741 writemsg(_("\n!!! Invalid binary package: '%s'\n") % full_path
,
745 missing_keys
.append("CATEGORY")
747 missing_keys
.append("PF")
749 missing_keys
.append("SLOT")
753 msg
.append(_("Missing metadata key(s): %s.") % \
754 ", ".join(missing_keys
))
755 msg
.append(_(" This binary package is not " \
756 "recoverable and should be deleted."))
757 for line
in textwrap
.wrap("".join(msg
), 72):
758 writemsg("!!! %s\n" % line
, noiselevel
=-1)
759 self
.invalids
.append(mypkg
)
761 mycat
= mycat
.strip()
763 if mycat
!= mydir
and mydir
!= "All":
765 if mypkg
!= mypf
.strip():
767 mycpv
= mycat
+ "/" + mypkg
768 if mycpv
in pkg_paths
:
769 # All is first, so it's preferred.
771 if not self
.dbapi
._category_re
.match(mycat
):
772 writemsg(_("!!! Binary package has an " \
773 "unrecognized category: '%s'\n") % full_path
,
775 writemsg(_("!!! '%s' has a category that is not" \
776 " listed in %setc/portage/categories\n") % \
777 (mycpv
, self
.settings
["PORTAGE_CONFIGROOT"]),
780 mycpv
= _pkg_str(mycpv
)
781 pkg_paths
[mycpv
] = mypath
782 self
.dbapi
.cpv_inject(mycpv
)
783 update_pkgindex
= True
784 d
= metadata
.get(mycpv
, {})
787 if long(d
["MTIME"]) != s
[stat
.ST_MTIME
]:
789 except (KeyError, ValueError):
793 if long(d
["SIZE"]) != long(s
.st_size
):
795 except (KeyError, ValueError):
800 d
["MTIME"] = str(s
[stat
.ST_MTIME
])
801 d
["SIZE"] = str(s
.st_size
)
803 d
.update(zip(self
._pkgindex_aux_keys
,
804 self
.dbapi
.aux_get(mycpv
, self
._pkgindex_aux_keys
)))
806 self
._eval_use_flags(mycpv
, d
)
807 except portage
.exception
.InvalidDependString
:
808 writemsg(_("!!! Invalid binary package: '%s'\n") % \
809 self
.getname(mycpv
), noiselevel
=-1)
810 self
.dbapi
.cpv_remove(mycpv
)
813 # record location if it's non-default
814 if mypath
!= mycpv
+ ".tbz2":
819 if not self
.dbapi
._aux_cache_keys
.difference(d
):
820 aux_cache
= self
.dbapi
._aux_cache_slot_dict()
821 for k
in self
.dbapi
._aux_cache_keys
:
823 self
.dbapi
._aux_cache
[mycpv
] = aux_cache
825 for cpv
in list(metadata
):
826 if cpv
not in pkg_paths
:
829 # Do not bother to write the Packages index if $PKGDIR/All/ exists
830 # since it will provide no benefit due to the need to read CATEGORY
832 if update_pkgindex
and os
.access(self
.pkgdir
, os
.W_OK
):
833 del pkgindex
.packages
[:]
834 pkgindex
.packages
.extend(iter(metadata
.values()))
835 self
._update_pkgindex_header(pkgindex
.header
)
836 self
._pkgindex_write(pkgindex
)
838 if getbinpkgs
and not self
.settings
["PORTAGE_BINHOST"]:
839 writemsg(_("!!! PORTAGE_BINHOST unset, but use is requested.\n"),
842 if not getbinpkgs
or 'PORTAGE_BINHOST' not in self
.settings
:
845 self
._remotepkgs
= {}
846 for base_url
in self
.settings
["PORTAGE_BINHOST"].split():
847 parsed_url
= urlparse(base_url
)
848 host
= parsed_url
.netloc
849 port
= parsed_url
.port
854 user
, host
= host
.split("@", 1)
855 user_passwd
= user
+ "@"
857 user
, passwd
= user
.split(":", 1)
860 port_str
= ":%s" % (port
,)
861 if host
.endswith(port_str
):
862 host
= host
[:-len(port_str
)]
863 pkgindex_file
= os
.path
.join(self
.settings
["EROOT"], CACHE_PATH
, "binhost",
864 host
, parsed_url
.path
.lstrip("/"), "Packages")
865 pkgindex
= self
._new_pkgindex()
867 f
= io
.open(_unicode_encode(pkgindex_file
,
868 encoding
=_encodings
['fs'], errors
='strict'),
869 mode
='r', encoding
=_encodings
['repo.content'],
875 except EnvironmentError as e
:
876 if e
.errno
!= errno
.ENOENT
:
878 local_timestamp
= pkgindex
.header
.get("TIMESTAMP", None)
879 remote_timestamp
= None
880 rmt_idx
= self
._new_pkgindex()
884 # urlparse.urljoin() only works correctly with recognized
885 # protocols and requires the base url to have a trailing
886 # slash, so join manually...
887 url
= base_url
.rstrip("/") + "/Packages"
890 # Don't use urlopen for https, since it doesn't support
891 # certificate/hostname verification (bug #469888).
892 if parsed_url
.scheme
not in ('https',):
894 f
= _urlopen(url
, if_modified_since
=local_timestamp
)
895 if hasattr(f
, 'headers') and f
.headers
.get('timestamp', ''):
896 remote_timestamp
= f
.headers
.get('timestamp')
897 except IOError as err
:
898 if hasattr(err
, 'code') and err
.code
== 304: # not modified (since local_timestamp)
899 raise UseCachedCopyOfRemoteIndex()
901 if parsed_url
.scheme
in ('ftp', 'http', 'https'):
902 # This protocol is supposedly supported by urlopen,
903 # so apparently there's a problem with the url
904 # or a bug in urlopen.
905 if self
.settings
.get("PORTAGE_DEBUG", "0") != "0":
906 traceback
.print_exc()
912 path
= parsed_url
.path
.rstrip("/") + "/Packages"
914 if parsed_url
.scheme
== 'ssh':
915 # Use a pipe so that we can terminate the download
916 # early if we detect that the TIMESTAMP header
917 # matches that of the cached Packages file.
920 ssh_args
.append("-p%s" % (port
,))
921 # NOTE: shlex evaluates embedded quotes
922 ssh_args
.extend(portage
.util
.shlex_split(
923 self
.settings
.get("PORTAGE_SSH_OPTS", "")))
924 ssh_args
.append(user_passwd
+ host
)
925 ssh_args
.append('--')
926 ssh_args
.append('cat')
927 ssh_args
.append(path
)
929 proc
= subprocess
.Popen(ssh_args
,
930 stdout
=subprocess
.PIPE
)
933 setting
= 'FETCHCOMMAND_' + parsed_url
.scheme
.upper()
934 fcmd
= self
.settings
.get(setting
)
936 fcmd
= self
.settings
.get('FETCHCOMMAND')
938 raise EnvironmentError("FETCHCOMMAND is unset")
940 fd
, tmp_filename
= tempfile
.mkstemp()
941 tmp_dirname
, tmp_basename
= os
.path
.split(tmp_filename
)
945 "DISTDIR": tmp_dirname
,
946 "FILE": tmp_basename
,
950 for k
in ("PORTAGE_SSH_OPTS",):
952 fcmd_vars
[k
] = self
.settings
[k
]
956 success
= portage
.getbinpkg
.file_get(
957 fcmd
=fcmd
, fcmd_vars
=fcmd_vars
)
959 raise EnvironmentError("%s failed" % (setting
,))
960 f
= open(tmp_filename
, 'rb')
962 f_dec
= codecs
.iterdecode(f
,
963 _encodings
['repo.content'], errors
='replace')
965 rmt_idx
.readHeader(f_dec
)
966 if not remote_timestamp
: # in case it had not been read from HTTP header
967 remote_timestamp
= rmt_idx
.header
.get("TIMESTAMP", None)
968 if not remote_timestamp
:
969 # no timestamp in the header, something's wrong
971 writemsg(_("\n\n!!! Binhost package index " \
972 " has no TIMESTAMP field.\n"), noiselevel
=-1)
974 if not self
._pkgindex_version_supported(rmt_idx
):
975 writemsg(_("\n\n!!! Binhost package index version" \
976 " is not supported: '%s'\n") % \
977 rmt_idx
.header
.get("VERSION"), noiselevel
=-1)
979 elif local_timestamp
!= remote_timestamp
:
980 rmt_idx
.readBody(f_dec
)
983 # Timeout after 5 seconds, in case close() blocks
984 # indefinitely (see bug #350139).
987 AlarmSignal
.register(5)
990 AlarmSignal
.unregister()
992 writemsg("\n\n!!! %s\n" % \
993 _("Timed out while closing connection to binhost"),
995 except UseCachedCopyOfRemoteIndex
:
996 writemsg_stdout("\n")
998 colorize("GOOD", _("Local copy of remote index is up-to-date and will be used.")) + \
1001 except EnvironmentError as e
:
1002 writemsg(_("\n\n!!! Error fetching binhost package" \
1003 " info from '%s'\n") % _hide_url_passwd(base_url
))
1004 writemsg("!!! %s\n\n" % str(e
))
1007 if proc
is not None:
1008 if proc
.poll() is None:
1012 if tmp_filename
is not None:
1014 os
.unlink(tmp_filename
)
1017 if pkgindex
is rmt_idx
:
1018 pkgindex
.modified
= False # don't update the header
1020 ensure_dirs(os
.path
.dirname(pkgindex_file
))
1021 f
= atomic_ofstream(pkgindex_file
)
1024 except (IOError, PortageException
):
1025 if os
.access(os
.path
.dirname(pkgindex_file
), os
.W_OK
):
1027 # The current user doesn't have permission to cache the
1028 # file, but that's alright.
1030 # Organize remote package list as a cpv -> metadata map.
1031 remotepkgs
= _pkgindex_cpv_map_latest_build(pkgindex
)
1032 remote_base_uri
= pkgindex
.header
.get("URI", base_url
)
1033 for cpv
, remote_metadata
in remotepkgs
.items():
1034 remote_metadata
["BASE_URI"] = remote_base_uri
1035 self
._pkgindex_uri
[cpv
] = url
1036 self
._remotepkgs
.update(remotepkgs
)
1037 self
._remote_has_index
= True
1038 for cpv
in remotepkgs
:
1039 self
.dbapi
.cpv_inject(cpv
)
1041 # Remote package instances override local package
1042 # if they are not identical.
1043 hash_names
= ["SIZE"] + self
._pkgindex_hashes
1044 for cpv
, local_metadata
in metadata
.items():
1045 remote_metadata
= self
._remotepkgs
.get(cpv
)
1046 if remote_metadata
is None:
1048 # Use digests to compare identity.
1050 for hash_name
in hash_names
:
1051 local_value
= local_metadata
.get(hash_name
)
1052 if local_value
is None:
1054 remote_value
= remote_metadata
.get(hash_name
)
1055 if remote_value
is None:
1057 if local_value
!= remote_value
:
1061 del self
._remotepkgs
[cpv
]
1063 # Override the local package in the aux_get cache.
1064 self
.dbapi
._aux_cache
[cpv
] = remote_metadata
1066 # Local package instances override remote instances.
1067 for cpv
in metadata
:
1068 self
._remotepkgs
.pop(cpv
, None)
1072 def inject(self
, cpv
, filename
=None):
1073 """Add a freshly built package to the database. This updates
1074 $PKGDIR/Packages with the new package metadata (including MD5).
1075 @param cpv: The cpv of the new package to inject
1077 @param filename: File path of the package to inject, or None if it's
1078 already in the location returned by getname()
1079 @type filename: string
1082 mycat
, mypkg
= catsplit(cpv
)
1083 if not self
.populated
:
1085 if filename
is None:
1086 full_path
= self
.getname(cpv
)
1088 full_path
= filename
1090 s
= os
.stat(full_path
)
1091 except OSError as e
:
1092 if e
.errno
!= errno
.ENOENT
:
1095 writemsg(_("!!! Binary package does not exist: '%s'\n") % full_path
,
1098 mytbz2
= portage
.xpak
.tbz2(full_path
)
1099 slot
= mytbz2
.getfile("SLOT")
1101 writemsg(_("!!! Invalid binary package: '%s'\n") % full_path
,
1105 self
.dbapi
.cpv_inject(cpv
)
1107 # Reread the Packages index (in case it's been changed by another
1108 # process) and then updated it, all while holding a lock.
1109 pkgindex_lock
= None
1110 created_symlink
= False
1112 pkgindex_lock
= lockfile(self
._pkgindex_file
,
1114 if filename
is not None:
1115 new_filename
= self
.getname(cpv
)
1117 samefile
= os
.path
.samefile(filename
, new_filename
)
1121 self
._ensure_dir(os
.path
.dirname(new_filename
))
1122 _movefile(filename
, new_filename
, mysettings
=self
.settings
)
1123 full_path
= new_filename
1125 self
._file_permissions(full_path
)
1127 if self
._all_directory
and \
1128 self
.getname(cpv
).split(os
.path
.sep
)[-2] == "All":
1129 self
._create_symlink(cpv
)
1130 created_symlink
= True
1131 pkgindex
= self
._load_pkgindex()
1133 if not self
._pkgindex_version_supported(pkgindex
):
1134 pkgindex
= self
._new_pkgindex()
1136 # Discard remote metadata to ensure that _pkgindex_entry
1137 # gets the local metadata. This also updates state for future
1139 if self
._remotepkgs
is not None:
1140 self
._remotepkgs
.pop(cpv
, None)
1142 # Discard cached metadata to ensure that _pkgindex_entry
1143 # doesn't return stale metadata.
1144 self
.dbapi
._aux_cache
.pop(cpv
, None)
1147 d
= self
._pkgindex_entry(cpv
)
1148 except portage
.exception
.InvalidDependString
:
1149 writemsg(_("!!! Invalid binary package: '%s'\n") % \
1150 self
.getname(cpv
), noiselevel
=-1)
1151 self
.dbapi
.cpv_remove(cpv
)
1152 del self
._pkg_paths
[cpv
]
1155 # If found, remove package(s) with duplicate path.
1156 path
= d
.get("PATH", "")
1157 for i
in range(len(pkgindex
.packages
) - 1, -1, -1):
1158 d2
= pkgindex
.packages
[i
]
1159 if path
and path
== d2
.get("PATH"):
1160 # Handle path collisions in $PKGDIR/All
1161 # when CPV is not identical.
1162 del pkgindex
.packages
[i
]
1163 elif cpv
== d2
.get("CPV"):
1164 if path
== d2
.get("PATH", ""):
1165 del pkgindex
.packages
[i
]
1166 elif created_symlink
and not d2
.get("PATH", ""):
1167 # Delete entry for the package that was just
1168 # overwritten by a symlink to this package.
1169 del pkgindex
.packages
[i
]
1171 pkgindex
.packages
.append(d
)
1173 self
._update_pkgindex_header(pkgindex
.header
)
1174 self
._pkgindex_write(pkgindex
)
1178 unlockfile(pkgindex_lock
)
1180 def _pkgindex_write(self
, pkgindex
):
1181 contents
= codecs
.getwriter(_encodings
['repo.content'])(io
.BytesIO())
1182 pkgindex
.write(contents
)
1183 contents
= contents
.getvalue()
1184 atime
= mtime
= long(pkgindex
.header
["TIMESTAMP"])
1185 output_files
= [(atomic_ofstream(self
._pkgindex_file
, mode
="wb"),
1186 self
._pkgindex_file
, None)]
1188 if "compress-index" in self
.settings
.features
:
1189 gz_fname
= self
._pkgindex_file
+ ".gz"
1190 fileobj
= atomic_ofstream(gz_fname
, mode
="wb")
1191 output_files
.append((GzipFile(filename
='', mode
="wb",
1192 fileobj
=fileobj
, mtime
=mtime
), gz_fname
, fileobj
))
1194 for f
, fname
, f_close
in output_files
:
1197 if f_close
is not None:
1199 self
._file_permissions(fname
)
1200 # some seconds might have elapsed since TIMESTAMP
1201 os
.utime(fname
, (atime
, mtime
))
1203 def _pkgindex_entry(self
, cpv
):
1205 Performs checksums and evaluates USE flag conditionals.
1206 Raises InvalidDependString if necessary.
1208 @return: a dict containing entry for the give cpv.
1211 pkg_path
= self
.getname(cpv
)
1213 d
= dict(zip(self
._pkgindex_aux_keys
,
1214 self
.dbapi
.aux_get(cpv
, self
._pkgindex_aux_keys
)))
1216 d
.update(perform_multiple_checksums(
1217 pkg_path
, hashes
=self
._pkgindex_hashes
))
1220 st
= os
.stat(pkg_path
)
1221 d
["MTIME"] = str(st
[stat
.ST_MTIME
])
1222 d
["SIZE"] = str(st
.st_size
)
1224 rel_path
= self
._pkg_paths
[cpv
]
1225 # record location if it's non-default
1226 if rel_path
!= cpv
+ ".tbz2":
1227 d
["PATH"] = rel_path
1229 self
._eval_use_flags(cpv
, d
)
1232 def _new_pkgindex(self
):
1233 return portage
.getbinpkg
.PackageIndex(
1234 allowed_pkg_keys
=self
._pkgindex_allowed_pkg_keys
,
1235 default_header_data
=self
._pkgindex_default_header_data
,
1236 default_pkg_data
=self
._pkgindex_default_pkg_data
,
1237 inherited_keys
=self
._pkgindex_inherited_keys
,
1238 translated_keys
=self
._pkgindex_translated_keys
)
1240 def _update_pkgindex_header(self
, header
):
1241 portdir
= normalize_path(os
.path
.realpath(self
.settings
["PORTDIR"]))
1242 profiles_base
= os
.path
.join(portdir
, "profiles") + os
.path
.sep
1243 if self
.settings
.profile_path
:
1244 profile_path
= normalize_path(
1245 os
.path
.realpath(self
.settings
.profile_path
))
1246 if profile_path
.startswith(profiles_base
):
1247 profile_path
= profile_path
[len(profiles_base
):]
1248 header
["PROFILE"] = profile_path
1249 header
["VERSION"] = str(self
._pkgindex_version
)
1250 base_uri
= self
.settings
.get("PORTAGE_BINHOST_HEADER_URI")
1252 header
["URI"] = base_uri
1254 header
.pop("URI", None)
1255 for k
in self
._pkgindex_header_keys
:
1256 v
= self
.settings
.get(k
, None)
1262 def _pkgindex_version_supported(self
, pkgindex
):
1263 version
= pkgindex
.header
.get("VERSION")
1266 if int(version
) <= self
._pkgindex_version
:
1272 def _eval_use_flags(self
, cpv
, metadata
):
1273 use
= frozenset(metadata
["USE"].split())
1275 iuse
= set(f
.lstrip("-+") for f
in metadata
["IUSE"].split())
1276 use
= [f
for f
in use
if f
in iuse
]
1278 metadata
["USE"] = " ".join(use
)
1279 for k
in self
._pkgindex_use_evaluated_keys
:
1280 if k
.endswith('DEPEND'):
1287 deps
= use_reduce(deps
, uselist
=raw_use
, token_class
=token_class
)
1288 deps
= paren_enclose(deps
)
1289 except portage
.exception
.InvalidDependString
as e
:
1290 writemsg("%s: %s\n" % (k
, str(e
)),
1295 def exists_specific(self
, cpv
):
1296 if not self
.populated
:
1298 return self
.dbapi
.match(
1299 dep_expand("="+cpv
, mydb
=self
.dbapi
, settings
=self
.settings
))
1301 def dep_bestmatch(self
, mydep
):
1302 "compatibility method -- all matches, not just visible ones"
1303 if not self
.populated
:
1306 writemsg("mydep: %s\n" % mydep
, 1)
1307 mydep
= dep_expand(mydep
, mydb
=self
.dbapi
, settings
=self
.settings
)
1308 writemsg("mydep: %s\n" % mydep
, 1)
1309 mykey
= dep_getkey(mydep
)
1310 writemsg("mykey: %s\n" % mykey
, 1)
1311 mymatch
= best(match_from_list(mydep
,self
.dbapi
.cp_list(mykey
)))
1312 writemsg("mymatch: %s\n" % mymatch
, 1)
1317 def getname(self
, pkgname
):
1318 """Returns a file location for this package. The default location is
1319 ${PKGDIR}/All/${PF}.tbz2, but will be ${PKGDIR}/${CATEGORY}/${PF}.tbz2
1320 in the rare event of a collision. The prevent_collision() method can
1321 be called to ensure that ${PKGDIR}/All/${PF}.tbz2 is available for a
1323 if not self
.populated
:
1326 mypath
= self
._pkg_paths
.get(mycpv
, None)
1328 return os
.path
.join(self
.pkgdir
, mypath
)
1329 mycat
, mypkg
= catsplit(mycpv
)
1330 if self
._all_directory
:
1331 mypath
= os
.path
.join("All", mypkg
+ ".tbz2")
1332 if mypath
in self
._pkg_paths
.values():
1333 mypath
= os
.path
.join(mycat
, mypkg
+ ".tbz2")
1335 mypath
= os
.path
.join(mycat
, mypkg
+ ".tbz2")
1336 self
._pkg_paths
[mycpv
] = mypath
# cache for future lookups
1337 return os
.path
.join(self
.pkgdir
, mypath
)
1339 def isremote(self
, pkgname
):
1340 """Returns true if the package is kept remotely and it has not been
1341 downloaded (or it is only partially downloaded)."""
1342 if self
._remotepkgs
is None or pkgname
not in self
._remotepkgs
:
1344 # Presence in self._remotepkgs implies that it's remote. When a
1345 # package is downloaded, state is updated by self.inject().
1348 def get_pkgindex_uri(self
, pkgname
):
1349 """Returns the URI to the Packages file for a given package."""
1350 return self
._pkgindex_uri
.get(pkgname
)
1354 def gettbz2(self
, pkgname
):
1355 """Fetches the package from a remote site, if necessary. Attempts to
1356 resume if the file appears to be partially downloaded."""
1357 tbz2_path
= self
.getname(pkgname
)
1358 tbz2name
= os
.path
.basename(tbz2_path
)
1360 if os
.path
.exists(tbz2_path
):
1361 if tbz2name
[:-5] not in self
.invalids
:
1365 writemsg(_("Resuming download of this tbz2, but it is possible that it is corrupt.\n"),
1368 mydest
= os
.path
.dirname(self
.getname(pkgname
))
1369 self
._ensure_dir(mydest
)
1370 # urljoin doesn't work correctly with unrecognized protocols like sftp
1371 if self
._remote_has_index
:
1372 rel_url
= self
._remotepkgs
[pkgname
].get("PATH")
1374 rel_url
= pkgname
+".tbz2"
1375 remote_base_uri
= self
._remotepkgs
[pkgname
]["BASE_URI"]
1376 url
= remote_base_uri
.rstrip("/") + "/" + rel_url
.lstrip("/")
1378 url
= self
.settings
["PORTAGE_BINHOST"].rstrip("/") + "/" + tbz2name
1379 protocol
= urlparse(url
)[0]
1380 fcmd_prefix
= "FETCHCOMMAND"
1382 fcmd_prefix
= "RESUMECOMMAND"
1383 fcmd
= self
.settings
.get(fcmd_prefix
+ "_" + protocol
.upper())
1385 fcmd
= self
.settings
.get(fcmd_prefix
)
1386 success
= portage
.getbinpkg
.file_get(url
, mydest
, fcmd
=fcmd
)
1389 os
.unlink(self
.getname(pkgname
))
1392 raise portage
.exception
.FileNotFound(mydest
)
1393 self
.inject(pkgname
)
1395 def _load_pkgindex(self
):
1396 pkgindex
= self
._new_pkgindex()
1398 f
= io
.open(_unicode_encode(self
._pkgindex_file
,
1399 encoding
=_encodings
['fs'], errors
='strict'),
1400 mode
='r', encoding
=_encodings
['repo.content'],
1402 except EnvironmentError:
1411 def _get_digests(self
, pkg
):
1415 except AttributeError:
1420 if self
._remotepkgs
is None or cpv
not in self
._remotepkgs
:
1421 for d
in self
._load_pkgindex().packages
:
1426 metadata
= self
._remotepkgs
[cpv
]
1427 if metadata
is None:
1430 for k
in hashfunc_map
:
1436 if "SIZE" in metadata
:
1438 digests
["size"] = int(metadata
["SIZE"])
1440 writemsg(_("!!! Malformed SIZE attribute in remote " \
1441 "metadata for '%s'\n") % cpv
)
1445 def digestCheck(self
, pkg
):
1447 Verify digests for the given package and raise DigestException
1448 if verification fails.
1450 @return: True if digests could be located, False otherwise.
1453 digests
= self
._get_digests(pkg
)
1460 except AttributeError:
1463 pkg_path
= self
.getname(cpv
)
1464 hash_filter
= _hash_filter(
1465 self
.settings
.get("PORTAGE_CHECKSUM_FILTER", ""))
1466 if not hash_filter
.transparent
:
1467 digests
= _apply_hash_filter(digests
, hash_filter
)
1469 eout
.quiet
= self
.settings
.get("PORTAGE_QUIET") == "1"
1470 ok
, st
= _check_distfile(pkg_path
, digests
, eout
, show_errors
=0)
1472 ok
, reason
= verify_all(pkg_path
, digests
)
1474 raise portage
.exception
.DigestException(
1475 (pkg_path
,) + tuple(reason
))
1479 def getslot(self
, mycatpkg
):
1480 "Get a slot for a catpkg; assume it exists."
1483 myslot
= self
.dbapi
._pkg_str(mycatpkg
, None).slot