--- 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)
--- 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()
--- 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/
--- 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:
--- 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."""
--- 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)
--- 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
--- 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
--- 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."""
--- 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)
--- /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
+
+
--- /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 [email protected], install and uninstall.
+# {{{1
+
+tcase=1
+trans_id=$(pkgsend -s $REPO_URL open [email protected],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 [email protected], containing a directory and a file,
+# install and uninstall.
+# {{{1
+
+tcase=2
+trans_id=$(pkgsend -s $REPO_URL open [email protected],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 [email protected], upgrade to [email protected], 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 [email protected]; then
+ fail pkg install foo failed
+fi
+
+find $IMAGE_DIR
+
+if ! pkg status; then
+ fail pkg status failed
+fi
+
+if ! pkg install [email protected]; 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 [email protected], dependent on [email protected], install, uninstall.
+# {{{1
+
+tcase=4
+trans_id=$(pkgsend -s $REPO_URL open [email protected],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:/[email protected]; 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 [email protected]; 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 [email protected], dependent on [email protected], 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 [email protected]; 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