pkgrepo.py revision 3210
1968N/A# The contents of this file are subject to the terms of the 1968N/A# Common Development and Distribution License (the "License"). 1968N/A# You may not use this file except in compliance with the License. 1968N/A# See the License for the specific language governing permissions 1968N/A# and limitations under the License. 1968N/A# When distributing Covered Code, include this CDDL HEADER in each 1968N/A# If applicable, add the following below this CDDL HEADER, with the 1968N/A# fields enclosed by brackets "[]" replaced with your own identifying 1968N/A# information: Portions Copyright [yyyy] [name of copyright owner] 1968N/A# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 1968N/A """To be called at program finish.""" 1968N/A """Emit an error message prefixed by the command name """ 1968N/A # If we get passed something like an Exception, we can convert 1978N/A # If the message starts with whitespace, assume that it should come 1978N/A # *before* the command-name prefix. 1978N/A # This has to be a constant value as we can't reliably get our actual 1968N/A # program name on all platforms. 1968N/A """Emit a usage message and optionally prefix it with a more 1968N/A specific error message. Causes program to exit. 1968N/A # The full usage message isn't desired. 1968N/A pkgrepo [options] command [cmd_options] [operands] 1968N/A pkgrepo create [--version ver] uri_or_path 1968N/A pkgrepo add-publisher -s repo_uri_or_path publisher ... 1968N/A pkgrepo remove-publisher [-n] [--synchronous] -s repo_uri_or_path 1968N/A pkgrepo get [-F format] [-p publisher ...] -s repo_uri_or_path 1968N/A pkgrepo info [-F format] [-H] [-p publisher ...] -s repo_uri_or_path 1968N/A [--key ssl_key ... --cert ssl_cert ...] 1968N/A pkgrepo list [-F format] [-H] [-p publisher ...] -s repo_uri_or_path 1968N/A [--key ssl_key ... --cert ssl_cert ...] [pkg_fmri_pattern ...] 1968N/A pkgrepo contents [-m] [-t action_type ...] -s repo_uri_or_path 1968N/A [--key ssl_key ... --cert ssl_cert ...] [pkg_fmri_pattern ...] 1968N/A pkgrepo rebuild [-p publisher ...] -s repo_uri_or_path [--key ssl_key ... 1968N/A --cert ssl_cert ...] [--no-catalog] [--no-index] 1968N/A pkgrepo refresh [-p publisher ...] -s repo_uri_or_path [--key ssl_key ... 1968N/A --cert ssl_cert ...] [--no-catalog] [--no-index] 1968N/A pkgrepo remove [-n] [-p publisher ...] -s repo_uri_or_path 1968N/A pkgrepo set [-p publisher ...] -s repo_uri_or_path 1968N/A pkgrepo verify [-d] [-p publisher ...] [-i ignored_dep_file ...] 1968N/A [--disable verification ...] -s repo_uri_or_path 1968N/A pkgrepo fix [-v] [-p publisher ...] -s repo_uri_or_path 1968N/A pkgrepo diff [-vq] [--strict] [--parsable] [-p publisher ...] 1968N/A -s first_repo_uri_or_path [--key ssl_key ... --cert ssl_cert ...] 1968N/A -s second_repo_uri_or_path [--key ssl_key ... --cert ssl_cert ...] 1968N/A Displays a usage message."""))
1968N/A """Parse the repository location provided and attempt to transform it 1968N/A into a valid repository URI. 1968N/A usage(_(
"At least one package pattern must be provided."),
1968N/A usage(_(
"A package repository location must be provided " 1968N/A # Don't make any changes; display list of packages to be 1968N/A # Add a newline between each publisher. 1968N/A """Return the repository object for current program configuration. 1968N/A 'allow_invalid' specifies whether potentially corrupt repositories are 1968N/A allowed; should only be True if performing a rebuild operation.""" 1968N/A usage(_(
"Network repositories are not currently supported " 1968N/A # Create transport and transport config. 1968N/A # Configure target publisher. 1968N/A """Add publisher(s) to the specified repository.""" 1968N/A usage(_(
"Network repositories are not currently supported " 1968N/A usage(_(
"At least one publisher must be specified"),
1968N/A # Elide the publishers that already exist, but retain the order 1968N/A # publishers were specified in. 1968N/A # Tricky logic; _set_pub will happily add new publishers if necessary 1968N/A # and not set any properties if you didn't specify any. 1968N/A # No publisher existed previously, so set the default publisher 1968N/A # to be the first new one that was added. 1968N/A # Some of the publishers that were requested for addition 1968N/A """Remove publisher(s) from a repository""" 1968N/A usage(_(
"Network repositories are not currently supported " 1968N/A usage(_(
"At least one publisher must be specified"),
1968N/A # Publishers left if remove succeeds. 1968N/A error(_(
"The following publisher(s) could not be found:\n " 1968N/A msg(_(
"The default publisher was removed." 1968N/A msg(_(
"The default publisher was removed." 1968N/A """Create a package repository at the given location.""" 1968N/A # This option is currently private and allows creating a 1968N/A # repository with a specific format based on version. 1968N/A usage(_(
"Only one repository location may be specified."),
1968N/A usage(_(
"Network repositories are not currently supported " 1968N/A # Attempt to create a repository at the specified location. Allow 1968N/A # whatever exceptions are raised to bubble up. 1968N/A """Display repository properties.""" 1968N/A # Setup transport so configuration can be retrieved. 1968N/A usage(_(
"A package repository location must be provided " 1968N/A """Display repository properties.""" 1968N/A # Configuration index is indexed by section name and property name. 1968N/A # Retrieve and flatten it to simplify listing process. 1968N/A # Set minimum widths for section and property name columns by using the 1968N/A # length of the column headers. 1968N/A # <sec_1> <prop_1> <prop_1_value> 1968N/A # <sec_2> <prop_2> <prop_2_value> 1968N/A "section" : [(
"default",
"json",
"tsv"), _(
"SECTION"),
""],
1968N/A "property" : [(
"default",
"json",
"tsv"), _(
"PROPERTY"),
""],
1968N/A "value" : [(
"default",
"json",
"tsv"), _(
"VALUE"),
""],
1968N/A # Default output formatting. 1968N/A # print without trailing newline. 1968N/A # Don't pollute other output formats. 1968N/A # Retrieve publisher information. # Assign transport information. # Establish initial return value and perform early exit if appropriate. # Don't pollute other output formats. err_msg = _(
"no matching publishers found")
err_msg = _(
"no matching publishers found in " """Display publisher properties.""" # Set minimum widths for section and property name columns by using the # length of the column headers and data. # For each requested publisher, retrieve the requested property data. "collection-type":
"core",
# Determine possible set of properties and lengths. # Determine properties to display. # PUBLISHER SECTION PROPERTY VALUE # <pub_1> <sec_1> <prop_1> <prop_1_value> # <pub_1> <sec_2> <prop_2> <prop_2_value> "publisher" : [(
"default",
"json",
"tsv"), _(
"PUBLISHER"),
""],
"section" : [(
"default",
"json",
"tsv"), _(
"SECTION"),
""],
"property" : [(
"default",
"json",
"tsv"), _(
"PROPERTY"),
""],
"value" : [(
"default",
"json",
"tsv"), _(
"VALUE"),
""],
# Default output formatting. # print without trailing newline. # Don't pollute other output formats. error(_(
"no matching properties found"),
"""Display a list of known publishers and a summary of known packages and when the package data for the given publisher was last updated. # Setup transport so status can be retrieved. usage(_(
"A package repository location must be provided " # Retrieve repository status information. # Reformat the date into something more user # friendly (and locale specific). # PUBLISHER PACKAGES STATUS UPDATED # <pub_1> <num_uniq_pkgs> <status> <cat_last_modified> # <pub_2> <num_uniq_pkgs> <status> <cat_last_modified> "publisher" : [(
"default",
"json",
"tsv"), _(
"PUBLISHER"),
""],
"packages" : [(
"default",
"json",
"tsv"), _(
"PACKAGES"),
""],
"status" : [(
"default",
"json",
"tsv"), _(
"STATUS"),
""],
"updated" : [(
"default",
"json",
"tsv"), _(
"UPDATED"),
""],
# Default output formatting. # print without trailing newline. # Don't pollute other output formats. error(_(
"no matching publishers found"),
"""List all packages matching the specified patterns.""" # Setup transport so configuration can be retrieved. usage(_(
"A package repository location must be provided " "publisher": [(
"default",
"json",
"tsv"), _(
"PUBLISHER"),
""],
"name": [(
"default",
"json",
"tsv"), _(
"NAME"),
""],
"version": [(
"default",
"json"), _(
"VERSION"),
""],
"release": [(
"json",
"tsv",), _(
"RELEASE"),
""],
"build-release": [(
"json",
"tsv",), _(
"BUILD RELEASE"),
""],
"branch": [(
"json",
"tsv",), _(
"BRANCH"),
""],
"timestamp": [(
"json",
"tsv",), _(
"PACKAGING DATE"),
""],
"pkg.fmri": [(
"json",
"tsv",), _(
"FMRI"),
""],
"short_state": [(
"default",
"tsv"),
"O",
""],
_(
"SUMMARY"), _(
"DESCRIPTION"), _(
"CATEGORIES"), _(
"RELEASE"),
_(
"BUILD RELEASE"), _(
"BRANCH"), _(
"PACKAGING DATE"), _(
"FMRI"),
# Default output formatting. # print without trailing newline. # One or more patterns didn't match a package from any # publisher; only display the error. """A helper function to refresh all specified publishers.""" # Assume that a catalog doesn't exist for the target # publisher and drive on. """List package contents.""" # Setup transport so configuration can be retrieved. usage(_(
"A package repository location must be provided " # Default output prints out the raw manifest. The -m option is implicit # for now and supported to make the interface equivalent to pkg # Build a generator expression based on whether specific action types # If query is limited to specific action types, use the more # efficient type-based generation mechanism. (m.
fmri, a,
None,
None,
None)
(m.
fmri, a,
None,
None,
None)
# Determine if the query returned any results by "peeking" at the first # value returned from the generator expression. pkgrepo: contents: This package contains no actions with the types specified using the -t option""",
"""\ pkgrepo: contents: These packages contain no actions with the types specified pkgrepo: contents: no packages matching the following patterns you specified were found in the repository."""))
"""In an attempt to allow operations on potentially corrupt repositories, 'local' repositories (filesystem-basd ones) are handled """Rebuild the repository's catalog and index data (as permitted).""" elif opt ==
"--no-catalog":
elif opt ==
"--no-index":
# Why? Who knows; but do what was requested--nothing! # Setup transport so operation can be performed. usage(_(
"A package repository location must be provided " """Refresh the repository's catalog and index data (as permitted).""" elif opt ==
"--no-catalog":
elif opt ==
"--no-index":
# Why? Who knows; but do what was requested--nothing! # Setup transport so operation can be performed. usage(_(
"A package repository location must be provided " """Set repository properties.""" # Attempt to parse property into components. # Store property values by section. # Parse the property value into a list if # necessary, otherwise append it to the list # of values for the property. # Determine if previous value is already # a list, and if not, convert and append # Otherwise, just store the value. usage(_(
"a property name and value must be provided in the " usage(_(
"A package repository location must be provided " """Set publisher properties.""" if sname not in (
"publisher",
"repository"):
usage(_(
"unknown property section " usage(_(
"'{0}' may not be set using " # Default to list of all publishers. # If there are still no known publishers, this # operation cannot succeed, so fail now. usage(_(
"One or more publishers must be specified to " "create and set properties for as none exist yet."),
# Get publishers and update properties. # Get a copy of the existing publisher. elif sname ==
"repository":
# If the target property expects # a list, transform the provided # value into one if it isn't error(_(
"Unable to set properties for publisher " """Set repository properties.""" """Display the version of the pkg(5) API.""" """Since our gettext isn't loaded we need to ensure our globals have correct content by calling this method. These values are used by both fix when in verbose mode, and verify""" # A map of error detail types to the human-readable description of each # type. These correspond to keys in the dictionary returned by # sr.Repository.verify(..) "path": _(
"Repository path"),
"actual": _(
"Computed hash"),
"permissionspath": _(
"Path"),
"depend": _(
"Dependency"),
"type":_(
"Dependency type"),
"""Format a verify_tuple, of the form (error, path, message, reason) returning a formatted error message, and an FMRI indicating what packages within the repository are affected. Note that the returned FMRI may not be valid, in which case a path to the broken manifest in the repository is returned instead.""" "{error_type:>16}: {message}\n".
format(
# A list of the details we provide. Some error codes # have different details associated with them. # the detailed error message can be long, so we'll wrap it. If what we # have fits on a single line, use it, otherwise begin displaying the # message on the next line. # sometimes we don't have the key we want, for example we may # not have a file path from the package if the error is a # missing repository file for a 'license' action (which don't # have 'path' attributes, hence no 'fpath' dictionary entry) """Helpler function to collect default ignored-dependency files.""" """Verify the repository content (file, manifest content and usage(_(
"Invalid verification to be disabled, " usage(_(
"A package repository location must be provided " usage(_(
"Network repositories are not currently supported " usage(_(
"-d or -i option cannot be used when dependency " logger.
info(
"Initiating repository verification.")
"""Fix the repository content (file and manifest content only) For index and catalog content corruption, a rebuild should be # Dependency verification. Note fix will not force dependency check. usage(_(
"A package repository location must be provided " usage(_(
"Network repositories are not currently supported " """A method passed to sr.Repository.fix(..) to emit verify messages if verbose mode is enabled.""" # When we can't get the FMRI, eg. in the case # of a corrupt manifest, use the path instead. logger.
info(_(
"Use pkgsend(1) or pkgrecv(1) to republish the\n" "following packages or paths which were quarantined:\n\n\t" logger.
info(_(
"\npkgrepo could not repair the following paths " "in the repository:\n\n\t{0}").
format(
logger.
info(_(
"\npkgrepo could not repair the following " "dependency issues in the repository:\n\n\t{0}").
format(
# Create a temporary directory for catalog. """formatting diff output. diff_type: can be MINUS, PLUS or COMMON. subject: can be a publisher or a package. """Determine the differences between two repositories.""" [
"Repo2",
str(
conf[
"com_repo_uri"])]],
"table_header": [_(
"Publisher"),
# This is a table column header which tells that this # row shows number of packages found in specific # Use terse translation to avoid too-wide header. # This is a table column header which tells that this # row shows number of packages found in both # repositories being compared together. # Use terse translation to avoid too-wide header. _(
"In both"), _(
"Total")],
# Row based table contents. None, {
"packages":
0,
"versions":
0},
# Indicates whether those two pubs have same pkgs. # Common publishers with different catalog # Add to the table only if there are differences # Emit publisher name if there are differences. # Emit catalog differences. omsg = _(
"catalog last modified: {0}")
msg(_(
" ({0:d} pkg(s) with {1:d} " "version(s) are in both repositories.)" # Same repo. Will use EXIT_OK to represent. ftemp =
"{0:d} [{1:{2}d}]" msg(_(
"The catalog for the following publisher(s) " "in repository {0} is not an exact copy of the " "one for the same publisher in repository {1}:" # Calculate column wise maximum number for formatting. # This message explains that each cell of the table # shows two numbers in a format e.g. "4870 [10227]". # Here "number of packages" and "total distinct # versions" are shown outside and inside of square The table below shows the number of packages [total distinct versions] by publisher in the specified repositories. """Compare two repositories.""" """Helper function for collecting key and cert.""" usage(_(
"--{0} must be specified following a " if "repo_uri" not in conf:
elif "com_repo_uri" not in conf:
usage(_(
"only two repositories can be " elif opt ==
"--parsable":
usage(_(
"Two package repository locations must be provided " usage(_(
"A second package repository location must also be " elif opt in (
"--help",
"-?"):
elif opt ==
"-D" or opt ==
"--debug":
usage(_(
"{opt} takes argument of form " "name=value, not {arg}").
format(
usage(_(
"no subcommand specified"))
if e.
opt in (
"help",
"?"):
# Establish a specific exit status which means: "python barfed an exception" # so that we can more easily detect these in testing of the CLI commands. """Catch exceptions raised by the main program function and then print a message and/or exit with an appropriate return code. # Out of memory errors can be raised as EnvironmentErrors with # an errno of ENOMEM, so in order to handle those exceptions # with other errnos, we nest this try block and have the outer # one handle the other instances. # Don't display any messages here to prevent possible further # broken pipe (EPIPE) errors. error(_(
"The pkgrepo command appears out of sync with the " "libraries provided\nby pkg:/package/pkg. The client " "version is {client} while the library\nAPI version is " # Make all warnings be errors. # Ignore python's spurious pipe problems.