manifest.py revision 296
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#!/usr/bin/python
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# CDDL HEADER START
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# The contents of this file are subject to the terms of the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# Common Development and Distribution License (the "License").
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# You may not use this file except in compliance with the License.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen# or http://www.opensolaris.org/os/licensing.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# See the License for the specific language governing permissions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# and limitations under the License.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# When distributing Covered Code, include this CDDL HEADER in each
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# If applicable, add the following below this CDDL HEADER, with the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# fields enclosed by brackets "[]" replaced with your own identifying
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# information: Portions Copyright [yyyy] [name of copyright owner]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# CDDL HEADER END
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# Use is subject to license terms.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport bisect
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport os
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport cPickle
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenfrom itertools import groupby, chain
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport pkg.actions as actions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport pkg.client.retrieve as retrieve
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenimport pkg.client.filter as filter
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenfrom pkg.actions.attribute import AttributeAction
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen# The type member is used for the ordering of actions.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_DIR = 10
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_FILE = 20
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_LINK = 50
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_HARDLINK = 55
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_DEVICE = 100
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_USER = 200
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_GROUP = 210
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_SERVICE = 300
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_RESTART = 310
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenACTION_DEPEND = 400
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenDEPEND_REQUIRE = 0
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenDEPEND_OPTIONAL = 1
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo SirainenDEPEND_INCORPORATE =10
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainendepend_str = { DEPEND_REQUIRE : "require",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen DEPEND_OPTIONAL : "optional",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen DEPEND_INCORPORATE : "incorporate"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenclass Manifest(object):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """A Manifest is the representation of the actions composing a specific
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen package version on both the client and the repository. Both purposes
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen utilize the same storage format.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen The serialized structure of a manifest is an unordered list of actions.
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen The special action, "set", represents a package attribute.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen The reserved attribute, "fmri", represents the package and version
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen described by this manifest. It is available as a string via the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen attributes dictionary, and as an FMRI object from the fmri member.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen The list of manifest-wide reserved attributes is
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen base_directory Default base directory, for non-user images.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen fmri Package FMRI.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen isa Package is intended for a list of ISAs.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen platform Package is intended for a list of platforms.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen relocatable Suitable for User Image.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen All non-prefixed attributes are reserved to the framework. Third
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen parties may prefix their attributes with a reversed domain name, domain
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen name, or stock symbol. An example might be
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen com.example,supported
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen as an indicator that a specific package version is supported by the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen vendor, example.com.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen manifest.null is provided as the null manifest. Differences against the
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen null manifest result in the complete set of attributes and actions of
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen the non-null manifest, meaning that all operations can be viewed as
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen tranitions between the manifest being installed and the manifest already
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen present in the image (which may be the null manifest).
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def __init__(self):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.img = None
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.fmri = None
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.actions = []
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def __str__(self):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen r = ""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if self.fmri != None:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen r = r + "set name=fmri value=%s\n" % self.fmri
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for act in sorted(self.actions):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen r = r + "%s\n" % act
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return r
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def difference(self, origin):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Return three lists of action pairs representing origin and
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen destination actions. The first list contains the pairs
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen representing additions, the second list contains the pairs
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen representing updates, and the third list contains the pairs
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen represnting removals. All three lists are in the order in which
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen they should be executed."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # XXX Do we need to find some way to assert that the keys are
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # all unique?
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen sdict = dict(
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ((a.name, a.attrs.get(a.key_attr, id(a))), a)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in self.actions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen )
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen odict = dict(
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ((a.name, a.attrs.get(a.key_attr, id(a))), a)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in origin.actions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen )
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen sset = set(sdict.keys())
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen oset = set(odict.keys())
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen added = [(None, sdict[i]) for i in sset - oset]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen removed = [(odict[i], None) for i in oset - sset]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # XXX for now, we force license actions to always be
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # different to insure that existing license files for
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen # new versions are always installed
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen changed = [
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (odict[i], sdict[i])
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for i in oset & sset
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if odict[i].different(sdict[i]) or i[0] == "license"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # XXX Do changed actions need to be sorted at all? This is
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # likely to be the largest list, so we might save significant
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # time by not sorting. Should we sort above? Insert into a
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # sorted list?
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # singlesort = lambda x: x[0] or x[1]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen addsort = lambda x: x[1]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen remsort = lambda x: x[0]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen removed.sort(key = remsort, reverse = True)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen added.sort(key = addsort)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen changed.sort(key = addsort)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return (added, changed, removed)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def combined_difference(self, origin):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Where difference() returns three lists, combined_difference()
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen returns a single list of the concatenation of th three."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return list(chain(*self.difference(origin)))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def humanized_differences(self, other):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Output expects that self is newer than other. Use of sets
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen requires that we convert the action objects into some marshalled
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen form, otherwise set member identities are derived from the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen object pointers, rather than the contents."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen l = self.difference(other)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen out = ""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for src, dest in chain(*l):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if not src:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen out += "+ %s\n" % str(dest)
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen elif not dest:
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen out += "- %s\n" + str(src)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen out += "%s -> %s\n" % (src, dest)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return out
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen def filter(self, filters):
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen """Filter out actions from the manifest based on filters."""
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.actions = [
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen a
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in self.actions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if filter.apply_filters(a, filters)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def duplicates(self):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Find actions in the manifest which are duplicates (i.e.,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen represent the same object) but which are not identical (i.e.,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen have all the same attributes)."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen def fun(a):
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen """Return a key on which actions can be sorted."""
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen return a.name, a.attrs.get(a.key_attr, id(a))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen alldups = []
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for k, g in groupby(sorted(self.actions, key = fun), fun):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen glist = list(g)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen dups = set()
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for i in range(len(glist) - 1):
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if glist[i].different(glist[i + 1]):
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen dups.add(glist[i])
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen dups.add(glist[i + 1])
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if dups:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen alldups.append((k, dups))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return alldups
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def set_fmri(self, img, fmri):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.img = img
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.fmri = fmri
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen @staticmethod
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def make_opener(img, fmri, action):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def opener():
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return retrieve.get_datastream(img, fmri, action.hash)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return opener
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def set_content(self, str):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """str is the text representation of the manifest"""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # So we could build up here the type/key_attr dictionaries like
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # sdict and odict in difference() above, and have that be our
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # main datastore, rather than the simple list we have now. If
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # we do that here, we can even assert that the "same" action
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # can't be in a manifest twice. (The problem of having the same
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # action more than once in packages that can be installed
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # together has to be solved somewhere else, though.)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for l in str.splitlines():
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen l = l.lstrip()
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if not l or l[0] == "#":
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen continue
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen try:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen action = actions.fromstr(l)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen except KeyError:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen raise SyntaxError, \
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "unknown action '%s'" % l.split()[0]
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if action.attrs.has_key("path"):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen np = action.attrs["path"].lstrip(os.path.sep)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen action.attrs["path"] = np
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if hasattr(action, "hash"):
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen action.data = \
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen self.make_opener(self.img, self.fmri, action)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if not self.actions:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.actions.append(action)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen else:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen bisect.insort(self.actions, action)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen def search_dict(self):
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen """Return the dictionary used for searching."""
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen action_dict = {}
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen for a in self.actions:
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen for k, v in a.generate_indices().iteritems():
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if isinstance(v, list):
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if k in action_dict:
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen action_dict[k].update(
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen dict((i, True) for i in v))
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen else:
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen action_dict[k] = \
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen dict((i, True) for i in v)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen else:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if k in action_dict:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen action_dict[k][v] = True
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen else:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen action_dict[k] = { v: True }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return action_dict
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def pickle(self, file):
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen """Pickle the indices of the manifest's actions to the 'file'.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cPickle.dump(self.search_dict(), file,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen protocol = cPickle.HIGHEST_PROTOCOL)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def get(self, key, default):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen try:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return self[key]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen except KeyError:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return default
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def __getitem__(self, key):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Return the value for the package attribute 'key'. If
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen multiple attributes exist, return the first. Raises KeyError if
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen the attribute is not found."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen try:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen values = [
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen a.attrs["value"]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in self.actions
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if a.name == "set" and a.attrs["name"] == key
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen except KeyError:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # This hides the fact that we had busted attribute
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # actions in the manifest, but that's probably not so
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen # bad.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen raise KeyError, key
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if values:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return values[0]
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen raise KeyError, key
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def __setitem__(self, key, value):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen """Set the value for the package attribute 'key' to 'value'."""
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in self.actions:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if a.name == "set" and a.attrs["name"] == key:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen a.attrs["value"] = value
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen new_attr = AttributeAction(None, name=key, value=value)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen self.actions.append(new_attr)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen def __contains__(self, key):
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for a in self.actions:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if a.name == "set" and a.attrs["name"] == key:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return True
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return False
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainennull = Manifest()
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen