Add the license action
authorDanek Duvall <danek.duvall@sun.com>
Mon, 08 Oct 2007 13:36:55 -0700
changeset 136 da65641c4607
parent 135 a1e20e9a9845
child 137 82a6c035a6da
Add the license action
src/Makefile
src/modules/actions/directory.py
src/modules/actions/driver.py
src/modules/actions/file.py
src/modules/actions/generic.py
src/modules/actions/hardlink.py
src/modules/actions/license.py
src/modules/actions/link.py
src/modules/client/pkgplan.py
src/publish.py
--- a/src/Makefile	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/Makefile	Mon Oct 08 13:36:55 2007 -0700
@@ -96,6 +96,7 @@
 	modules/actions/file.py \
 	modules/actions/generic.py \
 	modules/actions/hardlink.py \
+	modules/actions/license.py \
 	modules/actions/link.py \
 	modules/actions/unknown.py
 PYCACTIONMODS = $(PYACTIONMODS:%.py=%.pyc)
--- a/src/modules/actions/directory.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/directory.py	Mon Oct 08 13:36:55 2007 -0700
@@ -47,7 +47,7 @@
         def __init__(self, data=None, **attrs):
                 generic.Action.__init__(self, data, **attrs)
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
                 """Client-side method that installs a directory."""
                 path = self.attrs["path"]
                 mode = int(self.attrs["mode"], 8)
@@ -60,14 +60,14 @@
                         ogroup = grp.getgrnam(orig.attrs["group"]).gr_gid
 
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), path)))
+                    (pkgplan.image.get_root(), path)))
 
                 # XXX Hack!  (See below comment.)
                 mode |= 0200
 
                 if not orig:
                         try:
-                                self.makedirs(path, mode)
+                                self.makedirs(path, mode = mode)
                         except OSError, e:
                                 if e.errno != errno.EEXIST:
                                         raise
@@ -93,9 +93,9 @@
                                 if e.errno != errno.EPERM:
                                         raise
 
-        def remove(self, image):
+        def remove(self, pkgplan):
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), self.attrs["path"])))
+                    (pkgplan.image.get_root(), self.attrs["path"])))
 
                 try:
                         os.rmdir(path)
--- a/src/modules/actions/driver.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/driver.py	Mon Oct 08 13:36:55 2007 -0700
@@ -60,7 +60,8 @@
         def __init__(self, data=None, **attrs):
                 generic.Action.__init__(self, data, **attrs)
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
+                image = pkgplan.image
                 n2m = os.path.normpath(os.path.sep.join(
                     (image.get_root(), "etc/name_to_major")))
 
@@ -191,11 +192,11 @@
                                     "return code %s" % \
                                     (self.name, self.attrs["name"], retcode)
 
-        def remove(self, image):
+        def remove(self, pkgplan):
                 args = (
                     self.rem_drv,
                     "-b",
-                    image.get_root(),
+                    pkgplan.image.get_root(),
                     self.attrs["name"]
                 )
 
--- a/src/modules/actions/file.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/file.py	Mon Oct 08 13:36:55 2007 -0700
@@ -49,7 +49,7 @@
                 generic.Action.__init__(self, data, **attrs)
                 self.hash = "NOHASH"
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
                 """Client-side method that installs a file."""
                 path = self.attrs["path"]
                 mode = int(self.attrs["mode"], 8)
@@ -57,7 +57,7 @@
                 group = grp.getgrnam(self.attrs["group"]).gr_gid
 
                 final_path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), path)))
+                    (pkgplan.image.get_root(), path)))
 
                 # If we're upgrading, extract the attributes from the old file.
                 if orig:
@@ -94,7 +94,7 @@
                 # XXX This needs to be controlled by policy.
                 if self.needsdata(orig): 
                         temp = os.path.normpath(os.path.sep.join(
-                            (image.get_root(), path + "." + self.hash)))
+                            (pkgplan.image.get_root(), path + "." + self.hash)))
 
                         stream = self.data()
                         tfile = file(temp, "wb")
@@ -138,9 +138,9 @@
                 return False
 
 
-        def remove(self, image):
+        def remove(self, pkgplan):
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), self.attrs["path"])))
+                    (pkgplan.image.get_root(), self.attrs["path"])))
 
                 os.unlink(path)
 
--- a/src/modules/actions/generic.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/generic.py	Mon Oct 08 13:36:55 2007 -0700
@@ -273,14 +273,16 @@
                 return indices
 
         @staticmethod
-        def makedirs(path, leafmode):
-                """Make directory specified by 'path' with mode 'leafmode', as
-                well as all missing parent directories.
+        def makedirs(path, **kw):
+                """Make directory specified by 'path' with given permissions, as
+                well as all missing parent directories.  Permissions are
+                specified by the keyword arguments 'mode', 'uid', and 'gid'.
 
-                The difference between this and os.makedirs() is that 'leafmode'
-                specifies only the mode of the leaf directory.  Missing parent
-                directories are created with the permissions of the deepest
-                existing directory."""
+                The difference between this and os.makedirs() is that the
+                permissions specify only those of the leaf directory.  Missing
+                parent directories inherit the permissions of the deepest
+                existing directory.  The leaf directory will also inherit any
+                permissions not explicitly set."""
 
                 pathlist = path.split("/")
                 pathlist[0] = "/"
@@ -289,13 +291,32 @@
                 for i, e in g:
                         if not os.path.isdir(os.path.join("/", *pathlist[:i + 1])):
                                 break
+                else:
+                        # If we run off the end of the list, the requested
+                        # directory is present, so we can just return.
+                        return
 
-                # XXX need to set owner/group, too
-                mode = os.stat(os.path.join("/", *pathlist[:i])).st_mode
+                stat = os.stat(os.path.join("/", *pathlist[:i]))
                 for i, e in g:
-                        os.mkdir(os.path.join("/", *pathlist[:i]), mode)
+                        p = os.path.join("/", *pathlist[:i])
+                        os.mkdir(p, stat.st_mode)
+                        try:
+                                os.chown(p, stat.st_uid, stat.st_gid)
+                        except OSError, e:
+                                if e.errno != errno.EPERM:
+                                        raise
 
-                os.mkdir(path, leafmode)
+                # Create the leaf with any requested permissions, substituting
+                # missing perms with the parent's perms.
+                mode = kw.get("mode", stat.st_mode)
+                uid = kw.get("uid", stat.st_uid)
+                gid = kw.get("gid", stat.st_gid)
+                os.mkdir(path, mode)
+                try:
+                        os.chown(path, uid, gid)
+                except OSError, e:
+                        if e.errno != errno.EPERM:
+                                raise
 
         def needsdata(self, orig):
                 """Returns True if the action transition requires a
@@ -310,26 +331,26 @@
                 else:
                         return [ value ]
 
-        def preinstall(self, image, orig):
+        def preinstall(self, pkgplan, orig):
                 """Client-side method that performs pre-install actions."""
                 pass
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
                 """Client-side method that installs the object."""
                 pass
 
-        def postinstall(self, image, orig):
+        def postinstall(self, pkgplan, orig):
                 """Client-side method that performs post-install actions."""
                 pass
 
-        def preremove(self, image):
+        def preremove(self, pkgplan):
                 """Client-side method that performs pre-remove actions."""
                 pass
 
-        def remove(self, image):
+        def remove(self, pkgplan):
                 """Client-side method that removes the object."""
                 pass
 
-        def postremove(self, image):
+        def postremove(self, pkgplan):
                 """Client-side method that performs post-remove actions."""
                 pass
--- a/src/modules/actions/hardlink.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/hardlink.py	Mon Oct 08 13:36:55 2007 -0700
@@ -42,14 +42,14 @@
         def __init__(self, data=None, **attrs):
                 link.LinkAction.__init__(self, data, **attrs)
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
                 """Client-side method that installs a hard link."""
 
                 path = self.attrs["path"]
                 target = self.attrs["target"]
 
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), path)))
+                    (pkgplan.image.get_root(), path)))
 
                 if os.path.exists(path):
                         os.unlink(path)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/actions/license.py	Mon Oct 08 13:36:55 2007 -0700
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+#
+# 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.
+#
+
+"""module describing a license packaging object
+
+This module contains the LicenseAction class, which represents a license
+packaging object.  This contains a payload of the license text, and a single
+attribute, 'license', which is the name of the license.  Licenses are
+installed on the system in the package's directory."""
+
+import os
+import errno
+import sha
+
+import generic
+
+class LicenseAction(generic.Action):
+        """Class representing a license packaging object."""
+
+        name = "license"
+        key_attr = "license"
+        reverse_indices = ("license", )
+
+        def __init__(self, data=None, **attrs):
+                generic.Action.__init__(self, data, **attrs)
+                self.hash = "NOHASH"
+
+        def install(self, pkgplan, orig):
+                """Client-side method that installs the license."""
+                mode = 0444
+                owner = 0
+                group = 0
+
+                path = os.path.normpath(os.path.join(pkgplan.image.imgdir,
+                    "pkg", pkgplan.destination_fmri.get_dir_path(),
+                    "license." + self.attrs["license"]))
+
+                stream = self.data()
+                lfile = file(path, "wb")
+                # XXX Should throw an exception if shasum doesn't match
+                # self.hash
+                shasum = generic.gunzip_from_stream(stream, lfile)
+
+                lfile.close()
+                stream.close()
+
+                os.chmod(path, mode)
+
+                try:
+                        os.chown(path, owner, group)
+                except OSError, e:
+                        if e.errno != errno.EPERM:
+                                raise
+
+        def remove(self, pkgplan):
+                path = os.path.normpath(os.path.join(pkgplan.image.imgdir,
+                    "pkg", pkgplan.origin_fmri.get_dir_path(),
+                    "license." + self.attrs["license"]))
+
+                os.unlink(path)
--- a/src/modules/actions/link.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/actions/link.py	Mon Oct 08 13:36:55 2007 -0700
@@ -44,7 +44,7 @@
         def __init__(self, data=None, **attrs):
                 generic.Action.__init__(self, data, **attrs)
 
-        def install(self, image, orig):
+        def install(self, pkgplan, orig):
                 """Client-side method that installs a link."""
                 # XXX The exists-unlink-symlink path appears to be as safe as it
                 # gets with the current symlink(2) interface.
@@ -53,15 +53,15 @@
                 target = self.attrs["target"]
 
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), path)))
+                    (pkgplan.image.get_root(), path)))
 
                 if os.path.lexists(path):
                         os.unlink(path)
 
                 os.symlink(target, path)
 
-        def remove(self, image):
+        def remove(self, pkgplan):
                 path = os.path.normpath(os.path.sep.join(
-                    (image.get_root(), self.attrs["path"])))
+                    (pkgplan.image.get_root(), self.attrs["path"])))
 
                 os.unlink(path)
--- a/src/modules/client/pkgplan.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/modules/client/pkgplan.py	Mon Oct 08 13:36:55 2007 -0700
@@ -164,9 +164,9 @@
 
                 for src, dest in self.actions:
                         if dest:
-                                dest.preinstall(self.image, src)
+                                dest.preinstall(self, src)
                         else:
-                                src.preremove(self.image)
+                                src.preremove(self)
 
                         if dest and dest.needsdata(src) and flist_supported:
 
@@ -212,7 +212,7 @@
                 for src, dest in self.actions:
                         if dest:
                                 try:
-                                        dest.install(self.image, src)
+                                        dest.install(self, src)
                                 except Exception, e:
                                         print "Action install failed for '%s' (%s):\n  %s: %s" % \
                                             (dest.attrs.get(dest.key_attr, id(dest)),
@@ -220,7 +220,7 @@
                                             e.__class__.__name__, e)
                                         raise
                         else:
-                                src.remove(self.image)
+                                src.remove(self)
 
         def postexecute(self):
                 """Perform actions required after installation or removal of a package.
@@ -232,9 +232,9 @@
                 # record that package states are consistent
                 for src, dest in self.actions:
                         if dest:
-                                dest.postinstall(self.image, src)
+                                dest.postinstall(self, src)
                         else:
-                                src.postremove(self.image)
+                                src.postremove(self)
 
                 # In the case of an upgrade, remove the installation turds from
                 # the origin's directory.
--- a/src/publish.py	Mon Oct 08 13:18:41 2007 -0700
+++ b/src/publish.py	Mon Oct 08 13:36:55 2007 -0700
@@ -165,7 +165,7 @@
                 print "No transaction ID specified in $PKG_TRANS_ID"
                 sys.exit(1)
 
-        if args[0] == "file":
+        if args[0] in ("file", "license"):
                 action = pkg.actions.fromlist(args[0], args[2:])
                 def opener():
                         return open(args[1])