#
# 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 six
# A list of locations beneath a given proto_dir where we expect to
# find SMF manifest files
# maps SMF fmris to the manifest files that defined them
instance_mf = None
# maps SMF FMRIs to a list the SMF FMRIs they declare as dependencies
instance_deps = None
manifest = None
""" See __init__ for PublishingDependency.
"""
full_paths = None
# we can depend on multiple files delivering instances
# of a service that was marked as a dependency. If we
# do, we must specify the full paths to the manifests
# search for SMF manifests this way.
base_names = []
paths = []
for p in path]
else:
"tuple must be specified for 'path'.")
def _clear_cache():
"""Clear our manifest caches. This is primarily provided for
test code."""
SMFManifestDependency.instance_mf = None
"""Build our instance_mf and instance_deps dictionaries
from the known SMF manifests installed on the current system
and those that appear in the proto_dirs.
"""
if not force_update:
if SMFManifestDependency.instance_mf != None:
return
manifest_paths = []
# we want our proto_dirs to be the authoritative source
# for SMF manifests, so scan the local system first, then
# iterate through the proto_dirs, starting from the
# oldest, overwriting with progressively newer proto_dirs
for location in manifest_locations:
for location in manifest_locations:
location))
for location in manifest_paths:
for f in filenames:
dirpath, f)
"""Add a information information about the SMF instances and
their dependencies from the given manifest_file to a global
set of dictionaries."""
# more work is needed here when
# multiple-manifests per service is supported by
# SMF: we'll need to merge additional
# service-level dependencies into each service
# instance as each manifest gets added.
if instance_mf:
if instance_deps:
"""Split an SMF FMRI into constituent parts, returning the svc protocol,
the service name, and the instance name, if any."""
protocol = None
service = None
instance = None
protocol = "svc"
protocol = "svc"
else:
raise ValueError(_("FMRI does not appear to be valid"))
"""Search a dictionary of SMF FMRI mappings, returning a list of
results. If the FMRI points to an instance, we can return quickly. If
the FMRI points to a service, we return all matching instances. Note
if the dictionary contains service FMRIs, those won't appear in the
results - we only ever return instances."""
results = []
if instance is not None:
if fmri in dictionary:
else:
# return all matching instances of this service
for item in dictionary:
return results
"""Given an instance FMRI, determine the FMRIs it depends on. If we
match more than one fmri, we raise an exception. """
return results[0]
# this can only happen if we've been asked to resolve a
# service-level FMRI, not a fully qualified instance FMRI
raise ValueError(
_("more than one set of dependencies found: {0}").format(
results))
return results[0]
raise ValueError(
_("more than one set of dependencies found: {0}").format(
results))
return []
"""Given an SMF FMRI that satisfies a given SMF dependency, determine
which file(s) deliver that dependency using both the provided
instance_mf dictionary and the global SmfManifestDependency dictionary.
If multiple files match, we have a problem."""
# we can't satisfy the dependency at all
raise ValueError(_("cannot resolve FMRI to a delivered file"))
"""Given an action and a place to find the file it references, if the
file is an SMF manifest, we return a list of SmfManifestDependencies
pointing to the SMF manifests in the proto area that would satisfy each
dependency, a list of errors, and a dictionary containing the SMF FMRIs
that were contained in the SMF manifest that this action delivers.
Note that while we resolve SMF dependencies from SMF FMRIs to the files
that deliver them, we don't attempt to further resolve those files to
pkg(7) packages at this point.
That stage is done using the normal "pkgdepend resolve" mechanism."""
return [], \
[ _("{0} actions cannot deliver SMF manifests").format(
# we don't report an error here, as SMF manifest files may be delivered
# to a location specifically not intended to be imported to the SMF
# repository.
return [], [], {}
deps = []
elist = []
dep_manifests = set()
if instance_mf is None:
return [], [ _("Unable to parse SMF manifest {0}").format(
proto_file)], {}
for fmri in instance_mf:
try:
# we're only interested in trying to resolve
# dependencies that instances have declared
if instance is None:
continue
except ValueError as err:
**locals()))
continue
# determine the set of SMF FMRIs we depend on
try:
except ValueError as err:
_("Problem determining dependencies for {fmri}:"
# determine the file paths that deliver those dependencies
try:
except ValueError as err:
# we've declared an SMF dependency, but can't
# determine what file delivers it from the known
# SMF manifests in either the proto area or the
# local machine.
manifests = []
_("Unable to generate SMF dependency on "
"{dep_fmri} declared in {proto_file} by "
# This should never happen, as it implies a
# service FMRI, not an instance FMRI has been
# returned from search_smf_dic via
# resolve_smf_dependency.
if instance is not None:
_("Unable to generate SMF "
"dependency on the service FMRI "
"{dep_fmri} declared in "
"{proto_file} by {fmri}. "
"SMF dependencies should always "
"resolve to SMF instances rather "
"than SMF services and multiple "
"files deliver instances of this "
"service: {manifests}").format(
for manifest in dep_manifests:
pkg_attrs = {
}
"""Given a minidom Element deps, search for the <service_fmri> elements
inside it, and return the values as a list of strings."""
dependencies = []
for dependency in deps:
# we don't include SMF path dependencies as these are often
# not packaged files.
grouping == "require_all" and \
delete != "true":
for service_fmri in fmris:
if dependency:
return dependencies
"""Quickly determine if smf_file is a valid SMF manifest."""
try:
# catching ValueError, as minidom has been seen to raise this on some
# invalid XML files.
return False
return False
return False
return True
"""Returns a tuple of two dictionaries. The first maps the SMF FMRIs
found in that manifest to the path of the manifest file. The second maps
each SMF FMRI found in the file to the list of FMRIs that are declared
as dependencies.
Note this method makes no distinction between service FMRIs and instance
FMRIs; both get added to the dictionaries, but only the instance FMRIs
should be used to determine dependencies.
Calling this with a path to the file, we include manifest_paths in the
first dictionary, otherwise with raw file data, we don't.
If we weren't handed an SMF XML file, or have trouble parsing it, we
return a tuple of None, None.
"""
instance_mf = {}
instance_deps = {}
try:
# catching ValueError, as minidom has been seen to raise this on some
# invalid XML files.
return None, None
return None, None
return None, None
manifest_path = None
fmris = []
svc_dependencies = []
# get the service name
else:
# no defined service name, so no dependencies here
continue
# Get the FMRIs we declare dependencies on. When splitting SMF
# services across multiple manifests is supported, more work
# will be needed here.
svc_deps = []
# determine our instances
inst_dependencies = []
fmri = None
if inst_name:
# we've declared a
# create_default_instance tag but we've
# also explicitly created an instance
# called "default"
# we can use getElementsByTagName here, since
# there are no nested <dependency> tags that
# won't apply, unlike for <service> above, when
# we needed to look strictly at immediate
# children.
"dependency")
if fmri is not None:
if create_default and not duplicate_default:
# add the service FMRI
return instance_mf, instance_deps
"""Determine if the given path string contains any of the directories
where SMF manifests are usually delivered. An optional named parameter
prefix gets stripped from the path before checking.
"""
global manifest_locations
if prefix:
for location in manifest_locations:
return True
return False