#
# 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
#
#
#
# pkgrepo exit codes
# listing constants
# diff type
# globals
tmpdirs = []
import atexit
import collections
import copy
import errno
import getopt
import gettext
import locale
import logging
import os
import operator
import shlex
import shutil
import six
import sys
import tempfile
import textwrap
import traceback
import warnings
import itertools
import pkg
def cleanup():
"""To be called at program finish."""
for d in tmpdirs:
"""Emit an error message prefixed by the command name """
if cmd:
pkg_cmd = "pkgrepo "
else:
pkg_cmd = "pkgrepo: "
# If we get passed something like an Exception, we can convert
# it down to a string.
# If the message starts with whitespace, assume that it should come
# *before* the command-name prefix.
# This has to be a constant value as we can't reliably get our actual
# program name on all platforms.
if quiet:
else:
try:
progtrack = \
progtrack = \
return progtrack
"""Emit a usage message and optionally prefix it with a more
specific error message. Causes program to exit.
"""
if usage_error:
if not full:
# The full usage message isn't desired.
"information."))
msg(_("""\
Usage:
pkgrepo [options] command [cmd_options] [operands]
Subcommands:
pkgrepo create [--version ver] uri_or_path
pkgrepo add-publisher -s repo_uri_or_path publisher ...
pkgrepo remove-publisher [-n] [--synchronous] -s repo_uri_or_path
publisher ...
pkgrepo get [-F format] [-p publisher ...] -s repo_uri_or_path
pkgrepo info [-F format] [-H] [-p publisher ...] -s repo_uri_or_path
[--key ssl_key ... --cert ssl_cert ...]
pkgrepo list [-F format] [-H] [-p publisher ...] -s repo_uri_or_path
[--key ssl_key ... --cert ssl_cert ...] [pkg_fmri_pattern ...]
pkgrepo contents [-m] [-t action_type ...] -s repo_uri_or_path
[--key ssl_key ... --cert ssl_cert ...] [pkg_fmri_pattern ...]
pkgrepo rebuild [-p publisher ...] -s repo_uri_or_path [--key ssl_key ...
--cert ssl_cert ...] [--no-catalog] [--no-index]
pkgrepo refresh [-p publisher ...] -s repo_uri_or_path [--key ssl_key ...
--cert ssl_cert ...] [--no-catalog] [--no-index]
pkgrepo remove [-n] [-p publisher ...] -s repo_uri_or_path
pkg_fmri_pattern ...
pkgrepo set [-p publisher ...] -s repo_uri_or_path
pkgrepo verify [-d] [-p publisher ...] [-i ignored_dep_file ...]
[--disable verification ...] -s repo_uri_or_path
pkgrepo fix [-v] [-p publisher ...] -s repo_uri_or_path
pkgrepo diff [-vq] [--strict] [--parsable] [-p publisher ...]
-s first_repo_uri_or_path [--key ssl_key ... --cert ssl_cert ...]
-s second_repo_uri_or_path [--key ssl_key ... --cert ssl_cert ...]
pkgrepo help
pkgrepo version
Options:
--help or -?
Displays a usage message."""))
"""Option exception. """
"""Parse the repository location provided and attempt to transform it
into a valid repository URI.
"""
subcommand = "remove"
if opt == "-n":
elif opt == "-p":
elif opt == "-s":
if not pargs:
usage(_("At least one package pattern must be provided."),
# Get repository object.
usage(_("A package repository location must be provided "
if "all" in pubs:
# Find matching packages.
try:
except apx.PackageMatchErrors as e:
return EXIT_OOPS
if dry_run:
# Don't make any changes; display list of packages to be
# removed and exit.
return EXIT_OK
progtrack = get_tracker()
for f in m:
# Add a newline between each publisher.
return EXIT_OK
"""Return the repository object for current program configuration.
'allow_invalid' specifies whether potentially corrupt repositories are
allowed; should only be True if performing a rebuild operation."""
usage(_("Network repositories are not currently supported "
if not path:
# Bad URI?
if not repo_uri:
global tmpdirs
# Create transport and transport config.
if not prefix:
pub = "target"
else:
# Configure target publisher.
"""Add publisher(s) to the specified repository."""
subcommand = "add-publisher"
if opt == "-s":
if not repo_uri:
usage(_("Network repositories are not currently supported "
if not pargs:
usage(_("At least one publisher must be specified"),
if abort:
return EXIT_OOPS
# Elide the publishers that already exist, but retain the order
# publishers were specified in.
new_pubs = [
]
# Tricky logic; _set_pub will happily add new publishers if necessary
# and not set any properties if you didn't specify any.
if make_default:
# No publisher existed previously, so set the default publisher
# to be the first new one that was added.
# Some of the publishers that were requested for addition
# were already known.
if new_pubs:
return EXIT_PARTIAL
return EXIT_OOPS
return rval
"""Remove publisher(s) from a repository"""
subcommand = "remove-publisher"
if opt == "-s":
elif opt == "-n":
elif opt == "--synchronous":
if not repo_uri:
usage(_("Network repositories are not currently supported "
if not pargs:
usage(_("At least one publisher must be specified"),
inv_pfxs = []
if inv_pfxs:
return EXIT_OOPS
# Publishers left if remove succeeds.
if noexisting:
error(_("The following publisher(s) could not be found:\n "
return EXIT_OOPS
if dry_run:
return EXIT_OK
if defaultpfx in existing:
msg(_("The default publisher was removed."
else:
msg(_("The default publisher was removed."
" unset"))
return EXIT_OK
"""Create a package repository at the given location."""
subcommand = "create"
version = None
if opt == "-s":
elif opt == "--version":
# This option is currently private and allows creating a
# repository with a specific format based on version.
try:
except ValueError:
usage(_("Version must be an integer value."),
usage(_("Only one repository location may be specified."),
elif pargs:
if not repo_uri:
usage(_("Network repositories are not currently supported "
# Attempt to create a repository at the specified location. Allow
# whatever exceptions are raised to bubble up.
return EXIT_OK
"""Display repository properties."""
subcommand = "get"
out_format = "default"
key = None
cert = None
if opt == "-F":
if arg not in LISTING_FORMATS:
raise apx.InvalidOptionError(
elif opt == "-H":
elif opt == "-p":
elif opt == "-s":
elif opt == "--key":
elif opt == "--cert":
# Setup transport so configuration can be retrieved.
usage(_("A package repository location must be provided "
# Get properties.
if pubs:
"""Display repository properties."""
# Configuration index is indexed by section name and property name.
# Retrieve and flatten it to simplify listing process.
# Set minimum widths for section and property name columns by using the
# length of the column headers.
del props
else:
def gen_listing():
yield {
"section": sname,
"property": pname,
"value": sval,
}
# SECTION PROPERTY VALUE
# <sec_1> <prop_1> <prop_1_value>
# <sec_2> <prop_2> <prop_2_value>
# ...
field_data = {
"section" : [("default", "json", "tsv"), _("SECTION"), ""],
"property" : [("default", "json", "tsv"), _("PROPERTY"), ""],
"value" : [("default", "json", "tsv"), _("VALUE"), ""],
}
# Default output formatting.
"} {2}"
# print without trailing newline.
return EXIT_PARTIAL
if out_format == "default":
# Don't pollute other output formats.
error(_("no matching properties found"),
return EXIT_OOPS
return EXIT_OK
# Retrieve publisher information.
else:
if use_transport:
# Assign transport information.
for p in pub_data:
# Establish initial return value and perform early exit if appropriate.
if out_format == "default":
# Don't pollute other output formats.
err_msg = _("no matching publishers found")
if repo_uri:
err_msg = _("no matching publishers found in "
return EXIT_OOPS, None, None
pargs):
"""Display publisher properties."""
return rval
# 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.
pub_idx = {}
"publisher": {
},
}
if pub_repo:
}
else:
"collection-type": "core",
"description": "",
"legal-uris": [],
"mirrors": [],
"name": "",
"origins": [],
"refresh-seconds": "",
"registration-uri": "",
"related-uris": [],
}
# Determine possible set of properties and lengths.
# Determine properties to display.
del props
else:
def gen_listing():
yield {
"publisher": pub,
"section": sname,
"property": pname,
"value": sval,
}
# PUBLISHER SECTION PROPERTY VALUE
# <pub_1> <sec_1> <prop_1> <prop_1_value>
# <pub_1> <sec_2> <prop_2> <prop_2_value>
# ...
field_data = {
"publisher" : [("default", "json", "tsv"), _("PUBLISHER"), ""],
"section" : [("default", "json", "tsv"), _("SECTION"), ""],
"property" : [("default", "json", "tsv"), _("PROPERTY"), ""],
"value" : [("default", "json", "tsv"), _("VALUE"), ""],
}
_("VALUE"))
# Default output formatting.
# print without trailing newline.
if out_format == "default":
# Don't pollute other output formats.
error(_("no matching properties found"),
return rval
"""Display a list of known publishers and a summary of known packages
and when the package data for the given publisher was last updated.
"""
subcommand = "info"
out_format = "default"
key = None
cert = None
if opt == "-F":
if arg not in LISTING_FORMATS:
raise apx.InvalidOptionError(
elif opt == "-H":
elif opt == "-p":
elif opt == "-s":
elif opt == "--key":
elif opt == "--cert":
if pargs:
# Setup transport so status can be retrieved.
usage(_("A package repository location must be provided "
# Retrieve repository status information.
else:
def gen_listing():
if last_update:
# Reformat the date into something more user
# friendly (and locale specific).
yield {
"publisher": pfx,
"packages": pkg_count,
"status": rstatus,
"updated": last_update,
}
# PUBLISHER PACKAGES STATUS UPDATED
# <pub_1> <num_uniq_pkgs> <status> <cat_last_modified>
# <pub_2> <num_uniq_pkgs> <status> <cat_last_modified>
# ...
field_data = {
"publisher" : [("default", "json", "tsv"), _("PUBLISHER"), ""],
"packages" : [("default", "json", "tsv"), _("PACKAGES"), ""],
"status" : [("default", "json", "tsv"), _("STATUS"), ""],
"updated" : [("default", "json", "tsv"), _("UPDATED"), ""],
}
_("UPDATED"))
# Default output formatting.
))
# print without trailing newline.
return EXIT_PARTIAL
if out_format == "default":
# Don't pollute other output formats.
error(_("no matching publishers found"),
return EXIT_OOPS
return EXIT_OK
"""List all packages matching the specified patterns."""
subcommand = "list"
out_format = "default"
key = None
cert = None
if opt == "-F":
if arg not in LISTING_FORMATS:
raise apx.InvalidOptionError(
elif opt == "-H":
elif opt == "-p":
elif opt == "-s":
elif opt == "--key":
elif opt == "--cert":
# Setup transport so configuration can be retrieved.
usage(_("A package repository location must be provided "
return rval
listed = {}
def gen_listing():
if not listed:
state = None
if out_format == "default" or \
out_format == "tsv":
if pkgdefs.PKG_STATE_OBSOLETE in \
state = "o"
elif pkgdefs.PKG_STATE_RENAMED in \
state = "r"
if out_format == "default":
else:
ret = {
"publisher": f.publisher,
"name": f.pkg_name,
"version": fver,
"build-release":
"timestamp":
"pkg.fmri": ffmri,
"short_state": state,
}
d["value"] = \
yield ret
field_data = {
"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"),
_("STATE"))
# Default output formatting.
# print without trailing newline.
# No matching packages.
if not unmatched:
return EXIT_OOPS
elif unmatched:
# One or more patterns didn't match a package from any
# publisher; only display the error.
return EXIT_PARTIAL
return EXIT_OK
"""A helper function to refresh all specified publishers."""
global tmpdirs
progtrack = get_tracker()
try:
except apx.TransportError:
# Assume that a catalog doesn't exist for the target
# publisher and drive on.
pass
"""List package contents."""
subcommand = "contents"
key = None
cert = None
attrs = []
action_types = []
if opt == "-s":
elif opt == "-m":
elif opt == "-t":
elif opt == "--key":
elif opt == "--cert":
# Setup transport so configuration can be retrieved.
usage(_("A package repository location must be provided "
return rval
# Default output prints out the raw manifest. The -m option is implicit
# for now and supported to make the interface equivalent to pkg
# contents.
if not attrs or display_raw:
attrs = ["action.raw"]
manifests = []
if not listed:
# Build a generator expression based on whether specific action types
# were provided.
if action_types:
# If query is limited to specific action types, use the more
# efficient type-based generation mechanism.
gen_expr = (
(m.fmri, a, None, None, None)
for m in manifests
for a in m.gen_actions_by_types(action_types)
)
else:
gen_expr = (
(m.fmri, a, None, None, None)
for m in manifests
for a in m.gen_actions()
)
# Determine if the query returned any results by "peeking" at the first
# value returned from the generator expression.
try:
except StopIteration:
got = None
actionlist = []
if got:
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
if not text:
continue
if unmatched:
if manifests:
pkgrepo: contents: no packages matching the following patterns you specified
were found in the repository."""))
for p in unmatched:
return rval
"""In an attempt to allow operations on potentially corrupt
repositories, 'local' repositories (filesystem-basd ones) are handled
separately."""
if not pubs:
else:
return EXIT_OOPS
return rval
if build_catalog and build_index:
elif build_catalog:
elif build_index:
xpub)
return rval
return rval
"""Rebuild the repository's catalog and index data (as permitted)."""
subcommand = "rebuild"
key = None
cert = None
"key=", "cert="])
if opt == "-p":
elif opt == "-s":
elif opt == "--no-catalog":
elif opt == "--no-index":
elif opt == "--key":
elif opt == "--cert":
if pargs:
if not build_catalog and not build_index:
# Why? Who knows; but do what was requested--nothing!
return EXIT_OK
# 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)."""
subcommand = "refresh"
key = None
cert = None
"key=", "cert="])
if opt == "-p":
elif opt == "-s":
elif opt == "--no-catalog":
elif opt == "--no-index":
elif opt == "--key":
elif opt == "--cert":
if pargs:
if not add_content and not refresh_index:
# Why? Who knows; but do what was requested--nothing!
return EXIT_OK
# Setup transport so operation can be performed.
usage(_("A package repository location must be provided "
if add_content and refresh_index:
elif add_content:
elif refresh_index:
xpub)
return rval
return rval
"""Set repository properties."""
subcommand = "set"
if opt == "-p":
elif opt == "-s":
props = {}
if not pargs:
else:
try:
# 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
# the value.
else:
else:
# Otherwise, just store the value.
except ValueError:
break
if bad_args:
usage(_("a property name and value must be provided in the "
# Get repository object.
usage(_("A package repository location must be provided "
# Set properties.
if pubs:
"""Set publisher properties."""
usage(_("unknown property section "
usage(_("'{0}' may not be set using "
if "all" in pubs:
# Default to list of all publishers.
if not pubs:
# 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.
failed = []
try:
# Get a copy of the existing publisher.
except sr.RepositoryUnknownPublisher as e:
except sr.RepositoryError as e:
continue
try:
if sname == "publisher":
elif sname == "repository":
if not target:
# If the target property expects
# a list, transform the provided
# value into one if it isn't
# already.
if val == "":
val = []
else:
except apx.ApiException as e:
continue
if new_pub:
else:
if failed:
error(_("Unable to set properties for publisher "
return EXIT_PARTIAL
return EXIT_OOPS
return EXIT_OK
"""Set repository properties."""
# Set properties.
return EXIT_OK
"""Display the version of the pkg(7) API."""
subcommand = "version"
if args:
return EXIT_OK
verify_error_header = None
verify_warning_header = None
verify_reason_headers = None
def __load_verify_msgs():
"""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"""
global verify_error_header
global verify_warning_header
global verify_reason_headers
# 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"),
"fpath": _("Path"),
"permissionspath": _("Path"),
"pkg": _("Package"),
"depend": _("Dependency"),
"type":_("Dependency type"),
"err": _("Detail")
}
verify_error_header = _("ERROR")
verify_warning_header = _("WARNING")
"""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(
else:
# 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.
if "err" in reason_keys:
err_str = ""
else:
for key in reason_keys:
# 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)
continue
formatted_message += "\n"
return formatted_message, None
elif "depend" in reason:
elif "pkg" in reason:
"""Helpler function to collect default ignored-dependency files."""
root_ignored = "/usr/share/pkg/ignored_deps"
if altroot:
igf))
"""Verify the repository content (file, manifest content and
dependencies only)."""
subcommand = "verify"
ignored_dep_files = []
if opt == "-s":
elif opt == "-p":
elif opt == "-d":
elif opt == "--disable":
if arg in allowed_checks:
else:
usage(_("Invalid verification to be disabled, "
elif opt == "-i":
if pargs:
if not repo_uri:
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 "
xpub)
return rval
progtrack = get_tracker()
if bad_fmri:
found_pubs = []
if bad_fmris:
return EXIT_OOPS
return EXIT_OK
"""Fix the repository content (file and manifest content only)
For index and catalog content corruption, a rebuild should be
performed."""
subcommand = "fix"
# Dependency verification. Note fix will not force dependency check.
ignored_dep_files = []
if opt == "-s":
if opt == "-v":
if opt == "-p":
if pargs:
if not repo_uri:
usage(_("A package repository location must be provided "
usage(_("Network repositories are not currently supported "
xpub)
return rval
"""A method passed to sr.Repository.fix(..) to emit verify
messages if verbose mode is enabled."""
if not verbose:
return
broken_fmris = set()
failed_fix_paths = set()
progtrack = get_tracker()
found_pubs = []
# When we can't get the FMRI, eg. in the case
# of a corrupt manifest, use the path instead.
if not fmri:
if verbose:
else:
if broken_fmris:
"following packages or paths which were quarantined:\n\n\t"
"{0}").format(
if failed_fix_paths:
"in the repository:\n\n\t{0}").format(
if bad_deps:
"dependency issues in the repository:\n\n\t{0}").format(
else:
if failed_fix_paths or bad_deps:
return EXIT_OOPS
return EXIT_OK
# 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.
"""
format_pub = "{0}{1}"
format_fmri = " {0}{1}"
format_str = " {0}{1}"
text = ""
else:
return text
if stype == "pub":
"""Determine the differences between two repositories."""
stype="pub")
stype="pub")
if minus_pubs or plus_pubs:
if quiet:
return EXIT_DIFF
stype="pub")
stype="pub")
"table_header": [_("Publisher"),
# This is a table column header which tells that this
# row shows number of packages found in specific
# repository only.
# 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.
"table_data": []
}
"common_pubs": []}
# Summary level.
if not verbose:
None, {"packages": 0, "versions": 0},
return
if parsable:
key_name = "minus_pubs"
key_name = "plus_pubs"
return
for pub in minus_pubs:
# Indicates whether those two pubs have same pkgs.
if minus_fmris or plus_fmris:
if quiet:
return EXIT_DIFF
cat_lm_pub = None
cat_lm_rpub = None
if compare_cat:
return EXIT_DIFF
# Print summary.
if not verbose:
if not same_cat:
# Common publishers with different catalog
# modification time.
# Add to the table only if there are differences
# for this publisher.
if not same_pkgs:
del minus_pkgs, minus_fmris
del plus_pkgs, plus_fmris
del total_pkgs, total_fmris
continue
com_pub_info = {}
# Emit publisher name if there are differences.
if parsable:
com_pub_info["+"] = []
com_pub_info["-"] = []
else:
# Emit catalog differences.
if not same_cat:
omsg = _("catalog last modified: {0}")
if parsable:
"+": plus_cat}
else:
for f in minus_fmris:
if parsable:
else:
__emit_msg(MINUS, f)
del minus_fmris
for f in plus_fmris:
if parsable:
else:
__emit_msg(PLUS, f)
del plus_fmris
if not same_pkgs:
if parsable:
com_pub_info["common"] = {
else:
msg(_(" ({0:d} pkg(s) with {1:d} "
"version(s) are in both repositories.)"
len(common_fmris)))
if com_pub_info:
if same_repo:
# Same repo. Will use EXIT_OK to represent.
return EXIT_OK
if verbose:
if parsable:
return EXIT_DIFF
if not parsable:
ftemp = "{0:d} [{1:{2}d}]"
msg("")
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}:"
conf["com_repo_uri"],
if res_dict["table_data"]:
# Calculate column wise maximum number for formatting.
cell["versions"])
t_row = []
if not cell:
cell["packages"],
# 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
# brackets respectively.
msg(_("""
The table below shows the number of packages [total distinct versions]
by publisher in the specified repositories.
"""))
msg("")
else:
return EXIT_DIFF
"""Compare two repositories."""
"key=", "cert="])
subcommand = "diff"
verbose = 0
"""Helper function for collecting key and cert."""
else:
usage(_("--{0} must be specified following a "
if opt == "-s":
if "repo_uri" not in conf:
elif "com_repo_uri" not in conf:
else:
usage(_("only two repositories can be "
if opt == "-v":
verbose += 1
elif opt == "-q":
elif opt == "--strict":
elif opt == "--parsable":
elif opt == "-p":
return EXIT_OOPS
elif opt == "--key":
elif opt == "--cert":
if not repo_uri:
usage(_("Two package repository locations must be provided "
if not com_repo_uri:
usage(_("A second package repository location must also be "
return rval
return rval
def main_func():
try:
["help", "debug="])
except getopt.GetoptError as e:
conf = {}
if opt == "-s":
try:
except (AttributeError, ValueError):
usage(_("{opt} takes argument of form "
"name=value, not {arg}").format(
if DebugValues:
subcommand = None
if pargs:
if subcommand == "help":
if show_usage:
elif not subcommand:
usage(_("no subcommand specified"))
if not func:
try:
except getopt.GetoptError as e:
#
# 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
"""
try:
# 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.
try:
raise
except SystemExit as __e:
raise __e
# Don't display any messages here to prevent possible further
# broken pipe (EPIPE) errors.
error(_("The pkgrepo command appears out of sync with the "
"version is {client} while the library\nAPI version is "
except:
__ret = 99
return __ret
if __name__ == "__main__":
# Make all warnings be errors.
# disable ResourceWarning: unclosed file
try:
except IOError:
# Ignore python's spurious pipe problems.
pass