#
# 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
#
#
#
"""Action describing a package dependency.
This module contains the DependencyAction class, which represents a
relationship between the package containing the action and another package.
"""
from . import generic
import re
import six
known_types = (
"conditional",
"exclude",
"group",
"group-any",
"incorporate",
"optional",
"origin",
"parent",
"require",
"require-any")
#
# this is a special package name that when present in an fmri defines a
# dependency on the current package in which the dependency is present.
# this is useful with the "parent" dependency type.
#
"""Class representing a dependency packaging object. The fmri attribute
is expected to be the pkg FMRI that this package depends on. The type
attribute is one of these:
optional - optional dependency on minimum version of other package. In
other words, if installed, other packages must be at least at specified
version level.
require - dependency on minimum version of other package is needed
for correct function of this package.
conditional - dependency on minimum version of specified package
if predicate package is installed at specified version or newer.
require-any - dependency on minimum version of any of the specified
packages.
origin - specified package must be at this version or newer
in order to install this package; if root-image=true, dependency is
on version installed in / rather than image being modified.
parent - dependency on same version of this package being present in
the parent image. if the current image is not a child then this
dependency is ignored.
incorporate - optional dependency on precise version of other package;
non-specified portion of version is free to float.
exclude - package may not be installed together with named version
or higher - reverse logic of require.
group - a version of package is required unless stem is in image
avoid list; version part of fmri is ignored. Obsolete packages
are assumed to satisfy dependency.
group-any - dependency on at least one of the specified packages is
required unless stem is in image avoid list; version part of fmri is
ignored. Obsolete packages are assumed to satisfy dependency."""
__slots__ = []
# data cannot be specified as a keyword argument
# if we're not a linked child then ignore "parent"
# dependencies.
return []
# create a dictionary of packages installed in the parent
ppkgs_dict = dict([
(i.pkg_name, i)
])
errors = []
_("Package is not installed in "
return errors
# package is from a different publisher
"different publisher: {0}").
return errors
# parent dependency is satisfied
return []
else:
return errors
errors = []
if not installed_version:
return errors
_("{dep_type} dependency {dep_val} "
"is downrev ({inst_ver})").format(
return errors
_("{dep_type} dependency {dep_val} "
"is uprev ({inst_ver})").format(
return errors
_("{dep_type} dependency on an obsolete "
"package ({obs_pkg}); this package must "
"be uninstalled manually").format(
return errors
return errors
"""Returns a tuple of lists of the form (errors, warnings,
info). The error list will be empty if the action has been
correctly installed in the given image."""
errors = []
warnings = []
info = []
# the fmri for the package containing this action should
# include a publisher
# XXX Exclude and range between min and max not yet handled
def __min_version():
if ctype not in known_types:
_("Unknown type ({0}) in depend action").
# get a list of fmris and do fmri token substitution
pfmris = []
if f.pkg_name == DEPEND_SELF:
f = pfmri
if ctype == "parent":
# handle "parent" dependencies here
for f in pfmris
]
min_fmri = None
max_fmri = None
if ctype == "require":
elif ctype == "incorporate":
elif ctype == "optional":
elif ctype == "exclude":
elif ctype == "conditional":
if installed_cversion is not None and \
elif ctype == "group":
elif ctype == "group-any":
f.pkg_name for f in installed_versions
if f is not None)
group_stems = set(
# If there are stems for this group-any dependency not
# on the avoid list and none are installed, the
# group-any dependency has not been satisfied.
if group_stems and not matching_stems:
_("Group dependency on one of {0} not "
elif ctype == "require-any":
if ifmri and not e:
# this one is present and happy
return [], [], []
else:
if not errors: # none was installed
_("Required dependency on one of "
"{0} not met").
for p in pfmris))))
if ok:
return [], [], []
else:
if ok:
return [], [], []
else:
# do checking for other dependency types
if required and not installed_version:
# cannot verify origin since it applys to upgrade
# operation, not final state
"""Generates the indices needed by the search dictionary. See
generic.py for a more detailed explanation."""
if ctype not in known_types:
return []
#
# XXX Ideally, we'd turn the string into a PkgFmri, and
# separate the stem from the version, or use get_dir_path,
# but we can't create a PkgFmri without supplying a build
# release and without it creating a dummy timestamp.
# Instead we have to split it apart manually.
#
inds = []
for p in pfmris:
# Strip pkg:/ or pkg:/// from the fmri.
# If fmri has pkg:// then strip the prefix
# from 'pkg://' upto the first slash.
# Note that this creates a directory hierarchy!
("depend", ctype, p, None)
)
if "@" in p:
return inds
"""Write a dependency action across multiple lines. This is
designed to be used in exceptions for cleaner printing of
unsatisfied dependencies."""
base_indent = " "
# high order bits in sorting
def kvord(a):
# Variants should always be last attribute.
return 7
# Facets should always be before variants.
return 6
# List attributes should be before facets and variants.
return 5
# For depend actions, type should always come
# first even though it's not the key attribute,
# and fmri should always come after type.
if a[0] == "fmri":
return 1
elif a[0] == "type":
return 0
# Any other attributes should come just before list,
# facet, and variant attributes.
return 4
# No special order for all other cases.
return 0
# actual key function
def key_func(a):
return (kvord(a), a[0])
if not force_nl:
if lastnl == -1:
lastnl = 0
if rem_values == 1:
# If outputting the last attribute
# value, then use full line length.
max_len = 80
else:
# If V1 format, or there are more
# attributes to output, then account
# for the line-continuation marker.
max_len = 78
# Note this length comparison doesn't include
# the space used to append the second part of
# the string.
return a + " " + b
return a + JOIN_TOK + b
# Number of attribute values for first line and
# remaining.
# Total number of remaining attribute values to output.
# Now build the action output string an attribute at a
# time.
# Newline breaks are only forced when there is
# more than one value for an attribute.
if not (isinstance(v, list) or
isinstance(v, set)):
nv = [v]
else:
nv = v
force_nl = use_force_nl and \
k.startswith("pkg.debug")
(k,
lmt))),
# Must be done for each value.
rem_count -= 1
return aout
"""Performs additional validation of action attributes that
for performance or other reasons cannot or should not be done
during Action object creation. An ActionError exception (or
subclass of) will be raised if any attributes are not valid.
This is primarily intended for use during publication or during
error handling to provide additional diagonostics.
'fmri' is an optional package FMRI (object or string)
indicating what package contained this action."""
if dtype == "conditional":
"type"]
# Other dependency types only expect a single value.
dtype not in known_types):
_("Unknown type '{0}' in depend action").
_("a predicate may only be specified "
"for conditional dependencies")))
_("the root-image attribute is only "
"valid for origin dependencies")))
# Logic here intentionally treats 'predicate' and 'fmri' as
# having multiple values for simplicity.
try:
# pkgdepend uses this special
# value.
continue
attr,
_("invalid {attr} value "
"'{value}': {error}").
value=f,
if errors:
self,