#
# 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
#
#
#
# Some pkg(7) specific lint manifest checks
import six
"""A class to check manifests."""
self.description = _(
"Checks for errors within the scope of a single manifest.")
self.ref_lastnames = {}
self.lint_lastnames = {}
self.processed_lastnames = []
# maps package names to a list of packages which depend on them.
self.dependencies = {}
if "pkg.renamed" in manifest or \
"pkg.obsolete" in manifest:
return
else:
"""Updates a dictionary of package names that declare
dependencies, keyed by the depend action fmri name.
We drop versions and consider all dependency types
except 'incorporate'."""
continue
try:
f.get_name(), []
for d in dep:
f.get_name(), []
# If we have a bad FMRI, this will be picked up
# by pkglint.action006 and pkglint.action009.
pass
_("Seeding reference manifest dictionaries."))
_("Seeding lint manifest dictionaries."))
"""Checks for correct package obsoletion.
* error if obsoleted packages contain anything other than
set or signature actions
* error if pkg.description or pkg.summary are set.
* warn if other packages have non-incorporate dependencies on
this package.
"""
return
"{key} attribute").format(
# the loggers are no longer concerned about actions
linted_action = None
# since we only emit the error once, after iterating
# over all actions, we may lose the action that could
# contain the linted flag, so the logging
# subsystem will not be able to use it to print a
# "lint bypassed" message. Save it here.
continue
_("obsolete package {0} contains actions other than "
# report that we bypassed a check
if linted_action and not has_invalid_action:
_("obsolete package {0} contains actions other than "
# determine whether other packages we know about have
# dependencies on this obsolete package.
obsolete_depends = set()
if depends:
for depending_package in depends:
if obsolete_depends:
# this is only a warning, because at install-time the
# solver may still be able to find a non-obsolete
# version of a package.
"upon by the following packages: "
obsoletion.pkglint_desc = _(
"Obsolete packages should have valid contents.")
"""Checks for correct package renaming.
* error if renamed packages contain anything other than set,
signature and depend actions.
* follows renames, ensuring they're not circular, and don't
end up at an obsolete package.
"""
if "pkg.renamed" not in manifest:
return
count_depends = 0
continue
"other than set, depend or signature actions").format(
# if all actions in the manifest that would have caused errors
# were marked as linted, we need to advise the logging mechanism
# of at least one action that was marked as linted, then log the
# error, ultimately resulting in an INFO level message.
if seen_linted_action and not has_invalid_action:
"other than set, depend or signature actions").format(
if count_depends == 0:
"'require' dependency indicating what it was "
"renamed to").format(
try:
old_mfs=[])
if not mf:
"{0}: possible missing package").format(
else:
if "pkg.obsolete" not in mf:
return
"to an obsolete package {obs}").format(
"""Checks for correct use of variant tags.
* if variant tags present, matching variant descriptions
exist and are correctly specified, with the exception of
variant.debug.* variants
* All manifests that deliver file actions of a given
architecture declare variant.arch
These checks are only performed on published packages."""
if not engine.do_pub_checks:
return
unknown_variants = set()
"""check whether we can ignore this variant."""
continue
for k in diff.type_diffs:
if ignore_variant(k):
continue
for k, v in diff.value_diffs:
if ignore_variant(k):
continue
v))
"{pkg}").format(
"of known values for variants in {pkg}").format(
"""Warn when there's a namespace clash where the last component
of the pkg name matches an existing one in the catalog."""
return
return
# we ignored renamed or obsolete packages when building
# ref_lastnames, so this package might not be there,
# in which case, we can ignore this package too.
return
_("last name component {name} in package name "
"clashes across {pkgs}").format(
naming.pkglint_desc = _(
"Packages are encouraged to use unique leaf names.")
"""Checks for repeated dependencies, including package version
substrings."""
seen_deps = {}
duplicates = []
dup_msg = _(
"duplicate depend actions in {pkg} {actions}")
duplicates = []
# this only checks require, require-any and group-any
# actions
"require-any", "group-any"]:
continue
_("no fmri attribute in depend "
"action in {0}").format(
continue
continue
else:
if conflict_actions:
if duplicates:
"Packages should not have duplicate 'depend' actions.")
"""Checks for duplicate set actions."""
seen_sets = {}
dup_set_msg = _("duplicate set actions on {names} in {pkg}")
duplicates = []
continue
else:
if conflict_actions:
if duplicates:
"Packages should not have duplicate 'set' actions.")
pkg.linted* attributes set on this manifest."""
if linted_attrs:
"""Checks that the info.classification attribute is valid."""
if (not "info.classification" in manifest) or \
return
if not self.classification_data or \
"for info.classification attribute: {0}").format(
return
"info.classification attribute should be valid.")
prefix = "org.opensolaris.category.2008:"
"does not contain '{prefix}' for {fmri}").format(
return
"does not match "
"{prefix}<Section>/<Category> for {fmri}").format(
return
# the data file looks like:
# [Section]
# category = Cat1,Cat2,Cat3
#
# We expect the info.classification action to look like:
#
ref_categories = []
try:
if category not in ref_categories:
except configparser.NoSectionError:
"does not contain one of the valid sections "
"{ref_sections} for {fmri}.").format(
return
except configparser.NoOptionError:
"{fmri}: data file {file} does not have a "
"'category' key for section {section}.").format(
return
if valid_value:
return
"does not contain one of the values defined for the "
"section {section}: {ref_cats} from {path}").format(
"""Warns when a package has an empty summary or description,
or a description which is identical to the summary."""
if desc == "":
if summ == "":
"A package's description should not match its summary.")
"""Various checks for missing attributes
* error when a package doesn't have a pkg.summary
(pkg.fmri should be present too, but that would get caught
before we get here)
"""
if "pkg.renamed" in manifest:
return
if "pkg.obsolete" in manifest:
return
if "pkg.summary" not in manifest:
_("Missing attribute 'pkg.summary' in {0}").format(
"Standard package attributes should be present.")
attribute in the manifest. This only reports a warning, because
without pkglint content-checking support, we do not know whether
the file actually contains any services or instances."""
smf_manifests = []
continue
continue
if not smf_manifests:
return
if "org.opensolaris.smf.fmri" in manifest:
return
_("SMF manifests were delivered by {pkg}, but no "
"org.opensolaris.smf.fmri attribute was found. "
"Manifests found were: {manifests}").format(
"Packages delivering SMF services should have "
"org.opensolaris.smf.fmri attributes.")
"""Merges the given src list into the target list"""
for p in src:
if p not in target:
continue
"""Removes older versions of pfmri from
targ_list."""
removals = []
for i in removals: