# HG changeset patch # User Stephen Hahn # Date 1191874721 25200 # Node ID a1e20e9a9845956e65f9c3683e7b3e214367261f # Parent 6887274c15a38c2d87475625a1406754c06bc2c9 add CLI test suite, correct bugs found by test suite, ration out CLI options diff -r 6887274c15a3 -r a1e20e9a9845 src/Makefile --- a/src/Makefile Fri Oct 05 17:12:55 2007 -0700 +++ b/src/Makefile Mon Oct 08 13:18:41 2007 -0700 @@ -30,6 +30,7 @@ MACH:sh = uname -p +KSH=/usr/bin/ksh PYTHON = /usr/bin/python ROOT = ../proto/root_${MACH} @@ -224,7 +225,7 @@ @cd web; pwd; $(MAKE) $(TARGET) @cd brand; pwd; $(MAKE) $(TARGET) @cd man; pwd; $(MAKE) $(TARGET) - + # Invoke all known modules with tests. # XXX Invoke the bundle tests. test: @@ -238,6 +239,7 @@ $(PYTHON) $(LINKPYTHONPKG)/smf.py $(PYTHON) $(LINKPYTHONPKG)/client/imageconfig.py $(PYTHON) $(LINKPYTHONPKG)/client/filter.py + cd tests; $(KSH) -x cli-complete.ksh proto: $(ROOT) diff -r 6887274c15a3 -r a1e20e9a9845 src/depot.py --- a/src/depot.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/depot.py Mon Oct 08 13:18:41 2007 -0700 @@ -68,8 +68,10 @@ def usage(): print """\ -Usage: /usr/lib/pkg.depotd [-n] +Usage: /usr/lib/pkg.depotd [--readonly] [-d repo_dir] [-p port] + --readonly Read-only operation; modifying operations disallowed """ + sys.exit(2) def catalog_get(scfg, request): scfg.inc_catalog() @@ -161,6 +163,10 @@ def trans_open(scfg, request): # XXX Authentication will be handled by virtue of possessing a signed # certificate (or a more elaborate system). + if scfg.is_read_only(): + request.send_error(403, "Read-only server") + return + t = trans.Transaction() ret = t.open(scfg, request) @@ -178,6 +184,10 @@ def trans_close(scfg, request): + if scfg.is_read_only(): + request.send_error(403, "Read-only server") + return + # Pull transaction ID from headers. m = re.match("^/close/(.*)", request.path) trans_id = m.group(1) @@ -188,6 +198,10 @@ del scfg.in_flight_trans[trans_id] def trans_abandon(scfg, request): + if scfg.is_read_only(): + request.send_error(403, "Read-only server") + return + # Pull transaction ID from headers. m = re.match("^/abandon/(.*)", request.path) trans_id = m.group(1) @@ -197,6 +211,10 @@ del scfg.in_flight_trans[trans_id] def trans_add(scfg, request): + if scfg.is_read_only(): + request.send_error(403, "Read-only server") + return + m = re.match("^/add/([^/]*)/(.*)", request.path) trans_id = m.group(1) type = m.group(2) @@ -263,22 +281,26 @@ pass if __name__ == "__main__": + port = 10000 + + try: + opts, pargs = getopt.getopt(sys.argv[1:], "d:np:", ["readonly"]) + for opt, arg in opts: + if opt == "-n": + sys.exit(0) + elif opt == "-d": + scfg.set_repo_root(arg) + elif opt == "-p": + port = int(arg) + elif opt == "--readonly": + scfg.set_read_only() + except getopt.GetoptError, e: + print "pkg.depotd: unknown option '%s'" % e.opt + usage() + scfg.init_dirs() scfg.acquire_in_flight() scfg.acquire_catalog() - port = 10000 - - try: - opts, pargs = getopt.getopt(sys.argv[1:], "np:") - for opt, arg in opts: - if opt == "-n": - sys.exit(0) - elif opt == "-p": - port = int(arg) - except getopt.GetoptError, e: - print "pkg.depotd: unknown option '%s'" % e.opt - usage() - server = ThreadingHTTPServer(('', port), pkgHandler) server.serve_forever() diff -r 6887274c15a3 -r a1e20e9a9845 src/man/pkg.depotd.1m.txt --- a/src/man/pkg.depotd.1m.txt Fri Oct 05 17:12:55 2007 -0700 +++ b/src/man/pkg.depotd.1m.txt Mon Oct 08 13:18:41 2007 -0700 @@ -1,11 +1,11 @@ -System Administration Commands pkg.depotd(1M) +System Administration Commands pkg.depotd(1M) NAME pkg.depotd - image packaging system depot server SYNOPSIS - /usr/lib/pkg.depotd + /usr/lib/pkg.depotd [--readonly] [-d repo_dir] [-p port] DESCRIPTION pkg.depotd is the depot server for the image packaging system. @@ -20,40 +20,59 @@ properties associated with its service instance. Two properties are currently recognized - application/port (count) The port number on which this - instance of should listen for incoming - package requests. The default value is - 80. + application/port (count) The port number on which this + instance of should listen for incoming + package requests. The default value is + 80. + + application/read_only (boolean) Modifying operations, such as + those initiated by pkgsend(1M) are + disabled. Retrieval operations are + still available. - application/repo_root (astring) The file system path at which - this instance should find its repository - data. The default value is - /var/pkg/repo. + application/repo_dir (astring) The file system path at which + this instance should find its repository + data. The default value is + /var/pkg/repo. + +OPTIONS + The following options alter the default behavior, if present, and + will override the settings from the service instance when managed + via an smf(5) restarter: + + -d repo_dir Overrides application/repo_dir with the + value given by repo_dir. + + -p port Overrides application/port with the + value given by port. + + --readonly Overrides application/read_only to be + true. EXAMPLES Example 1: Enabling the depot server. # svcadm enable application/pkg/server:default - + Example 2: Changing the listening port of the server. # svccfg -s application/pkg/server:default set application/port = 9999 # svcadm refresh application/pkg/server:default # svcadm restart application/pkg/server:default - + EXIT STATUS The following exit values are returned: 0 Successful operation. - 1 Error encountered. + 1 Error encountered. 2 Invalid command line options were specified. FILES - /var/pkg/repo Default repository location; modify - application/repo_root to select an - alternate location. + /var/pkg/repo Default repository location; modify + application/repo_root to select an + alternate location. ATTRIBUTES See attributes(5) for descriptions of the following attri- @@ -71,7 +90,7 @@ The image packaging system is an under-development feature. Command names, invocation, formats, and operations are all subject to change. Development is hosted in the OpenSolaris community - at + at http://opensolaris.org/os/project/pkg/ diff -r 6887274c15a3 -r a1e20e9a9845 src/man/pkgsend.1.txt --- a/src/man/pkgsend.1.txt Fri Oct 05 17:12:55 2007 -0700 +++ b/src/man/pkgsend.1.txt Mon Oct 08 13:18:41 2007 -0700 @@ -22,6 +22,12 @@ pkgsend also has an alternate invocation that allows the conversion of existing software bundles via a submission. +OPTIONS + The following options alter the default behavior: + + -s repo_url The URL prefix of the depot server. The default + value is "http://localhost:10000/ + SUBCOMMANDS The following subcommands are supported: diff -r 6887274c15a3 -r a1e20e9a9845 src/modules/client/image.py --- a/src/modules/client/image.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/modules/client/image.py Mon Oct 08 13:18:41 2007 -0700 @@ -307,7 +307,7 @@ return "known" - def is_installed(self, fmri): + def has_version_installed(self, fmri): """Check that the version given in the FMRI or a successor is installed in the current image.""" @@ -321,6 +321,17 @@ return False + def is_installed(self, fmri): + """Check that the exact version given in the FMRI is installed + in the current image.""" + + try: + v = self.get_version_installed(fmri) + except LookupError: + return False + + return v == fmri + def get_dependents(self, pfmri): """Return a list of the packages directly dependent on the given FMRI.""" diff -r 6887274c15a3 -r a1e20e9a9845 src/modules/client/imageplan.py --- a/src/modules/client/imageplan.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/modules/client/imageplan.py Mon Oct 08 13:18:41 2007 -0700 @@ -113,7 +113,7 @@ def propose_fmri(self, fmri): # is a version of fmri.stem in the inventory? - if self.image.is_installed(fmri): + if self.image.has_version_installed(fmri): return # is there a freeze or incorporation statement? @@ -135,7 +135,7 @@ # XXX Need to make sure that the same package isn't being added and # removed in the same imageplan. def propose_fmri_removal(self, fmri): - if not self.image.is_installed(fmri): + if not self.image.has_version_installed(fmri): return for i, p in enumerate(self.target_rem_fmris): @@ -144,11 +144,9 @@ self.target_rem_fmris[i] = fmri break else: - if "i" not in locals(): - self.target_rem_fmris.append(fmri) + self.target_rem_fmris.append(fmri) def evaluate_fmri(self, pfmri): - # [image] do we have this manifest? if not self.image.has_manifest(pfmri): retrieve.get_manifest(self.image, pfmri) @@ -163,7 +161,7 @@ f = fmri.PkgFmri(a.attrs["fmri"], self.image.attrs["Build-Release"]) - if self.image.is_installed(f): + if self.image.has_version_installed(f): continue # XXX This alone only prevents infinite recursion when a @@ -172,7 +170,8 @@ # what was specified on the commandline, or include what # we've found while processing dependencies? # XXX probably should just use propose_fmri() here - # instead of this and the is_installed() call above. + # instead of this and the has_version_installed() call + # above. if self.is_proposed_fmri(f): continue @@ -194,13 +193,15 @@ if excluded: raise RuntimeError, "excluded by '%s'" % f - # treat-as-required, treat-as-required-unless-pinned, ignore + # treat-as-required, treat-as-required-unless-pinned, + # ignore # skip if ignoring # if pinned # ignore if treat-as-required-unless-pinned # else # **evaluation of incorporations** - # [imageplan] pursue installation of this package --> + # [imageplan] pursue installation of this package + # --> # backtrack or reset?? mvs = self.image.get_matching_pkgs(f) @@ -231,9 +232,18 @@ dependents = self.image.get_dependents(pfmri) + # Don't consider those dependencies already being removed in + # this imageplan transaction. + for i, d in enumerate(dependents): + if fmri.PkgFmri(d, None) in self.target_rem_fmris: + del dependents[i] + if dependents and not self.recursive_removal: - print "Cannot remove '%s' due to" % pfmri - print "the following packages that directly depend on it:" + # XXX Module function is printing, should raise or have + # complex return. + print """\ +Cannot remove '%s' due to the following packages that directly depend on it:"""\ + % pfmri for d in dependents: print " ", fmri.PkgFmri(d, "") return @@ -243,6 +253,7 @@ pp = pkgplan.PkgPlan(self.image) try: + print "pkgplan remove %s proposed" % pfmri pp.propose_removal(pfmri, m) except RuntimeError: print "pkg %s not installed" % pfmri @@ -253,8 +264,10 @@ for d in dependents: rf = fmri.PkgFmri(d, None) if self.is_proposed_rem_fmri(rf): + print "%s is already proposed for removal" % rf continue - if not self.image.is_installed(rf): + if not self.image.has_version_installed(rf): + print "%s is not installed" % rf continue self.target_rem_fmris.append(rf) self.evaluate_fmri_removal(rf) diff -r 6887274c15a3 -r a1e20e9a9845 src/modules/client/pkgplan.py --- a/src/modules/client/pkgplan.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/modules/client/pkgplan.py Mon Oct 08 13:18:41 2007 -0700 @@ -33,7 +33,7 @@ """A package plan takes two package FMRIs and an Image, and produces the set of actions required to take the Image from the origin FMRI to the destination FMRI. - + If the destination FMRI is None, the package is removed. """ @@ -117,7 +117,7 @@ f = file("%s/pkg/%s/filters" % \ (self.image.imgdir, self.origin_fmri.get_dir_path()), "r") - except OSError, e: + except IOError, e: if e.errno != errno.ENOENT: raise else: @@ -141,7 +141,7 @@ def preexecute(self): """Perform actions required prior to installation or removal of a package. - + This method executes each action's preremove() or preinstall() methods, as well as any package-wide steps that need to be taken at such a time. @@ -154,8 +154,13 @@ os.unlink("%s/pkg/%s/installed" % (self.image.imgdir, self.origin_fmri.get_dir_path())) - os.unlink("%s/pkg/%s/filters" % (self.image.imgdir, - self.origin_fmri.get_dir_path())) + try: + os.unlink("%s/pkg/%s/filters" % ( + self.image.imgdir, + self.origin_fmri.get_dir_path())) + except OSError, e: + if e.errno != errno.ENOENT: + raise for src, dest in self.actions: if dest: @@ -193,7 +198,7 @@ def execute(self): """Perform actions for installation or removal of a package. - + This method executes each action's remove() or install() methods. """ @@ -219,7 +224,7 @@ def postexecute(self): """Perform actions required after installation or removal of a package. - + This method executes each action's postremove() or postinstall() methods, as well as any package-wide steps that need to be taken at such a time. @@ -238,8 +243,13 @@ os.unlink("%s/pkg/%s/installed" % (self.image.imgdir, self.origin_fmri.get_dir_path())) - os.unlink("%s/pkg/%s/filters" % (self.image.imgdir, - self.origin_fmri.get_dir_path())) + try: + os.unlink("%s/pkg/%s/filters" % ( + self.image.imgdir, + self.origin_fmri.get_dir_path())) + except OSError, e: + if e.errno != errno.ENOENT: + raise if self.destination_fmri != None: file("%s/pkg/%s/installed" % (self.image.imgdir, @@ -260,7 +270,7 @@ def make_indices(self): """Create the reverse index databases for a particular package. - + These are the databases mapping packaging object attribute values back to their corresponding packages, allowing the packaging system to look up a package based on, say, the diff -r 6887274c15a3 -r a1e20e9a9845 src/modules/publish/transaction.py --- a/src/modules/publish/transaction.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/modules/publish/transaction.py Mon Oct 08 13:18:41 2007 -0700 @@ -168,7 +168,7 @@ try: r = c.getresponse() except httplib.BadStatusLine: - print "Server-side exception for:", action + print "Server-side exception for '%s'" % action return 500 return r.status diff -r 6887274c15a3 -r a1e20e9a9845 src/modules/server/config.py --- a/src/modules/server/config.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/modules/server/config.py Mon Oct 08 13:18:41 2007 -0700 @@ -25,7 +25,9 @@ # Use is subject to license terms. # +import errno import os +import statvfs import urllib import pkg.catalog as catalog @@ -34,6 +36,11 @@ import pkg.server.transaction as trans +# OpenSolaris: statvfs(2) flags field +ST_RDONLY = 0x01 +ST_NOSUID = 0x02 +ST_NOTRUNC = 0x04 + # depot Server Configuration class SvrConfig(object): @@ -43,13 +50,12 @@ transactions and packages stored by the repository.""" def __init__(self, repo_root, authority): - self.repo_root = repo_root - self.trans_root = "%s/trans" % self.repo_root - self.file_root = "%s/file" % self.repo_root - self.pkg_root = "%s/pkg" % self.repo_root + self.set_repo_root(repo_root) self.authority = authority + self.read_only = False + self.catalog = catalog.Catalog() self.in_flight_trans = {} @@ -64,13 +70,52 @@ self.flist_files = 0 def init_dirs(self): - # XXX refine try/except + root_needed = False + try: + vfs = os.statvfs(self.repo_root) + except OSError, e: + if e.errno == errno.ENOENT: + root_needed = True + else: + raise + + if root_needed: + try: + os.makedirs(self.repo_root) + except OSError, e: + raise + + vfs = os.statvfs(self.repo_root) + + emsg = "repository directories incomplete" + + if vfs[statvfs.F_FLAG] & ST_RDONLY != 0: + self.set_read_only() + emsg = "repository directories read-only and incomplete" + else: os.makedirs(self.trans_root) os.makedirs(self.file_root) os.makedirs(self.pkg_root) - except OSError: - pass + + if os.path.exists(self.trans_root) and \ + os.path.exists(self.file_root) and \ + os.path.exists(self.pkg_root): + return + + raise RuntimeError, emsg + + def set_repo_root(self, root): + self.repo_root = root + self.trans_root = "%s/trans" % self.repo_root + self.file_root = "%s/file" % self.repo_root + self.pkg_root = "%s/pkg" % self.repo_root + + def set_read_only(self): + self.read_only = True + + def is_read_only(self): + return self.read_only def acquire_in_flight(self): """Walk trans_root, acquiring valid transaction IDs.""" diff -r 6887274c15a3 -r a1e20e9a9845 src/publish.py --- a/src/publish.py Fri Oct 05 17:12:55 2007 -0700 +++ b/src/publish.py Mon Oct 08 13:18:41 2007 -0700 @@ -40,8 +40,10 @@ # pkgsend close -A import getopt +import gettext import os import sys +import threading import traceback import pkg.bundle @@ -54,10 +56,9 @@ import pkg.publish.transaction as trans import pkg.Queue25 as Queue25 -import threading def usage(): - print """\ + print _("""\ Usage: pkgsend [options] command [cmd_options] [operands] @@ -74,10 +75,10 @@ pkgsend close [-A] Options: - --repo, -s + -s repo_url destination repository server URL prefix Environment: - PKG_REPO""" + PKG_REPO""") sys.exit(2) def trans_open(config, args): @@ -86,7 +87,7 @@ try: opts, pargs = getopt.getopt(args, "e") except getopt.GetoptError, e: - print "pkgsend: illegal open option '%s'" % e.opt + print _("pkgsend: illegal open option '%s'") % e.opt usage() eval_form = True @@ -97,7 +98,7 @@ eval_form = False if len(pargs) != 1: - print "pkgsend: open requires one package name" + print _("pkgsend: open requires one package name") usage() t = trans.Transaction() @@ -105,11 +106,11 @@ status, id = t.open(config, pargs[0]) if status / 100 == 4 or status / 100 == 5: - print "pkgsend: server failed (status %s)" % status + print _("pkgsend: server failed (status %s)") % status sys.exit(1) if id == None: - print "pkgsend: no transaction ID provided in response" + print _("pkgsend: no transaction ID provided in response") sys.exit(1) if eval_form: @@ -135,7 +136,7 @@ if opt == "-t": trans_id = arg except getopt.GetoptError, e: - print "pkgsend: illegal option to close '%s'" % e.opt + print _("pkgsend: illegal option to close: '%s'") % e.opt usage() if trans_id == None: @@ -157,8 +158,6 @@ else: print "Failed with", ret - return - def trans_add(config, args): try: trans_id = os.environ["PKG_TRANS_ID"] @@ -187,7 +186,7 @@ """Via POST request, transfer a piece of metadata to the server.""" if not args[0] in ["set", "unset"]: - print "pkgsend: unknown metadata item '%s'" % args[0] + print _("pkgsend: unknown metadata item '%s'") % args[0] usage() trans_id = os.environ["PKG_TRANS_ID"] @@ -197,9 +196,6 @@ return -def trans_summary(config, args): - return - def batch(config, args): return @@ -273,21 +269,32 @@ t.close(config, id) - -pcfg = config.ParentRepo("http://localhost:10000", ["http://localhost:10000"]) +try: + repo = os.environ["PKG_REPO"] +except KeyError: + repo_url = "http://localhost:10000" if __name__ == "__main__": + # XXX /usr/lib/locale is OpenSolaris-specific. + gettext.install("pkgsend", "/usr/lib/locale") + opts = None pargs = None try: - opts, pargs = getopt.getopt(sys.argv[1:], "s:R:") + opts, pargs = getopt.getopt(sys.argv[1:], "s:") + for opt, arg in opts: + if opt == "-s": + repo_url = arg + except getopt.GetoptError, e: - print "pkgsend: illegal global option '%s'" % e.opt + print _("pkgsend: illegal global option '%s'") % e.opt usage() if pargs == None or len(pargs) == 0: usage() + pcfg = config.ParentRepo(repo_url, [repo_url]) + subcommand = pargs[0] del pargs[0] @@ -300,7 +307,7 @@ elif subcommand == "send": send_bundles(pcfg, pargs) else: - print "pkgsend: unknown subcommand '%s'" % subcommand + print _("pkgsend: unknown subcommand '%s'") % subcommand usage() sys.exit(0) diff -r 6887274c15a3 -r a1e20e9a9845 src/tests/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tests/README Mon Oct 08 13:18:41 2007 -0700 @@ -0,0 +1,38 @@ + +Copyright 2007 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. + +tests/README + + 1. Summary + + The global test target, i.e. "make test", should be executed prior to + requesting code review and prior to integration. That target invokes + both the unit tests embedded in a subset of the modules and the + tests/cli-complete.ksh script. The remainder of tests/ is a + miscellany of ksh scripts that do various small dependency scenarios. + + cli-complete.ksh is a script that exercises each of the command line + options of pkg(1) and pkgsend(1), using a variety of dependency + scenarios. + + 2. Pending work. + + The embedded tests from the various modules should become disembedded + and coded to use the Python unittest testing framework module. + + The special dependency scenarios should be recoded as part of + cli-compelete.ksh + + Targets to evaluate code coverage [1,2] should be added, possibly with + supporting global options added to each utility. + + 3. References + + [1] N. Batchelder, coverage module, 2007. + http://nedbatchelder.com/code/modules/coverage.html + + [2] C. T. Brown, figleaf module, 2006. + http://darcs.idyll.org/~t/projects/figleaf/README.html + + diff -r 6887274c15a3 -r a1e20e9a9845 src/tests/cli-complete.ksh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tests/cli-complete.ksh Mon Oct 08 13:18:41 2007 -0700 @@ -0,0 +1,338 @@ +#!/bin/ksh -px +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# + +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +# cli-complete.ksh - basic sanity test exercising all basic pkg(1) operations +# +# cli-complete.ksh runs out of $HG/src/tests, and runs an depot server +# and issues pkg(1) commands from the $HG/proto directory relevant to +# the executing system. +# +# XXX Should really select which cases to run. + +REPO_PORT=${REPO_PORT:-8000} +REPO_DIR=/tmp/repo.$$ +REPO_URL=http://localhost:$REPO_PORT +IMAGE_DIR=/tmp/image.$$ + +restore_dir=$PWD + +ROOT=$PWD/../../proto/root_$(uname -p) + +export PYTHONPATH=$ROOT/usr/lib/python2.4/vendor-packages/ +export PATH=$ROOT/usr/bin:$PATH + +$ROOT/usr/lib/pkg.depotd -p $REPO_PORT -d $REPO_DIR & + +DEPOT_PID=$! + +sleep 1 + +usage () { + cli-complete.ksh + exit 2 +} + +depot_cleanup () { + kill $DEPOT_PID + sleep 1 + if ps -p $DEPOT_PID > /dev/null; then + kill -9 $DEPOT_PID + fi + rm -fr $REPO_DIR + exit $1 +} + +image_cleanup () { + cd $restore_dir + rm -fr $IMAGE_DIR +} + +fail () { + echo "*** case $tcase: $@" + exit 1 +} + +trap "ret=$?; image_cleanup; depot_cleanup $ret" EXIT + +# Case 1. Send empty package foo@1.0, install and uninstall. +# {{{1 + +tcase=1 +trans_id=$(pkgsend -s $REPO_URL open foo@1.0,5.11-0) +if [[ $? != 0 ]]; then + fail pkgsend open failed +fi + +eval $trans_id + +if ! pkgsend -s $REPO_URL close; then + fail pkgsend close failed +fi + +if ! pkg image-create -F -a test=$REPO_URL $IMAGE_DIR; then + fail pkg image-create failed +fi + +find $IMAGE_DIR + +cd $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +if ! pkg install foo; then + fail pkg install foo failed +fi + +find $IMAGE_DIR + +if ! pkg status; then + fail pkg status failed +fi + +if ! pkg uninstall foo; then + fail pkg uninstall foo failed +fi + +find $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +# }}}1 + +# Case 2. Send package foo@1.1, containing a directory and a file, +# install and uninstall. +# {{{1 + +tcase=2 +trans_id=$(pkgsend -s $REPO_URL open foo@1.1,5.11-0) +if [[ $? != 0 ]]; then + fail pkgsend open failed +fi + +eval $trans_id + +if ! pkgsend -s $REPO_URL add dir mode=0755 owner=root group=bin path=/lib; then + fail pkgsend add dir failed +fi + +if ! pkgsend -s $REPO_URL add file /lib/libc.so.1 mode=0555 owner=root group=bin \ + path=/lib/libc.so.1; then + fail pkgsend add file failed +fi + +if ! pkgsend -s $REPO_URL close; then + fail pkgsend close failed +fi + +if ! pkg image-create -F -a test=$REPO_URL $IMAGE_DIR; then + fail pkg image-create failed + image_cleanup +fi + +find $IMAGE_DIR + +cd $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +if ! pkg install foo; then + fail pkg install foo failed +fi + +find $IMAGE_DIR + +if ! pkg status; then + fail pkg status failed +fi + +if ! pkg uninstall foo; then + fail pkg uninstall foo failed +fi + +find $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +# }}}1 + +# Case 3. Install foo@1.0, upgrade to foo@1.1, uninstall. +# {{{1 + +tcase=3 + +if ! pkg image-create -F -a test=$REPO_URL $IMAGE_DIR; then + fail pkgsend close failed +fi + +find $IMAGE_DIR + +cd $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +if ! pkg install foo@1.0; then + fail pkg install foo failed +fi + +find $IMAGE_DIR + +if ! pkg status; then + fail pkg status failed +fi + +if ! pkg install foo@1.1; then + fail pkg install foo \(1.0 -\> 1.1\) failed +fi + +find $IMAGE_DIR + +if ! pkg uninstall foo; then + fail pkg status failed +fi + +find $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +# }}}1 + +# Case 4. Add bar@1.0, dependent on foo@1.0, install, uninstall. +# {{{1 + +tcase=4 +trans_id=$(pkgsend -s $REPO_URL open bar@1.0,5.11-0) +if [[ $? != 0 ]]; then + fail pkgsend open failed +fi + +eval $trans_id + +if ! pkgsend -s $REPO_URL add depend type=require fmri=pkg:/foo@1.0; then + fail pkgsend add depend require failed +fi + +if ! pkgsend -s $REPO_URL add dir mode=0755 owner=root group=bin path=/bin; then + fail pkgsend add dir failed +fi + +if ! pkgsend -s $REPO_URL add file /bin/cat mode=0555 owner=root group=bin \ + path=/bin/cat; then + fail pkgsend add file failed +fi + +if ! pkgsend -s $REPO_URL close; then + fail pkgsend close failed +fi + +if ! pkg image-create -F -a test=$REPO_URL $IMAGE_DIR; then + fail pkgsend close failed +fi + +find $IMAGE_DIR + +cd $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +if ! pkg install bar@1.0; then + fail pkg install bar failed +fi + +find $IMAGE_DIR + +if ! pkg status; then + fail pkg status failed +fi + +find $IMAGE_DIR + +if ! pkg uninstall -v bar foo; then + fail pkg uninstall failed +fi + +find $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +# }}}1 + +# Case 5. Install bar@1.0, dependent on foo@1.0, uninstall recursively. +# {{{1 + +tcase=5 + +if ! pkg image-create -F -a test=$REPO_URL $IMAGE_DIR; then + fail pkg image-create failed +fi + +find $IMAGE_DIR + +cd $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +if ! pkg install bar@1.0; then + fail pkg install bar failed +fi + +find $IMAGE_DIR + +if ! pkg status; then + fail pkg status failed +fi + +find $IMAGE_DIR + +if ! pkg uninstall -vr bar; then + fail pkg uninstall -vr failed +fi + +find $IMAGE_DIR + +if ! pkg status -a; then + fail pkg status -a failed +fi + +# }}}1 + +exit 0