manifest.py revision 3041
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
import errno
import fnmatch
import hashlib
import os
import re
import tempfile
from operator import itemgetter
def _compile_fnpats(fn_pats):
"""Private helper function that returns a compiled version of a
dictionary of fnmatch patterns."""
return dict(
(key, [
])
)
"""Private helper function: given an action, return True if any of its
attributes' values matches the pattern for the same attribute in the
attr_match dictionary, and False otherwise. Note that the patterns must
be pre-comiled using re.compile() or _compile_fnpats."""
if not attr_match:
return True
return True
return False
class ManifestDifference(
__slots__ = []
__state__desc = tuple([
])
])
"""Returns the serialized state of this object in a format
that that can be easily stored using JSON, pickle, etc."""
"""Allocate a new object using previously serialized state
obtained via getstate()."""
# decode serialized state into python objects
return ManifestDifference(*state)
"""A Manifest is the representation of the actions composing a specific
package version on both the client and the repository. Both purposes
utilize the same storage format.
The serialized structure of a manifest is an unordered list of actions.
The special action, "set", represents a package attribute.
The reserved attribute, "fmri", represents the package and version
described by this manifest. It is available as a string via the
attributes dictionary, and as an FMRI object from the fmri member.
The list of manifest-wide reserved attributes is
base_directory Default base directory, for non-user images.
fmri Package FMRI.
isa Package is intended for a list of ISAs.
platform Package is intended for a list of platforms.
relocatable Suitable for User Image.
All non-prefixed attributes are reserved to the framework. Third
parties may prefix their attributes with a reversed domain name, domain
name, or stock symbol. An example might be
com.example,supported
as an indicator that a specific package version is supported by the
vendor, example.com.
manifest.null is provided as the null manifest. Differences against the
null manifest result in the complete set of attributes and actions of
the non-null manifest, meaning that all operations can be viewed as
tranitions between the manifest being installed and the manifest already
present in the image (which may be the null manifest).
"""
self._absent_cache = []
self.actions_bytype = {}
r = ""
r += "%s\n" % act
return r
"""A generator function that returns the unsorted manifest
contents as lines of text."""
yield "%s\n" % act
def tostr_unsorted(self):
"""Return three lists of action pairs representing origin and
destination actions. The first list contains the pairs
representing additions, the second list contains the pairs
representing updates, and the third list contains the pairs
representing removals. All three lists are in the order in
which they should be executed."""
# XXX Do we need to find some way to assert that the keys are
# all unique?
# No origin was provided, so nothing has been changed or
# removed; only added. In addition, this doesn't need
# to be sorted since the caller likely already does
return ManifestDifference(
[(None, a) for a in self.gen_actions(
excludes=self_exclude)], [], [])
def hashify(v):
"""handle key values that may be lists"""
return v
return tuple(v)
# Transform list of actions into a dictionary keyed by
# action key attribute, key attribute and mediator, or
# id if there is no key attribute.
if (a.name == "link" or
a.name == "hardlink") and \
]))
else:
yield (akey, a)
changed = [
]
# XXX Do changed actions need to be sorted at all? This is
# likely to be the largest list, so we might save significant
# time by not sorting. Should we sort above? Insert into a
# sorted list?
# singlesort = lambda x: x[0] or x[1]
"""Like the unix utility comm, except that this function
takes an arbitrary number of manifests and compares them,
returning a tuple consisting of each manifest's actions
that are not the same for all manifests, followed by a
list of actions that are the same in each manifest."""
# Must specify at least one manifest.
assert compare_m
dups = []
# construct list of dictionaries of actions in each
# manifest, indexed by unique key and variant combination
m_dicts = []
for m in compare_m:
m_dict = {}
for a in m.gen_actions():
# The unique key for each action is based on its
# type, key attribute, and unique variants set
# on the action.
try:
"%s=%s" % (v, a.attrs[v])
for v in a.get_varcet_keys()[0]
)
except KeyError:
# If there is no key attribute for the
# action, then fallback to the object
# id for the action as its identifier.
# catch duplicate actions here...
if dups:
# construct list of key sets in each dict
m_sets = [
for m in m_dicts
]
# determine which common_keys have common actions
for k in common_keys.copy():
m_dicts[i + 1][k]):
break
return tuple(
[
]
+
[
]
)
"""Where difference() returns three lists, combined_difference()
returns a single list of the concatenation of the three."""
"""Output expects that self is newer than other. Use of sets
requires that we convert the action objects into some marshalled
form, otherwise set member identities are derived from the
object pointers, rather than the contents."""
out = ""
if not src:
elif not dest:
else:
return out
def _gen_dirs_to_str(self):
"""Generate contents of dircache file containing all dirctories
referenced explicitly or implicitly from self.actions. Include
variants as values; collapse variants where possible."""
def gen_references(a):
for d in expanddirs(a.directory_references()):
yield d
for d in dirs:
for v in dirs[d]:
a = DirectoryAction(path=d, **v)
yield str(a) + "\n"
def _gen_mediators_to_str(self):
"""Generate contents of mediatorcache file containing all
mediators referenced explicitly or implicitly from self.actions.
Include variants as values; collapse variants where possible."""
def gen_references(a):
"mediator" in a.attrs:
values = {
}
a = "set name=pkg.mediator " \
" ".join((
"=".join(t)
if t[1]
)),
" ".join((
"=".join(t)
))
)
yield a
def _gen_attrs_to_str(self):
"""Generate set action supplemental data containing all facets
and variants from self.actions and size information. Each
returned line must be newline-terminated."""
# Package already has these attributes.
return
# List of possible variants and possible values for them.
# Seed with declared set of variants as actions may be common to
# both and so will not be tagged with variant.
# List of possible facets and under what variant combinations
# they were seen.
# Unique (facet, value) (variant, value) combinations.
for a in self.gen_actions():
if name == "set":
afacets = []
avariants = []
# Facet applicable to this particular variant
# combination.
# This *must* be sorted to ensure reproducible set
# action generation for sizes and to ensure each
# combination is actually unique.
if name == "signature":
# Prevent scope leak.
if emit_variants:
# Unnecessary if we can guarantee all variants will be
# declared at package level. Omit the "variant." prefix
# from attribute values since that's implicit and can be
# added back when the action is parsed.
# Emit a set action for every variant used with possible values
# if one does not already exist.
# merge_facets needs the variant values sorted and this
# is desirable when generating the variant attr anyway.
if emit_facets:
# Get unvarianted facet set.
# For each variant combination, remove unvarianted
# facets since they are common to all variants.
if not fnames:
# No facets unique to this combo;
# discard.
# If all possible variant combinations supported by the
# package have at least one facet, then the intersection
# of facets for all variants can be merged with the
# common set.
if merge_facets:
# Determine unique set of variant combinations
# seen for faceted actions.
vpair[0]
)
))
# For each unique variant combination, determine
# if the cartesian product of all variant values
# supported by the package for the combination
# has been seen. In other words, if the
# combination is ((variant.arch,)) and the
# package supports (i386, sparc), then both
# (variant.arch, i386) and (variant.arch, sparc)
# must exist. This code assumes variant values
# for each variant are already sorted.
product(*(
)
):
# If any combination the package
# supports has not been seen for
# one or more facets, then some
# facets are unique to one or
# more combinations.
break
if merge_facets:
# Merge the facets common to all variants if safe;
# if we always merged them, then facets only
# used by a single variant (think i386-only or
# sparc-only content) would be seen unvarianted
# (that's bad).
if vcfacets:
# At least one facet is shared between
# all variant combinations; move the
# common ones to the unvarianted set.
# Remove facets common to all combos.
if not fnames:
# No facets unique to
# this combo; discard.
# Omit the "facet." prefix from attribute values since
# that's implicit and can be added back when the action
# is parsed.
if not val:
# If we don't do this, action stringify will
# emit this as "set name=pkg.facet" which is
# then transformed to "set name=name
# value=pkg.facet". Not what we wanted, but is
# expected for historical reasons.
val = ""
# Always emit an action enumerating the list of facets
# common to all variants, even if there aren't any.
# That way if there are also no variant-specific facets,
# package operations will know that no facets are used
# by the package instead of having to scan the whole
# manifest.
yield "%s\n" % AttributeAction(None,
# Now emit a pkg.facet action for each variant
# combination containing the list of facets unique to
# that combination.
# A unique key for each combination is needed,
# and using a hash obfuscates that interface
# while giving us a reliable way to generate
# a reproducible, unique identifier. The key
# string below looks like this before hashing:
# variant.archi386variant.debug.osnetTrue...
).hexdigest()
# Omit the "facet." prefix from attribute values
# since that's implicit and can be added back
# when the action is parsed.
act = AttributeAction(None,
# Tag action with variants.
for v in varkey:
yield "%s\n" % act
# Emit pkg.[c]size attribute for [compressed] size of package
csize = 0
size = 0
for varcetkeys in refs:
if not varcetkeys:
# For unfaceted/unvarianted actions, keep a
# running total so a single [c]size action can
# be generated.
continue
# Only emit if > 0; actions may be
# A unique key for each combination is needed,
# and using a hash obfuscates that interface
# while giving us a reliable way to generate
# a reproducible, unique identifier. The key
# string below looks like this before hashing:
# facet.docTruevariant.archi386...
).hexdigest()
# The sizes are abbreviated in the name of byte
# conservation.
act = AttributeAction(None,
for v in varcetkeys:
yield "%s\n" % act
if emit_sizes:
yield "%s\n" % act
"""create dictionary of all actions referenced explicitly or
implicitly from self.actions... include variants as values;
collapse variants where possible"""
refs = {}
# build a dictionary containing all actions tagged w/
# variants
v, f = a.get_varcet_keys()
for ref in references(a):
# remove any tags if any entries are always delivered (NULL)
continue
# could collapse refs where all variants are present
# (the current logic only collapses them if at least
# one reference is delivered without a facet or
# variant)
return refs
""" return a list of directories implicitly or
explicitly referenced by this object"""
try:
except KeyError:
# generate actions that contain directories
for s in self._gen_dirs_to_str()
]
s = set([
a.attrs["path"]
for a in alist
])
return list(s)
"""A generator function that returns the supported facet
attributes (strings) for this package based on the specified (or
current) excludes that also match at least one of the patterns
provided. Facets must be true or false so a list of possible
facet values is not returned."""
try:
except KeyError:
facets = None
# No excludes? Then use the pre-determined set of
# facets.
yield f
return
# If different excludes were specified, then look for pkg.facet
# actions containing the list of facets.
# Either a pkg.facet.common action or a
# pkg.facet.X variant-specific action.
# No facets.
continue
"facet.%s" % n
for n in val
), patterns):
if f in seen:
# Prevent duplicates; it's
# possible a given facet may be
# valid for more than one unique
# variant combination that's
# allowed by current excludes.
continue
yield f
if not found:
# Fallback to sifting actions to yield possible.
yield f
"""A generator function that yields a list of tuples of the form
(variant, [values]). Where 'variant' is the variant attribute
name (e.g. 'variant.arch') and '[values]' is a list of the
variant values supported by this package. Variants returned are
those allowed by the specified (or current) excludes that also
match at least one of the patterns provided."""
try:
except KeyError:
variants = None
# No excludes? Then use the pre-determined set of
# variants.
patterns):
return
# If different excludes were specified, then look for
# pkg.variant action containing the list of variants.
if aname == "pkg.variant":
# No variants.
return
for v in val:
# Ensure variant entries exist (debug
# variants may not) via defaultdict.
variants["variant.%s" % v]
for v in a.attrlist("value"):
if not found:
# Fallback to sifting actions to get possible.
yield v, variants[v]
"""A generator function that yields tuples of the form (mediator,
mediations) expressing the set of possible mediations for this
package, where 'mediations' is a set() of possible mediations for
the mediator. Each mediation is a tuple of the form (priority,
version, implementation).
"""
try:
except KeyError:
# generate actions that contain mediators
for s in self._gen_mediators_to_str()
]
for attrs in (
if med_ver:
try:
except version.VersionError:
# Consider this mediation unavailable
# if it can't be parsed for whatever
# reason.
continue
))
for m in ret:
yield m, ret[m]
"""Generate actions in manifest through ordered callable list"""
if attr_match:
for c in excludes:
if not c(a):
break
else:
# These conditions are split by performance.
if not attr_match:
yield a
elif _attr_matches(a, attr_match):
yield a
"""Generate actions in the manifest of type "type"
through ordered callable list"""
if attr_match:
for c in excludes:
if not c(a):
break
else:
# These conditions are split by performance.
if not attr_match:
yield a
elif _attr_matches(a, attr_match):
yield a
"""Generate actions in the manifest of types "atypes"
through ordered callable list."""
yield a
"""Generate the value of the key attribute for each action
of type "type" in the manifest."""
return (
)
"""Find actions in the manifest which are duplicates (i.e.,
represent the same object) but which are not identical (i.e.,
have all the same attributes)."""
def fun(a):
"""Return a key on which actions can be sorted."""
alldups = []
if dups:
return alldups
accumulate = ""
lineno = 0
errors = []
# Get an iterable for the string.
for l in content:
lineno += 1
l = l.lstrip()
continue
elif accumulate:
l = accumulate + l
accumulate = ""
if not l or l[0] == "#": # ignore blank lines & comments
continue
try:
except actions.ActionError, e:
# Accumulate errors and continue so that as
# much of the action data as possible can be
# parsed.
if errors:
"""Populate the manifest with actions.
'content' is an optional value containing either the text
representation of the manifest or an iterable of
action objects.
'excludes' is optional. If provided it must be a length two
list with the variants to be excluded as the first element and
the facets to be excluded as the second element.
'pathname' is an optional filename containing the location of
the manifest content.
'signatures' is an optional boolean value that indicates whether
a manifest signature should be generated. This is only possible
when 'content' is a string or 'pathname' is provided.
"""
self.actions_bytype = {}
self.attributes = {}
self._absent_cache = []
# sdict and odict in difference() above, and have that be our
# main datastore, rather than the simple list we have now. If
# we do that here, we can even assert that the "same" action
# can't be in a manifest twice. (The problem of having the same
# action more than once in packages that can be installed
# together has to be solved somewhere else, though.)
if pathname:
try:
except EnvironmentError, e:
raise apx._convert_error(e)
if signatures:
# Generate manifest signature based upon
# input content, but only if signatures
# were requested. In order to interoperate with
# older clients, we must use sha-1 here.
self.signatures = {
}
# Make sure that either no excludes were provided or that both
# variants and facet excludes were.
"""Remove any actions from the manifest which should be
excluded."""
"""Performs any needed transformations on the action then adds
it to the manifest.
The "action" parameter is the action object that should be
added to the manifest.
The "excludes" parameter is the variants to exclude from the
manifest."""
# XXX handle legacy transition issues; not needed once support
# for upgrading images from older releases (< build 151) has
# been removed.
if "opensolaris.zone" in attrs and \
"variant.opensolaris.zone" not in attrs:
attrs["variant.opensolaris.zone"] = \
attrs["opensolaris.zone"]
# Translate old action to new.
return
try:
except KeyError:
# add any set actions to attributes
if aname == "set":
"""Fill attribute array w/ set action contents."""
try:
# To reduce manifest bloat, size and csize
# are set on a single action so need splitting
# into separate attributes.
if szname == "sz":
szname = "pkg.size"
elif szname == "csz":
szname = "pkg.csize"
else:
# Skip unknowns.
continue
return
# ignore broken set actions
pass
# Ensure facet and variant attributes are always lists.
# Possible facets list is spread over multiple actions.
# No facets.
val = []
for f in val:
entry = "facet.%s" % f
# Prevent duplicates; it's possible a
# given facet may be valid for more than
# one unique variant combination that's
# allowed by current excludes.
return
elif keyvalue == "pkg.variant":
# No variants.
val = []
"variant.%s" % v
for v in val
]
return
return
if keyvalue == "fmri":
# Ancient manifest compatibility.
keyvalue = "pkg.fmri"
log=None):
"""Produces the search dictionary for a specific manifest.
A dictionary is constructed which maps a tuple of token,
action type, key, and the value that matched the token to
the byte offset into the manifest file. file_path is the
path to the manifest file. excludes is the variants which
should be allowed in this image. return_line is a debugging
flag which makes the function map the information to the
string of the line, rather than the byte offset to allow
easier debugging."""
if log is None:
log = lambda x: None
try:
except EnvironmentError, e:
raise
log((_("%(fp)s:\n%(e)s") %
return {}
cur_pos = 0
action_dict = {}
"""Translates what actions.generate_indices produces
into a dictionary mapping token, action_name, key, and
the value that should be displayed for matching that
token to byte offsets into the manifest file.
The "lst" parameter is the data to be converted.
The "cp" parameter is the byte offset into the file
for the action which produced lst."""
if action_name == "set":
if full_value is None:
else:
if full_value is None:
if full_value is None:
(action_name, subtype, t,
for t in tok
], cp)
else:
full_value) in action_dict:
else:
while line:
if l and l[0] != "#":
try:
except actions.ActionError, e:
log((_("%(fp)s:\n%(e)s") %
else:
if not excludes or \
try:
except KeyError, k:
log(_("%(fp)s contains "
"an action which is"
" missing the "
"expected attribute"
": %(at)s.\nThe "
"action is:"
"%(act)s") %
{
"fp": file_path,
"act":l
})
else:
if return_line:
arg = l
return action_dict
def hash_create(mfstcontent):
"""This method takes a string representing the on-disk
manifest content, and returns a hash value."""
# This must be an SHA-1 hash in order to interoperate with
# older clients.
# Byte stream expected, so pass encoded.
else:
"""Verifies whether the signatures for the contents of
the manifest match the specified signature data. Raises
the 'BadManifestSignatures' exception on failure."""
"""Store the manifest contents to disk."""
try:
except EnvironmentError, e:
raise apx.ReadOnlyFileSystemException(
e.filename)
raise
try:
except EnvironmentError, e:
raise apx.ReadOnlyFileSystemException(
e.filename)
raise
#
# We specifically avoid sorting manifests before writing
# them to disk-- there's really no point in doing so, since
# we'll sort actions globally during packaging operations.
#
try:
except EnvironmentError, e:
raise apx.ReadOnlyFileSystemException(
e.filename)
raise
return None
return variants
return [variants]
def get_all_variants(self):
"""Return a dictionary mapping variant tags to their values."""
)))
try:
except KeyError:
return default
"""Returns the boolean of the value of the attribute 'key'."""
if ret == "true":
return True
elif ret == "false":
return False
else:
raise ValueError(_("Attribute value '%s' not 'true' or "
"'false'" % ret))
"""Returns an integer tuple of the form (size, csize), where
'size' represents the total uncompressed size, in bytes, of the
Manifest's data payload, and 'csize' represents the compressed
version of that.
'excludes' is a list of a list of variants and facets which
should be allowed when calculating the total."""
csize = 0
size = 0
# If specified excludes match loaded excludes, then use
# cached attributes; this is safe as manifest attributes
# are reset or updated every time exclude_content,
# set_content, or add_action is called.
# Cache for future calls.
if nexcludes:
# Facet filtering should never be applied when excluding
# actions; only variant filtering. This is ugly, but
# allow you to be selective and various bits in
# pkg.manifest assume you always filter on both so we
# have to fake up a filter for facets.
nexcludes = [
x for x in excludes
]
# Excludes list must always have zero or two items; so
# fake second entry.
# append any variants and facets to manifest dict
continue
try:
# While variants are package level (you
# can't install a package without
# setting the variant first), facets
# from the current action should only be
# included if the action is not
# excluded.
except TypeError:
# Lists can't be set elements.
_("%(forv)s '%(v)s' specified multiple times") %
"""Return the value for the package attribute 'key'."""
"""Set the value for the package attribute 'key' to 'value'."""
return
class FactoredManifest(Manifest):
"""This class serves as a wrapper for the Manifest class for callers
that need efficient access to package data on a per-action type basis.
It achieves this by partitioning the manifest into multiple files (one
per action type) and then storing an on-disk cache of the directories
explictly and implicitly referenced by the manifest each tagged with
pathname=None):
"""Raises KeyError exception if factored manifest is not present
and contents are None; delays reading of manifest until required
if cache file is present.
'fmri' is a PkgFmri object representing the identity of the
package.
'cache_root' is the pathname of the directory where the manifest
and cache files should be stored or loaded from.
'contents' is an optional string to use as the contents of the
manifest if a cached copy does not already exist.
'excludes' is optional. If provided it must be a length two
list with the variants to be excluded as the first element and
the facets to be exclduded as the second element.
'pathname' is an optional string containing the pathname of a
manifest. If not provided, it is assumed that the manifest is
stored in a file named 'manifest' in the directory indicated by
'cache_root'. If provided, and contents is also provided, then
'contents' will be stored in 'pathname' if it does not already
exist.
"""
# Make sure that either no excludes were provided or that both
# variants and facet excludes were.
# Do we have a cached copy?
if contents is None:
# we have no cached copy; save one
# don't specify excludes so on-disk copy has
# all variants
if self.__storeback():
if excludes:
return
# we have a cached copy of the manifest
# have we computed the dircache?
if self.__storeback():
if excludes:
return
"""Load all manifest contents from on-disk copy of manifest"""
"""Unload manifest; used to reduce peak memory comsumption
when downloading new manifests"""
self.actions_bytype = {}
self.attributes = {}
def __finiload(self):
"""Finish loading.... this part of initialization is common
to multiple code paths"""
def __storeback(self):
""" store the current action set; also create per-type
caches. Return True if data was saved, False if not"""
try:
return True
except apx.PermissionsException:
# this allows us to try to cache new manifests
# when non-root w/o failures.
return False
def __storebytype(self):
""" create manifest.<typename> files to accelerate partial
parsing of manifests. Separate from __storeback code to
allow upgrade to reuse existing on disk manifests"""
# Ensure target cache directory and intermediates exist.
# create per-action type cache; use rename to avoid corrupt
# files if ^C'd in the middle. All action types are considered
# so that empty cache files are created if no action of that
# type exists for the package (avoids full manifest loads
# later).
t_prefix = "manifest.%s." % n
try:
except EnvironmentError, e:
raise apx._convert_error(e)
try:
for a in acts:
f.write("%s\n" % a)
if n == "set":
# Add supplemental action data; yes this
# does mean the cache is not the same as
# retrieved manifest, but that's ok.
# Signature verification is done using
# the raw manifest.
except EnvironmentError, e:
raise apx._convert_error(e)
finally:
f.close()
try:
except EnvironmentError, e:
raise apx._convert_error(e)
try:
f.writelines(refs())
except EnvironmentError, e:
raise apx._convert_error(e)
create_cache("manifest.mediatorcache",
def clear_cache(cache_root):
"""Remove all manifest cache files found in the given directory
(excluding the manifest itself) and the cache_root if it is
empty afterwards.
"""
try:
continue
try:
cache_root, cname))
except EnvironmentError, e:
raise
# Ensure cache dir is removed if the last cache file is
# removed; we don't care if it fails.
try:
except:
pass
except EnvironmentError, e:
# Only raise error if failure wasn't due to
# cache directory not existing.
raise apx._convert_error(e)
"""Private helper function for loading arbitrary cached manifest
data.
"""
# we have cached copy on disk; use it
try:
a for a in
(
for s in f
)
]
return
except EnvironmentError, e:
raise apx._convert_error(e)
except actions.ActionError, e:
# Cache file is malformed; hopefully due to bugs
# that have been resolved (as opposed to actual
# corruption). Assume we should just ignore the
# cache and load action data.
try:
except Exception, e:
# Ignore errors encountered during cache
# dump for this specific case.
pass
# no cached copy
# need to load from disk
""" return a list of directories implicitly or explicitly
referenced by this object
"""
""" generate actions of the specified type;
use already in-memory stuff if already loaded,
otherwise use per-action types files"""
# invoke subclass method to generate action by action
yield a
return
# This checks if we've already written out the factored
# manifest files. If so, we'll use it, and if not, then
# we'll load the full manifest.
# no cached copy :-(
# get manifest from disk
# invoke subclass method to generate action by action
yield a
return
# No such action in the manifest; must be done *after*
# asserting excludes are correct to avoid hiding
# failures.
return
# Assume a cached copy exists; if not, tag the action type to
# avoid pointless I/O later.
if attr_match:
try:
for l in f:
if (excludes and
not a.include_this(excludes)):
continue
# These conditions are split by
# performance.
if not attr_match:
yield a
elif _attr_matches(a, attr_match):
yield a
except EnvironmentError, e:
return # no such action in this manifest
raise apx._convert_error(e)
"""A generator function that returns the supported facet
attributes (strings) for this package based on the specified (or
current) excludes that also match at least one of the patterns
provided. Facets must be true or false so a list of possible
facet values is not returned."""
"""A generator function that yields a list of tuples of the form
(variant, [values]). Where 'variant' is the variant attribute
name (e.g. 'variant.arch') and '[values]' is a list of the
variant values supported by this package. Variants returned are
those allowed by the specified (or current) excludes that also
match at least one of the patterns provided."""
"""A generator function that yields set actions expressing the
set of possible mediations for this package.
"""
def __load_attributes(self):
"""Load attributes dictionary from cached set actions;
this speeds up pkg info a lot"""
return False
for l in f:
return True
"""Returns an integer tuple of the form (size, csize), where
'size' represents the total uncompressed size, in bytes, of the
Manifest's data payload, and 'csize' represents the compressed
version of that.
'excludes' is a list of a list of variants and facets which
should be allowed when calculating the total."""
"""No assignments to factored manifests allowed."""
assert "FactoredManifests are not dicts"
try:
except KeyError:
return default
def get_all_variants(self):
"""Store the manifest contents to disk."""
"""The absolute pathname of the file containing the manifest."""
if self.__pathname:
return self.__pathname
class EmptyFactoredManifest(Manifest):
"""Special class for pkgplan's need for a empty manifest;
the regular null manifest doesn't support get_directories
and making the factored manifest code handle this case is
too ugly..."""
"""Return three lists of action pairs representing origin and
destination actions. The first list contains the pairs
representing additions, the second list contains the pairs
representing updates, and the third list contains the pairs
representing removals. All three lists are in the order in
which they should be executed."""
# The difference for this case is simply everything in the
# origin has been removed. This is an optimization for
# uninstall.
return ManifestDifference([], [],
def get_directories(excludes):
return []
# This method is overridden so that self.excludes is never set
# on the singleton NullFactoredManifest.
return
raise RuntimeError("Cannot call set_content on an "
"EmptyFactoredManifest")
class ManifestError(Exception):
"""Simple Exception class to handle manifest specific errors"""
ret = []
for d in self.__duplicates: