3263N/A#!/usr/bin/python
1506N/A#
1506N/A# CDDL HEADER START
1506N/A#
1506N/A# The contents of this file are subject to the terms of the
1506N/A# Common Development and Distribution License (the "License").
1506N/A# You may not use this file except in compliance with the License.
1506N/A#
1506N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1506N/A# or http://www.opensolaris.org/os/licensing.
1506N/A# See the License for the specific language governing permissions
1506N/A# and limitations under the License.
1506N/A#
1506N/A# When distributing Covered Code, include this CDDL HEADER in each
1506N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1506N/A# If applicable, add the following below this CDDL HEADER, with the
1506N/A# fields enclosed by brackets "[]" replaced with your own identifying
1506N/A# information: Portions Copyright [yyyy] [name of copyright owner]
1506N/A#
1506N/A# CDDL HEADER END
1903N/A
1506N/A#
3324N/A# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
1506N/A#
1506N/A
3263N/A
3143N/Afrom __future__ import print_function
1506N/Aimport os
1506N/Aimport re
1506N/Aimport shlex
3234N/Aimport six
1506N/Aimport sys
1715N/A
1506N/Aimport pkg.actions
1506N/A
1506N/A
3263N/Adef add_transform(transforms, printinfo, transform, filename, lineno):
1506N/A """This routine adds a transform tuple to the list used
1506N/A to process actions."""
1506N/A
1506N/A # strip off transform
1949N/A s = transform[10:]
1506N/A # make error messages familiar
1506N/A transform = "<" + transform + ">"
1506N/A
1506N/A try:
1506N/A index = s.index("->")
1506N/A except ValueError:
3194N/A raise RuntimeError(_("Missing -> in transform"))
1506N/A matching = s[0:index].strip().split()
1506N/A types = [a for a in matching if "=" not in a]
1506N/A attrdict = pkg.actions.attrsfromstr(" ".join([a for a in matching if "=" in a]))
1950N/A
1506N/A for a in attrdict:
1506N/A try:
1506N/A attrdict[a] = re.compile(attrdict[a])
3171N/A except re.error as e:
3194N/A raise RuntimeError(
3158N/A _("transform ({transform}) has regexp error "
3158N/A "({err}) in matching clause"
3194N/A ).format(transform=transform, err=e))
1506N/A
1949N/A op = s[index+2:].strip().split(None, 1)
1506N/A
1506N/A # use closures to encapsulate desired operation
1506N/A
1506N/A if op[0] == "drop":
1506N/A if len(op) > 1:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'drop' operation syntax error"
3194N/A ).format(transform))
1950N/A operation = lambda a, m, p, f, l: None
1506N/A
1949N/A elif op[0] == "set":
1506N/A try:
1506N/A attr, value = shlex.split(op[1])
1506N/A except ValueError:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'set' operation syntax error"
3194N/A ).format(transform))
1950N/A def set_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newattr = substitute_values(attr, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A newval = substitute_values(value, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A if newattr == "action.hash":
1950N/A if hasattr(action, "hash"):
1950N/A action.hash = newval
1950N/A else:
1950N/A action.attrs[newattr] = newval
1506N/A return action
1506N/A operation = set_func
1506N/A
1949N/A elif op[0] == "default":
1506N/A try:
1506N/A attr, value = shlex.split(op[1])
1506N/A except ValueError:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'default' operation syntax error"
3194N/A ).format(transform))
1506N/A
1950N/A def default_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newattr = substitute_values(attr, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A if newattr not in action.attrs:
1949N/A newval = substitute_values(value, action,
1950N/A matches, pkg_attrs, filename, lineno)
1950N/A action.attrs[newattr] = newval
1506N/A return action
1506N/A operation = default_func
1506N/A
1949N/A elif op[0] == "abort":
1949N/A if len(op) > 1:
3194N/A raise RuntimeError(_("transform ({0}) has 'abort' "
3194N/A "operation syntax error").format(transform))
1949N/A
1950N/A def abort_func(action, matches, pkg_attrs, filename, lineno):
1949N/A sys.exit(0)
1949N/A
1949N/A operation = abort_func
1949N/A
1949N/A elif op[0] == "exit":
1949N/A exitval = 0
1949N/A msg = None
1679N/A
1949N/A if len(op) == 2:
1949N/A args = op[1].split(None, 1)
1949N/A try:
1949N/A exitval = int(args[0])
1949N/A except ValueError:
3194N/A raise RuntimeError(_("transform ({0}) has 'exit' "
3158N/A "operation syntax error: illegal exit value").format(
3194N/A transform))
1949N/A if len(args) == 2:
1949N/A msg = args[1]
1949N/A
1950N/A def exit_func(action, matches, pkg_attrs, filename, lineno):
1949N/A if msg:
1949N/A newmsg = substitute_values(msg, action,
1955N/A matches, pkg_attrs, filename, lineno,
1955N/A quote=True)
3143N/A print(newmsg, file=sys.stderr)
1949N/A sys.exit(exitval)
1949N/A
1949N/A operation = exit_func
1949N/A
1949N/A elif op[0] == "add":
1506N/A try:
1506N/A attr, value = shlex.split(op[1])
1506N/A except ValueError:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'add' operation syntax error"
3194N/A ).format(transform))
1506N/A
1950N/A def add_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newattr = substitute_values(attr, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A newval = substitute_values(value, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A if newattr in action.attrs:
1950N/A av = action.attrs[newattr]
1506N/A if isinstance(av, list):
1950N/A action.attrs[newattr].append(newval)
1506N/A else:
1950N/A action.attrs[newattr] = [ av, newval ]
1506N/A else:
1950N/A action.attrs[newattr] = newval
1506N/A return action
1506N/A operation = add_func
1506N/A
1949N/A elif op[0] == "edit":
2790N/A if len(op) < 2:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'edit' operation syntax error"
3194N/A ).format(transform))
2790N/A
1506N/A args = shlex.split(op[1])
1506N/A if len(args) not in [2, 3]:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'edit' operation syntax error"
3194N/A ).format(transform))
1506N/A attr = args[0]
1506N/A
1950N/A # Run args[1] (the regexp) through substitute_values() with a
1950N/A # bunch of bogus values to see whether it triggers certain
1950N/A # exceptions. If it does, then substitution would have
1950N/A # occurred, and we can't compile the regex now, but wait until
1950N/A # we can correctly run substitute_values().
1506N/A try:
1950N/A substitute_values(args[1], None, [], None, None, None)
1506N/A regexp = re.compile(args[1])
1950N/A except (AttributeError, RuntimeError):
1950N/A regexp = args[1]
3171N/A except re.error as e:
3194N/A raise RuntimeError(
3158N/A _("transform ({transform}) has 'edit' operation "
3158N/A "with malformed regexp ({err})").format(
3194N/A transform=transform, err=e))
1950N/A
1506N/A if len(args) == 3:
1506N/A replace = args[2]
1506N/A else:
1506N/A replace = ""
1506N/A
1950N/A def replace_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newattr = substitute_values(attr, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A newrep = substitute_values(replace, action, matches,
1950N/A pkg_attrs, filename, lineno)
1950N/A val = attrval_as_list(action.attrs, newattr)
1950N/A
1506N/A if not val:
1506N/A return action
1950N/A
1950N/A # It's now appropriate to compile the regexp, if there
1950N/A # are substitutions to be made. So do the substitution
1950N/A # and compile the result.
3234N/A if isinstance(regexp, six.string_types):
1950N/A rx = re.compile(substitute_values(regexp,
1950N/A action, matches, pkg_attrs, filename, lineno))
1950N/A else:
1950N/A rx = regexp
1950N/A
1506N/A try:
1950N/A action.attrs[newattr] = [
1950N/A rx.sub(newrep, v)
1950N/A for v in val
1950N/A ]
3171N/A except re.error as e:
3194N/A raise RuntimeError(
3158N/A _("transform ({transform}) has edit "
2826N/A "operation with replacement string regexp "
3158N/A "error {err}").format(
3194N/A transform=transform, err=e))
1506N/A return action
1506N/A
1506N/A operation = replace_func
1506N/A
1949N/A elif op[0] == "delete":
2790N/A if len(op) < 2:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'delete' operation syntax error"
3194N/A ).format(transform))
2790N/A
1506N/A args = shlex.split(op[1])
1506N/A if len(args) != 2:
3194N/A raise RuntimeError(
3158N/A _("transform ({0}) has 'delete' operation syntax error"
3194N/A ).format(transform))
1506N/A attr = args[0]
1506N/A
1506N/A try:
1506N/A regexp = re.compile(args[1])
3171N/A except re.error as e:
3194N/A raise RuntimeError(
3158N/A _("transform ({transform}) has 'delete' operation"
3158N/A "with malformed regexp ({err})").format(
3194N/A transform=transform, err=e))
1506N/A
1950N/A def delete_func(action, matches, pkg_attrs, filename, lineno):
1506N/A val = attrval_as_list(action.attrs, attr)
1506N/A if not val:
1506N/A return action
1506N/A try:
1506N/A new_val = [
1950N/A v
1950N/A for v in val
1950N/A if not regexp.search(v)
1950N/A ]
1506N/A
1506N/A if new_val:
1506N/A action.attrs[attr] = new_val
1506N/A else:
1506N/A del action.attrs[attr]
3171N/A except re.error as e:
3194N/A raise RuntimeError(
3158N/A _("transform ({transform}) has delete "
2826N/A "operation with replacement string regexp "
3158N/A "error {err}").format(
3194N/A transform=transform, err=e))
1506N/A return action
1506N/A
1506N/A operation = delete_func
1506N/A
1949N/A elif op[0] == "print":
1949N/A if len(op) > 2:
3194N/A raise RuntimeError(_("transform ({0}) has 'print' "
3194N/A "operation syntax error").format(transform))
1949N/A
1949N/A if len(op) == 1:
1949N/A msg = ""
1949N/A else:
1949N/A msg = op[1]
1949N/A
1950N/A def print_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newmsg = substitute_values(msg, action, matches,
1955N/A pkg_attrs, filename, lineno, quote=True)
1949N/A
3158N/A printinfo.append("{0}".format(newmsg))
1949N/A return action
1949N/A
1949N/A operation = print_func
1949N/A
1949N/A elif op[0] == "emit":
1949N/A if len(op) > 2:
3194N/A raise RuntimeError(_("transform ({0}) has 'emit' "
3194N/A "operation syntax error").format(transform))
1949N/A
1949N/A if len(op) == 1:
1949N/A msg = ""
1949N/A else:
1949N/A msg = op[1]
1949N/A
1950N/A def emit_func(action, matches, pkg_attrs, filename, lineno):
1950N/A newmsg = substitute_values(msg, action, matches,
1955N/A pkg_attrs, filename, lineno, quote=True)
1949N/A
1949N/A if not newmsg.strip() or newmsg.strip()[0] == "#":
1949N/A return (newmsg, action)
1949N/A try:
1949N/A return (pkg.actions.fromstr(newmsg), action)
1949N/A except (pkg.actions.MalformedActionError,
1949N/A pkg.actions.UnknownActionError,
3171N/A pkg.actions.InvalidActionError) as e:
1949N/A raise RuntimeError(e)
1949N/A
1949N/A operation = emit_func
1949N/A
1949N/A else:
3194N/A raise RuntimeError(_("unknown transform operation '{0}'").format(op[0]))
1679N/A
1506N/A transforms.append((types, attrdict, operation, filename, lineno, transform))
1506N/A
1955N/Adef substitute_values(msg, action, matches, pkg_attrs, filename=None, lineno=None, quote=False):
1949N/A """Substitute tokens in messages which can be expanded to the action's
1949N/A attribute values."""
1949N/A
1949N/A newmsg = ""
1949N/A prevend = 0
1949N/A for i in re.finditer("%\((.+?)\)|%\{(.+?)\}", msg):
1949N/A m = i.string[slice(*i.span())]
1949N/A assert m[1] in "({"
1949N/A if m[1] == "(":
1949N/A group = 1
1949N/A elif m[1] == "{":
1949N/A group = 2
1949N/A d = {}
1949N/A if ";" in i.group(group):
1949N/A attrname, args = i.group(group).split(";", 1)
1949N/A tokstream = shlex.shlex(args)
1949N/A for tok in tokstream:
1949N/A if tok == ";":
1949N/A tok = tokstream.get_token()
1949N/A eq = tokstream.get_token()
1955N/A if eq == "" or eq == ";":
1955N/A val = True
1955N/A else:
1955N/A assert(eq == "=")
1955N/A val = tokstream.get_token()
1955N/A if ('"', '"') == (val[0], val[-1]):
1955N/A val = val[1:-1]
1955N/A elif ("'", "'") == (val[0], val[-1]):
1955N/A val = val[1:-1]
1949N/A d[tok] = val
1949N/A else:
1949N/A attrname = i.group(group)
1949N/A
1955N/A d.setdefault("quote", quote)
1955N/A
1955N/A if d.get("noquote", None):
1955N/A d["quote"] = False
1955N/A
1949N/A if group == 2:
1949N/A attr = pkg_attrs.get(attrname, d.get("notfound", None))
1949N/A if attr and len(attr) == 1:
1949N/A attr = attr[0]
1949N/A else:
1949N/A if attrname == "pkg.manifest.lineno":
1949N/A attr = str(lineno)
1949N/A elif attrname == "pkg.manifest.filename":
1949N/A attr = str(filename)
1949N/A elif attrname == "action.hash":
1949N/A attr = getattr(action, "hash",
1949N/A d.get("notfound", None))
1949N/A elif attrname == "action.key":
1949N/A attr = action.attrs.get(action.key_attr,
1949N/A d.get("notfound", None))
1949N/A elif attrname == "action.name":
1949N/A attr = action.name
1949N/A else:
1949N/A attr = action.attrs.get(attrname,
1949N/A d.get("notfound", None))
1949N/A
1949N/A if attr is None:
3194N/A raise RuntimeError(_("attribute '{0}' not found").format(
3194N/A attrname))
1949N/A
1949N/A def q(s):
1949N/A if " " in s or "'" in s or "\"" in s or s == "":
1949N/A if "\"" not in s:
3158N/A return '"{0}"'.format(s)
1949N/A elif "'" not in s:
3158N/A return "'{0}'".format(s)
1949N/A else:
3158N/A return '"{0}"'.format(s.replace("\"", "\\\""))
1949N/A else:
1949N/A return s
1949N/A
1955N/A if not d["quote"]:
1955N/A q = lambda x: x
1955N/A
3234N/A if isinstance(attr, six.string_types):
1949N/A newmsg += msg[prevend:i.start()] + \
1949N/A d.get("prefix", "") + q(attr) + d.get("suffix", "")
1949N/A else:
1949N/A newmsg += msg[prevend:i.start()] + \
1949N/A d.get("sep", " ").join([
1949N/A d.get("prefix", "") + q(v) + d.get("suffix", "")
1949N/A for v in attr
1949N/A ])
1949N/A prevend = i.end()
1950N/A
1950N/A newmsg += msg[prevend:]
1950N/A
1950N/A # Now see if there are any backreferences to match groups
1950N/A msg = newmsg
1950N/A newmsg = ""
1950N/A prevend = 0
1950N/A backrefs = sum((
1950N/A group
1950N/A for group in (
1950N/A match.groups()
1950N/A for match in matches
1950N/A if match.groups()
1950N/A )
1950N/A ), (None,))
1950N/A for i in re.finditer(r"%<\d>", msg):
1950N/A ref = int(i.string[slice(*i.span())][2:-1])
1950N/A
1950N/A if ref == 0 or ref > len(backrefs) - 1:
3194N/A raise RuntimeError(_("no match group {group:d} "
3158N/A "(max {maxgroups:d})").format(
3194N/A group=ref, maxgroups=len(backrefs) - 1))
3250N/A if backrefs[ref] is None:
3250N/A raise RuntimeError(_("Error\nInvalid backreference: "
3250N/A "%<{ref}> refers to an unmatched string"
3241N/A ).format(ref=ref))
1950N/A newmsg += msg[prevend:i.start()] + backrefs[ref]
1950N/A prevend = i.end()
1950N/A
1949N/A newmsg += msg[prevend:]
1949N/A return newmsg
1949N/A
1506N/Adef attrval_as_list(attrdict, key):
1506N/A """Return specified attribute as list;
1506N/A an empty list if no such attribute exists"""
1506N/A if key not in attrdict:
1506N/A return []
1506N/A val = attrdict[key]
1506N/A if not isinstance(val, list):
1506N/A val = [val]
1506N/A return val
1506N/A
1949N/Aclass PkgAction(pkg.actions.generic.Action):
1949N/A name = "pkg"
1949N/A def __init__(self, attrs):
1949N/A self.attrs = attrs
1949N/A
3263N/Adef apply_transforms(transforms, action, pkg_attrs, verbose, act_filename,
3263N/A act_lineno):
1506N/A """Apply all transforms to action, returning modified action
1506N/A or None if action is dropped"""
1506N/A comments = []
1949N/A newactions = []
1506N/A if verbose:
3158N/A comments.append("# Action: {0}".format(action))
1506N/A for types, attrdict, operation, filename, lineno, transform in transforms:
1949N/A if action is None:
1949N/A action = PkgAction(pkg_attrs)
1506N/A # skip if types are specified and none match
1506N/A if types and action.name not in types:
1506N/A continue
1506N/A # skip if some attrs don't exist
1506N/A if set(attrdict.keys()) - set(action.attrs.keys()):
1506N/A continue
1506N/A
1950N/A # Check to make sure all matching attrs actually match. The
1950N/A # order is effectively arbitrary, since they come from a dict.
1950N/A matches = [
1950N/A attrdict[key].match(attrval)
1949N/A for key in attrdict
1949N/A for attrval in attrval_as_list(action.attrs, key)
1950N/A ]
1950N/A
1950N/A if not all(matches):
1506N/A continue
1950N/A
1950N/A s = transform[11:transform.index("->")]
1950N/A # Map each pattern to its position in the original match string.
1950N/A matchorder = {}
3234N/A for attr, match in six.iteritems(attrdict):
1950N/A # Attributes might be quoted even if they don't need it,
1950N/A # and lead to a mis-match. These three patterns are all
1950N/A # safe to try. If we fail to find the match expression,
1950N/A # it's probably because it used different quoting rules
1950N/A # than the action code does, or from these three rules.
1950N/A # It might very well be okay, so we go ahead, but these
1950N/A # oddly quoted patterns will sort at the beginning, and
1950N/A # backref matching may be off.
1950N/A matchorder[match.pattern] = -1
3158N/A for qs in ("{0}={1}", "{0}=\"{1}\"", "{0}='{1}'"):
3158N/A pos = s.find(qs.format(attr, match.pattern))
1950N/A if pos != -1:
1950N/A matchorder[match.pattern] = pos
1950N/A break
1950N/A
1950N/A # Then sort the matches list by those positions.
1950N/A matches.sort(key=lambda x: matchorder[x.re.pattern])
1950N/A
1506N/A # time to apply transform operation
1506N/A try:
1506N/A if verbose:
1506N/A orig_attrs = action.attrs.copy()
1950N/A action = operation(action, matches, pkg_attrs,
1950N/A act_filename, act_lineno)
3171N/A except RuntimeError as e:
3194N/A raise RuntimeError("Transform specified in file {0}, line {1} reports {2}".format(
3194N/A filename, lineno, e))
1949N/A if isinstance(action, tuple):
1949N/A newactions.append(action[0])
1949N/A action = action[1]
1506N/A if verbose:
1949N/A if not action or \
3234N/A not isinstance(action, six.string_types) and \
1949N/A orig_attrs != action.attrs:
3158N/A comments.append("# Applied: {0} (file {1} line {2})".format(
1949N/A transform, filename, lineno))
3158N/A comments.append("# Result: {0}".format(action))
3234N/A if not action or isinstance(action, six.string_types):
1506N/A break
1506N/A
1949N/A # Any newly-created actions need to have the transforms applied, too.
1949N/A newnewactions = []
1949N/A for act in newactions:
3234N/A if not isinstance(act, six.string_types):
3263N/A c, al = apply_transforms(transforms, act, pkg_attrs,
3263N/A verbose, act_filename, act_lineno)
2257N/A if c:
2257N/A comments.append(c)
1949N/A newnewactions += [a for a in al if a is not None]
1949N/A else:
1949N/A newnewactions.append(act)
1949N/A
1506N/A if len(comments) == 1:
1506N/A comments = []
1949N/A
1949N/A if action and action.name != "pkg":
1949N/A return (comments, [action] + newnewactions)
1949N/A else:
1949N/A return (comments, [None] + newnewactions)
1949N/A
1949N/A
3263N/Adef searching_open(filename, includes, try_cwd=False):
1506N/A """ implement include hierarchy """
1506N/A
3324N/A if filename == "-":
3324N/A return filename, sys.stdin
3324N/A
1506N/A if filename.startswith("/") or try_cwd == True and \
1506N/A os.path.exists(filename):
1506N/A try:
3234N/A return filename, open(filename)
3171N/A except IOError as e:
3194N/A raise RuntimeError(_("Cannot open file: {0}").format(e))
1506N/A
1506N/A for i in includes:
1506N/A f = os.path.join(i, filename)
1506N/A if os.path.exists(f):
1506N/A try:
3234N/A return f, open(f)
3171N/A except IOError as e:
3194N/A raise RuntimeError(_("Cannot open file: {0}").format(e))
1506N/A
3194N/A raise RuntimeError(_("File not found: \'{0}\'").format(filename))
1506N/A
3263N/Adef apply_macros(s, macros):
1506N/A """Apply macro subs defined on command line... keep applying
1506N/A macros until no translations are found."""
1506N/A while s and "$(" in s:
1506N/A for key in macros.keys():
1506N/A if key in s:
1506N/A value = macros[key]
1506N/A s = s.replace(key, value)
1506N/A break # look for more substitutions
1506N/A else:
1506N/A break # no more substitutable tokens
1506N/A return s
1506N/A
3263N/Adef read_file(tp, ignoreincludes, transforms, macros, printinfo, includes,
3263N/A error_print_cb=None):
3263N/A """ return the lines in the file as a list of tuples containing
3263N/A (line, filename, line number); handle continuation and <include "path">
3263N/A """
1506N/A ret = []
1506N/A filename, f = tp
1506N/A
1506N/A accumulate = ""
1506N/A for lineno, line in enumerate(f):
1506N/A lineno = lineno + 1 # number from 1
1506N/A line = line.strip()
1903N/A if not line: # preserve blanks
1903N/A ret.append((line, filename, lineno))
1903N/A continue
1506N/A if line.endswith("\\"):
1506N/A accumulate += line[0:-1]
1506N/A continue
1506N/A elif accumulate:
1506N/A line = accumulate + line
1506N/A accumulate = ""
1949N/A
1506N/A if line:
3263N/A line = apply_macros(line, macros)
1506N/A
1506N/A line = line.strip()
1506N/A
1903N/A if not line:
1506N/A continue
1506N/A
1506N/A try:
1506N/A if line.startswith("<") and line.endswith(">"):
1903N/A if line.startswith("<include"):
1903N/A if not ignoreincludes:
1903N/A line = line[1:-1]
1903N/A line = line[7:].strip()
1903N/A line = line.strip('"')
1949N/A ret.extend(read_file(
3263N/A searching_open(line, includes,
3263N/A try_cwd=True),
3263N/A ignoreincludes,
3263N/A transforms, macros,
3263N/A printinfo, includes,
3263N/A error_print_cb))
1903N/A else:
1949N/A ret.append((line, filename, lineno))
1903N/A elif line.startswith("<transform"):
1903N/A line = line[1:-1]
3263N/A add_transform(transforms, printinfo,
3263N/A line, filename, lineno)
1506N/A else:
3263N/A raise RuntimeError(
3263N/A _("unknown command {0}").format(
3263N/A line))
1506N/A else:
1949N/A ret.append((line, filename, lineno))
3171N/A except RuntimeError as e:
3263N/A if error_print_cb:
3263N/A error_print_cb(_("File {file}, line {line:d}: "
3263N/A "{exception}").format(file=filename,
3263N/A line=lineno,
3263N/A exception=e),
3263N/A exitcode=None)
3194N/A raise RuntimeError("<included from>")
3339N/A f.close()
1949N/A
1506N/A return ret
1506N/A
3263N/Adef process_error(msg, error_cb=None):
3263N/A """Print the error message or raise the actual exception if no
3263N/A error printing callback specified."""
3263N/A
3263N/A if error_cb:
3263N/A error_cb(msg)
3263N/A else:
3263N/A raise
1506N/A
3263N/Adef process_mog(file_args, ignoreincludes, verbose, includes, macros,
3263N/A printinfo, output, error_cb=None, sys_supply_files=[]):
3263N/A """Entry point for mogrify logic.
3263N/A file_args: input files to be mogrified. If not provided, use stdin
3263N/A instead.
3263N/A
3263N/A ingoreincludes: whether to ignore <include ...> directives in input
3263N/A files.
3263N/A
3263N/A verbose: whether to include verbose action processing information
3263N/A in mogrify output. Useful for debug.
3263N/A
3263N/A includes: a list of directory paths used for searching include files.
3263N/A
3263N/A macros: a list of macros for substitution.
1506N/A
3263N/A printinfo: used to collect a list print info along processing. Could be
3263N/A empty initially.
3263N/A
3263N/A output: used to collect mogrify output. Empty initially.
3263N/A
3263N/A error_cb: used to supply a error printing callback.
3263N/A
3263N/A sys_supply_files: used for other systems or modules to supply
3263N/A additional input files.
3263N/A """
1506N/A
3263N/A transforms = []
3263N/A try:
3263N/A if file_args:
3263N/A infiles = [ searching_open(f, includes,
3263N/A try_cwd=True) for f in file_args ]
3263N/A else:
3263N/A infiles = [("<stdin>", sys.stdin)]
3263N/A if sys_supply_files:
3263N/A infiles.extend([searching_open(f, includes,
3263N/A try_cwd=True) for f in sys_supply_files])
3263N/A except RuntimeError as e:
3263N/A process_error(_("Error processing input arguments: {0}"
3263N/A ).format(e), error_cb)
1506N/A
1506N/A try:
1506N/A lines = []
1506N/A for f in infiles:
3263N/A lines.extend(read_file(f, ignoreincludes,
3263N/A transforms, macros, printinfo, includes, error_cb))
1955N/A lines.append((None, f[0], None))
3171N/A except RuntimeError as e:
3263N/A raise
1506N/A
1949N/A pkg_attrs = {}
1506N/A for line, filename, lineno in lines:
1949N/A if line is None:
1949N/A if "pkg.fmri" in pkg_attrs:
3263N/A comment, a = apply_transforms(transforms,
3263N/A None, pkg_attrs,
1949N/A verbose, filename, lineno)
1949N/A output.append((comment, a, None))
1949N/A pkg_attrs = {}
1949N/A continue
1949N/A
1903N/A if not line or line.startswith("#") or line.startswith("<"):
1949N/A output.append(([line], [], None))
1903N/A continue
1903N/A
1903N/A if line.startswith("$("): #prepended unexpanded macro
1903N/A # doesn't handle nested macros
1903N/A eom = line.index(")") + 1
1903N/A prepended_macro = line[0:eom]
1903N/A line = line[eom:]
1903N/A else:
1903N/A prepended_macro = None
1949N/A
1506N/A try:
1506N/A act = pkg.actions.fromstr(line)
1506N/A except (pkg.actions.MalformedActionError,
1506N/A pkg.actions.UnknownActionError,
3171N/A pkg.actions.InvalidActionError) as e:
3263N/A process_error("File {0} line {1:d}: {2}".format(
3263N/A filename, lineno, e), error_cb)
1506N/A try:
1949N/A if act.name == "set":
1949N/A name = act.attrs["name"]
1949N/A value = act.attrs["value"]
3234N/A if isinstance(value, six.string_types):
1949N/A pkg_attrs.setdefault(name, []).append(value)
1949N/A else:
1949N/A pkg_attrs.setdefault(name, []).extend(value)
3263N/A comment, a = apply_transforms(transforms, act,
3263N/A pkg_attrs, verbose, filename, lineno)
1903N/A output.append((comment, a, prepended_macro))
3171N/A except RuntimeError as e:
3263N/A process_error("File {0} line {1:d}: {2}".format(
3263N/A filename, lineno, e), error_cb)