__init__.py revision 1500
591N/A#!/usr/bin/python2.4
591N/A#
591N/A# CDDL HEADER START
591N/A#
591N/A# The contents of this file are subject to the terms of the
591N/A# Common Development and Distribution License (the "License").
591N/A# You may not use this file except in compliance with the License.
591N/A#
591N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
591N/A# or http://www.opensolaris.org/os/licensing.
591N/A# See the License for the specific language governing permissions
591N/A# and limitations under the License.
591N/A#
591N/A# When distributing Covered Code, include this CDDL HEADER in each
591N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
591N/A# If applicable, add the following below this CDDL HEADER, with the
591N/A# fields enclosed by brackets "[]" replaced with your own identifying
591N/A# information: Portions Copyright [yyyy] [name of copyright owner]
591N/A#
591N/A# CDDL HEADER END
591N/A#
591N/A
2639N/A#
591N/A# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
591N/A# Use is subject to license terms.
591N/A#
591N/A
591N/A"""
591N/Apackage containing packaging action (file type) modules
591N/A
1659N/AThis package contains modules describing packaging actions, or file types. The
2639N/Aactions are dynamically discovered, so that new modules can be placed in this
2639N/Apackage directory and they'll just be picked up. The current package contents
2639N/Acan be seen in the section "PACKAGE CONTENTS", below.
2639N/A
2639N/AThis package has one data member: "types". This is a dictionary which maps the
2639N/Aaction names to the classes that represent them.
2639N/A
2639N/AThis package also has one function: "fromstr", which creates an action instance
2639N/Abased on a str() representation of an action.
2639N/A"""
2639N/A
2639N/Aimport inspect
2639N/Aimport os
2639N/A
591N/A# All modules in this package (all python files except __init__.py with their
2639N/A# extensions stripped off).
2457N/A__all__ = [
2639N/A f[:-3]
591N/A for f in os.listdir(__path__[0])
591N/A if f.endswith(".py") and f != "__init__.py"
2639N/A]
2639N/A
2639N/A# A dictionary of all the types in this package, mapping to the classes that
591N/A# define them.
2639N/Atypes = {}
1846N/Afor modname in __all__:
2639N/A module = __import__("%s.%s" % (__name__, modname),
2639N/A globals(), locals(), [modname])
2639N/A
2639N/A nvlist = inspect.getmembers(module, inspect.isclass)
2639N/A
591N/A # Pull the class objects out of nvlist, keeping only those that are
591N/A # actually defined in this package.
2639N/A classes = [
2639N/A c[1]
2639N/A for c in nvlist
2639N/A if '.'.join(c[1].__module__.split('.')[:-1]) == __name__
2639N/A ]
2639N/A for cls in classes:
2639N/A types[cls.name] = cls
2639N/A
591N/A# Clean up after ourselves
591N/Adel f, modname, module, nvlist, classes, c, cls
1973N/A
591N/Aclass ActionError(Exception):
591N/A """Base exception class for Action errors."""
591N/A
591N/A def __str__(self):
629N/A raise NotImplementedError()
591N/A
629N/Aclass UnknownActionError(ActionError):
629N/A def __init__(self, *args):
591N/A self.actionstr = args[0]
591N/A self.type = args[1]
1973N/A
1659N/A def __str__(self):
1659N/A if hasattr(self, "fmri") and self.fmri is not None:
1659N/A return _("unknown action type '%(type)s' in package "
1659N/A "'%(fmri)s' in action '%(action)s'") % {
1659N/A "type": self.type, "fmri": self.fmri,
1659N/A "action": self.actionstr }
1659N/A return _("unknown action type '%(type)s' in action "
1659N/A "'%(action)s'") % { "type": self.type,
1659N/A "action": self.actionstr }
1659N/A
591N/Aclass MalformedActionError(ActionError):
591N/A def __init__(self, *args):
2639N/A self.actionstr = args[0]
591N/A self.position = args[1]
1890N/A self.errorstr = args[2]
1890N/A
2457N/A def __str__(self):
1890N/A marker = " " * (4 + self.position) + "^"
2233N/A if hasattr(self, "fmri") and self.fmri is not None:
2639N/A return _("Malformed action in package '%(fmri)s' at "
1659N/A "position: %(pos)d:\n %(action)s\n"
2233N/A "%(marker)s") % { "fmri": self.fmri,
591N/A "pos": self.position, "action": self.actionstr,
2639N/A "marker": marker }
2639N/A return _("Malformed action at position: %(pos)d:\n "
2639N/A "%(action)s\n%(marker)s") % { "pos": self.position,
2639N/A "action": self.actionstr, "marker": marker }
591N/A
591N/A
591N/Aclass ActionDataError(ActionError):
591N/A """Used to indicate that a file-related error occuring during action
591N/A initialization."""
2639N/A
2639N/A def __init__(self, *args):
2639N/A self.error = args[0]
2639N/A
591N/A def __str__(self):
591N/A return str(self.error)
1973N/A
1973N/A
1973N/Aclass InvalidActionError(ActionError):
1973N/A """Used to indicate that attributes provided were invalid, or required
1973N/A attributes were missing for an action."""
1973N/A
2639N/A def __init__(self, *args):
2639N/A self.actionstr = args[0]
2639N/A self.errorstr = args[1]
1890N/A
1846N/A def __str__(self):
1846N/A if hasattr(self, "fmri") and self.fmri is not None:
1846N/A return _("invalid action in package %(fmri)s: "
2457N/A "%(action)s: %(error)s") % { "fmri": self.fmri,
2457N/A "action": self.actionstr, "error": self.errorstr }
591N/A return _("invalid action, '%(action)s': %(error)s") % {
1890N/A "action": self.actionstr, "error": self.errorstr }
2639N/A
2639N/A
2639N/Afrom _actions import _fromstr
2639N/A
2639N/Adef attrsfromstr(string):
2639N/A """Create an attribute dict given a string w/ key=value pairs.
2639N/A
2639N/A Raises MalformedActionError if the attributes have syntactic problems.
2639N/A """
2639N/A return _fromstr("bogus %s" % string)[2]
1890N/A
1890N/Adef fromstr(string, data=None):
1890N/A """Create an action instance based on a str() representation of an
1890N/A action.
1890N/A
2639N/A Raises UnknownActionError if the action type is unknown.
2639N/A Raises MalformedActionError if the action has other syntactic problems.
591N/A """
591N/A
591N/A atype, ahash, attr_dict = _fromstr(string)
591N/A
591N/A if atype not in types:
591N/A raise UnknownActionError(string, atype)
1890N/A
1973N/A action = types[atype](data=data, **attr_dict)
1890N/A
1973N/A ka = action.key_attr
1890N/A if ka is not None and (ka not in action.attrs or
591N/A action.attrs[ka] is None):
2639N/A raise InvalidActionError(string, _("required attribute '%s' "
2639N/A "was not provided.") % ka)
2639N/A
2639N/A if ahash:
2639N/A action.hash = ahash
2639N/A
2639N/A return action
2639N/A
2639N/Adef internalizelist(atype, args, ahash=None, basedirs=None):
2639N/A """Create an action instance based on a sequence of "key=value" strings.
2639N/A This function also translates external representations of actions with
2639N/A payloads (like file and license which can use NOHASH or file paths to
2639N/A point to the payload) to an internal representation which sets the
2639N/A data field of the action returned.
2639N/A
2639N/A The "atype" parameter is the type of action to be built.
2639N/A
2639N/A The "args" parameter is the sequence of "key=value" strings.
2639N/A
2639N/A The "ahash" parameter is used to set the hash value for the action.
2639N/A
2639N/A The "basedirs" parameter is the list of directories to look in to find
2639N/A any payload for the action.
2639N/A
2639N/A Raises MalformedActionError if the attribute strings are malformed.
2639N/A """
2639N/A
2639N/A if atype not in types:
2639N/A raise UnknownActionError(("%s %s" % (atype,
2639N/A " ".join(args))).strip(), atype)
2639N/A
2639N/A data = None
2639N/A
2639N/A if atype in ("file", "license"):
2639N/A data = args.pop(0)
2639N/A
2639N/A attrs = {}
2639N/A
2639N/A try:
2639N/A for a, v in [kv.split("=", 1) for kv in args]:
2639N/A if v == '' or a == '':
2639N/A kvi = args.index(kv) + 1
2639N/A p1 = " ".join(args[:kvi])
2639N/A p2 = " ".join(args[kvi:])
2639N/A raise MalformedActionError(
2639N/A "%s %s %s" % (atype, p1, p2), len(p1) + 1,
2639N/A "attribute '%s'" % kv)
2639N/A
2639N/A # This is by far the common case-- an attribute with
2639N/A # a single value.
2639N/A if a not in attrs:
2639N/A attrs[a] = v
2639N/A else:
2639N/A av = attrs[a]
2639N/A if isinstance(av, list):
2639N/A attrs[a].append(v)
1890N/A else:
591N/A attrs[a] = [ av, v ]
1890N/A except ValueError:
591N/A # We're only here if the for: statement above throws a
2639N/A # MalformedActionError. That can happen if split yields a
591N/A # single element, which is possible if e.g. an attribute lacks
629N/A # an =.
1890N/A kvi = args.index(kv) + 1
591N/A p1 = " ".join(args[:kvi])
629N/A p2 = " ".join(args[kvi:])
591N/A raise MalformedActionError("%s %s %s" % (atype, p1, p2),
591N/A len(p1) + 2, "attribute '%s'" % kv)
1659N/A
1659N/A action = types[atype](data=None, **attrs)
1659N/A
591N/A ka = action.key_attr
629N/A if ka is not None and (ka not in action.attrs or
1973N/A action.attrs[ka] is None):
1846N/A raise InvalidActionError(("%s %s" % (atype,
1973N/A " ".join(args))).strip(), _("required attribute, "
2639N/A "'%s', was not provided.") % ka)
591N/A
2639N/A if ahash:
1846N/A action.hash = ahash
591N/A
1846N/A local_path = __set_action_data(data, action, basedirs)
2457N/A return action, local_path
591N/A
591N/Adef internalizestr(string, basedirs=None, load_data=True):
591N/A """Create an action instance based on a sequence of strings.
591N/A This function also translates external representations of actions with
2639N/A payloads (like file and license which can use NOHASH or file paths to
1846N/A point to the payload) to an internal representation which sets the
591N/A data field of the action returned.
1846N/A
1659N/A In general, each string should be in the form of "key=value". The
1973N/A exception is a payload for certain actions which should be the first
2639N/A item in the sequence.
1973N/A
1846N/A Raises MalformedActionError if the attribute strings are malformed.
1973N/A """
1659N/A
1659N/A string = string.strip()
1846N/A args = string.split()
1846N/A atype = args.pop(0)
1846N/A
1846N/A if atype not in types:
1846N/A raise UnknownActionError(("%s %s" % (atype,
1846N/A " ".join(args))).strip(), atype)
629N/A
1973N/A action = fromstr(string)
1846N/A
1973N/A if atype not in ("file", "license") or not load_data:
2639N/A return action, None
1973N/A
1846N/A local_path = __set_action_data(args[0], action, basedirs)
1973N/A return action, local_path
629N/A
591N/Adef __set_action_data(payload, action, basedirs):
591N/A """Sets the data field of an action using the information in the
591N/A payload and returns the actual path used to set the data.
591N/A
629N/A The "payload" parameter is the representation of the data to assign to
1973N/A the action's data field. It can either be NOHASH or a path to the file.
1846N/A
1973N/A The "action" parameter is the action to modify.
2639N/A
591N/A The "basedirs" parameter contains the directories to examine to find
591N/A the payload in."""
591N/A
629N/A if not payload:
1973N/A return None
1846N/A
1973N/A if payload == "NOHASH":
629N/A filepath = os.path.sep + action.attrs["path"]
591N/A else:
591N/A filepath = payload
591N/A
591N/A if basedirs:
591N/A path = filepath.lstrip(os.path.sep)
2233N/A # look for file in specified dirs
2233N/A for d in basedirs:
2233N/A data = os.path.join(d, path)
591N/A if os.path.isfile(data):
591N/A break
2233N/A else:
2639N/A data = filepath
2233N/A
2233N/A action.set_data(data)
2233N/A return data
2233N/A