pver supporte la gestion des versions maven
This commit is contained in:
parent
190519d968
commit
2980d15769
|
@ -1,10 +1,149 @@
|
|||
import exceptions
|
||||
from xpath.exceptions import *
|
||||
import xpath.exceptions
|
||||
import xpath.expr
|
||||
import xpath.parser
|
||||
import xpath.yappsrt
|
||||
|
||||
from _xpath import api, XPathContext, XPath
|
||||
from exceptions import *
|
||||
__all__ = ['find', 'findnode', 'findvalue', 'XPathContext', 'XPath']
|
||||
__all__.extend((x for x in dir(xpath.exceptions) if not x.startswith('_')))
|
||||
|
||||
__all__ = ['find', 'findnode', 'findvalue', 'findvalues', 'XPathContext', 'XPath']
|
||||
__all__.extend((x for x in dir(exceptions) if not x.startswith('_')))
|
||||
def api(f):
|
||||
"""Decorator for functions and methods that are part of the external
|
||||
module API and that can throw XPathError exceptions.
|
||||
|
||||
The call stack for these exceptions can be very large, and not very
|
||||
interesting to the user. This decorator rethrows XPathErrors to
|
||||
trim the stack.
|
||||
|
||||
"""
|
||||
def api_function(*args, **kwargs):
|
||||
try:
|
||||
return f(*args, **kwargs)
|
||||
except XPathError, e:
|
||||
raise e
|
||||
api_function.__name__ = f.__name__
|
||||
api_function.__doc__ = f.__doc__
|
||||
return api_function
|
||||
|
||||
class XPathContext(object):
|
||||
def __init__(self, document=None, **kwargs):
|
||||
self.default_namespace = None
|
||||
self.namespaces = {}
|
||||
self.variables = {}
|
||||
|
||||
if document is not None:
|
||||
if document.nodeType != document.DOCUMENT_NODE:
|
||||
document = document.ownerDocument
|
||||
if document.documentElement is not None:
|
||||
attrs = document.documentElement.attributes
|
||||
for attr in (attrs.item(i) for i in xrange(attrs.length)):
|
||||
if attr.name == 'xmlns':
|
||||
self.default_namespace = attr.value
|
||||
elif attr.name.startswith('xmlns:'):
|
||||
self.namespaces[attr.name[6:]] = attr.value
|
||||
|
||||
self.update(**kwargs)
|
||||
|
||||
def clone(self):
|
||||
dup = XPathContext()
|
||||
dup.default_namespace = self.default_namespace
|
||||
dup.namespaces.update(self.namespaces)
|
||||
dup.variables.update(self.variables)
|
||||
return dup
|
||||
|
||||
def update(self, default_namespace=None, namespaces=None,
|
||||
variables=None, **kwargs):
|
||||
if default_namespace is not None:
|
||||
self.default_namespace = default_namespace
|
||||
if namespaces is not None:
|
||||
self.namespaces = namespaces
|
||||
if variables is not None:
|
||||
self.variables = variables
|
||||
self.variables.update(kwargs)
|
||||
|
||||
@api
|
||||
def find(self, expr, node, **kwargs):
|
||||
return xpath.find(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findnode(self, expr, node, **kwargs):
|
||||
return xpath.findnode(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalue(self, expr, node, **kwargs):
|
||||
return xpath.findvalue(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalues(self, expr, node, **kwargs):
|
||||
return xpath.findvalues(expr, node, context=self, **kwargs)
|
||||
|
||||
class XPath():
|
||||
_max_cache = 100
|
||||
_cache = {}
|
||||
|
||||
def __init__(self, expr):
|
||||
"""Init docs.
|
||||
"""
|
||||
try:
|
||||
parser = xpath.parser.XPath(xpath.parser.XPathScanner(str(expr)))
|
||||
self.expr = parser.XPath()
|
||||
except xpath.yappsrt.SyntaxError, e:
|
||||
raise XPathParseError(str(expr), e.pos, e.msg)
|
||||
|
||||
@classmethod
|
||||
def get(cls, s):
|
||||
if isinstance(s, cls):
|
||||
return s
|
||||
try:
|
||||
return cls._cache[s]
|
||||
except KeyError:
|
||||
if len(cls._cache) > cls._max_cache:
|
||||
cls._cache.clear()
|
||||
expr = cls(s)
|
||||
cls._cache[s] = expr
|
||||
return expr
|
||||
|
||||
@api
|
||||
def find(self, node, context=None, **kwargs):
|
||||
if context is None:
|
||||
context = XPathContext(node, **kwargs)
|
||||
elif kwargs:
|
||||
context = context.clone()
|
||||
context.update(**kwargs)
|
||||
return self.expr.evaluate(node, 1, 1, context)
|
||||
|
||||
@api
|
||||
def findnode(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if not xpath.expr.nodesetp(result):
|
||||
raise XPathTypeError("expression is not a node-set")
|
||||
if len(result) == 0:
|
||||
return None
|
||||
return result[0]
|
||||
|
||||
@api
|
||||
def findvalue(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if xpath.expr.nodesetp(result):
|
||||
if len(result) == 0:
|
||||
return None
|
||||
result = xpath.expr.string(result)
|
||||
return result
|
||||
|
||||
@api
|
||||
def findvalues(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if not xpath.expr.nodesetp(result):
|
||||
raise XPathTypeError("expression is not a node-set")
|
||||
return [xpath.expr.string_value(x) for x in result]
|
||||
|
||||
def __repr__(self):
|
||||
return '%s.%s(%s)' % (self.__class__.__module__,
|
||||
self.__class__.__name__,
|
||||
repr(str(self.expr)))
|
||||
|
||||
def __str__(self):
|
||||
return str(self.expr)
|
||||
|
||||
@api
|
||||
def find(expr, node, **kwargs):
|
||||
|
|
|
@ -15,7 +15,7 @@ class XPathParseError(XPathError):
|
|||
XPathError.__init__(self)
|
||||
self.expr = expr
|
||||
self.pos = pos
|
||||
self.message = message
|
||||
self.err = message
|
||||
|
||||
def __str__(self):
|
||||
return ("Syntax error:\n" +
|
||||
|
|
|
@ -6,7 +6,8 @@ import re
|
|||
import xml.dom
|
||||
import weakref
|
||||
|
||||
from exceptions import *
|
||||
from xpath.exceptions import *
|
||||
import xpath
|
||||
|
||||
|
||||
#
|
||||
|
@ -21,6 +22,8 @@ def string_value(node):
|
|||
for n in axes['descendant'](node):
|
||||
if n.nodeType == n.TEXT_NODE:
|
||||
s += n.data
|
||||
elif n.nodeType == n.CDATA_SECTION_NODE:
|
||||
s += n.nodeValue
|
||||
return s
|
||||
|
||||
elif node.nodeType == node.ATTRIBUTE_NODE:
|
||||
|
@ -31,6 +34,9 @@ def string_value(node):
|
|||
node.nodeType == node.TEXT_NODE):
|
||||
return node.data
|
||||
|
||||
elif node.nodeType == node.CDATA_SECTION_NODE:
|
||||
return node.nodeValue
|
||||
|
||||
def document_order(node):
|
||||
"""Compute a document order value for the node.
|
||||
|
||||
|
@ -100,10 +106,10 @@ def string(v):
|
|||
return u'Infinity'
|
||||
elif v == float('-inf'):
|
||||
return u'-Infinity'
|
||||
elif int(v) == v and v <= 0xffffffff:
|
||||
v = int(v)
|
||||
elif str(v) == 'nan':
|
||||
return u'NaN'
|
||||
elif int(v) == v and v <= 0xffffffff:
|
||||
v = int(v)
|
||||
return unicode(v)
|
||||
elif booleanp(v):
|
||||
return u'true' if v else u'false'
|
||||
|
@ -883,7 +889,8 @@ class CommentTest(object):
|
|||
|
||||
class TextTest(object):
|
||||
def match(self, node, axis, context):
|
||||
return node.nodeType == node.TEXT_NODE
|
||||
return (node.nodeType == node.TEXT_NODE or
|
||||
node.nodeType == node.CDATA_SECTION_NODE)
|
||||
|
||||
def __str__(self):
|
||||
return 'text()'
|
||||
|
|
|
@ -1,252 +0,0 @@
|
|||
import expr as X
|
||||
from yappsrt import *
|
||||
|
||||
%%
|
||||
|
||||
parser XPath:
|
||||
option: 'no-support-module'
|
||||
|
||||
ignore: r'\s+'
|
||||
token END: r'$'
|
||||
|
||||
token FORWARD_AXIS_NAME:
|
||||
r'child|descendant-or-self|attribute|self|descendant|following-sibling|following|namespace'
|
||||
token REVERSE_AXIS_NAME:
|
||||
r'parent|preceding-sibling|preceding|ancestor-or-self|ancestor'
|
||||
|
||||
# Dire hack here, since yapps2 has only one token of lookahead: NCNAME
|
||||
# does not match when followed by a open paren.
|
||||
token NCNAME: r'[a-zA-Z_][a-zA-Z0-9_\-\.\w]*(?!\()'
|
||||
token FUNCNAME: r'[a-zA-Z_][a-zA-Z0-9_\-\.\w]*'
|
||||
|
||||
token DQUOTE: r'\"(?:[^\"])*\"'
|
||||
token SQUOTE: r"\'(?:[^\'])*\'"
|
||||
token NUMBER: r'((\.[0-9]+)|([0-9]+(\.[0-9]*)?))([eE][\+\-]?[0-9]+)?'
|
||||
token EQ_COMP: r'\!?\='
|
||||
token REL_COMP: r'[\<\>]\=?'
|
||||
token ADD_COMP: r'[\+\-]'
|
||||
token MUL_COMP: r'\*|div|mod'
|
||||
|
||||
rule XPath:
|
||||
Expr END {{ return Expr }}
|
||||
|
||||
rule Expr:
|
||||
OrExpr {{ return OrExpr }}
|
||||
|
||||
rule OrExpr:
|
||||
AndExpr {{ Expr = AndExpr }}
|
||||
(
|
||||
r'or' AndExpr
|
||||
{{ Expr = X.OrExpr('or', Expr, AndExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule AndExpr:
|
||||
EqualityExpr {{ Expr = EqualityExpr }}
|
||||
(
|
||||
r'and' EqualityExpr
|
||||
{{ Expr = X.AndExpr('and', Expr, EqualityExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule EqualityExpr:
|
||||
RelationalExpr {{ Expr = RelationalExpr }}
|
||||
(
|
||||
EQ_COMP
|
||||
RelationalExpr
|
||||
{{ Expr = X.EqualityExpr(EQ_COMP, Expr, RelationalExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule RelationalExpr:
|
||||
AdditiveExpr {{ Expr = AdditiveExpr }}
|
||||
(
|
||||
REL_COMP
|
||||
AdditiveExpr
|
||||
{{ Expr = X.EqualityExpr(REL_COMP, Expr, AdditiveExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule AdditiveExpr:
|
||||
MultiplicativeExpr {{ Expr = MultiplicativeExpr }}
|
||||
(
|
||||
ADD_COMP
|
||||
MultiplicativeExpr
|
||||
{{ Expr = X.ArithmeticalExpr(ADD_COMP, Expr, MultiplicativeExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule MultiplicativeExpr:
|
||||
UnionExpr {{ Expr = UnionExpr }}
|
||||
(
|
||||
MUL_COMP
|
||||
UnionExpr
|
||||
{{ Expr = X.ArithmeticalExpr(MUL_COMP, Expr, UnionExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule UnionExpr:
|
||||
UnaryExpr {{ Expr = UnaryExpr }}
|
||||
(
|
||||
'\|' UnaryExpr
|
||||
{{ Expr = X.UnionExpr('|', Expr, UnaryExpr) }}
|
||||
)* {{ return Expr }}
|
||||
|
||||
rule UnaryExpr:
|
||||
r'\-' ValueExpr {{ return X.NegationExpr(ValueExpr) }}
|
||||
| ValueExpr {{ return ValueExpr }}
|
||||
|
||||
rule ValueExpr:
|
||||
PathExpr {{ return PathExpr }}
|
||||
|
||||
rule PathExpr:
|
||||
r'\/' {{ path = None }}
|
||||
[
|
||||
RelativePathExpr {{ path = RelativePathExpr }}
|
||||
] {{ return X.AbsolutePathExpr(path) }}
|
||||
| r'\/\/' RelativePathExpr
|
||||
{{ step = X.AxisStep('descendant-or-self') }}
|
||||
{{ RelativePathExpr.steps.insert(0, step) }}
|
||||
{{ return X.AbsolutePathExpr(RelativePathExpr) }}
|
||||
| RelativePathExpr {{ return RelativePathExpr }}
|
||||
|
||||
rule RelativePathExpr:
|
||||
StepExpr {{ steps = [StepExpr] }}
|
||||
(
|
||||
(
|
||||
r'\/'
|
||||
| r'\/\/'
|
||||
{{ steps.append(X.AxisStep('descendant-or-self')) }}
|
||||
)
|
||||
StepExpr {{ steps.append(StepExpr) }}
|
||||
)*
|
||||
{{ return X.PathExpr(steps) }}
|
||||
|
||||
rule StepExpr:
|
||||
AxisStep {{ return AxisStep }}
|
||||
| FilterExpr {{ return FilterExpr }}
|
||||
|
||||
rule AxisStep:
|
||||
(
|
||||
ForwardStep {{ step = ForwardStep }}
|
||||
| ReverseStep {{ step = ReverseStep }}
|
||||
) {{ expr = X.AxisStep(*step) }}
|
||||
[
|
||||
PredicateList
|
||||
{{ expr = X.PredicateList(expr, PredicateList, step[0]) }}
|
||||
]
|
||||
{{ return expr }}
|
||||
|
||||
rule ForwardStep:
|
||||
ForwardAxis NodeTest {{ return [ForwardAxis, NodeTest] }}
|
||||
| AbbrevForwardStep {{ return AbbrevForwardStep }}
|
||||
|
||||
rule ForwardAxis:
|
||||
FORWARD_AXIS_NAME r'::' {{ return FORWARD_AXIS_NAME }}
|
||||
|
||||
rule AbbrevForwardStep:
|
||||
{{ axis = 'child' }}
|
||||
[
|
||||
r'@' {{ axis = 'attribute' }}
|
||||
]
|
||||
NodeTest {{ return [axis, NodeTest] }}
|
||||
|
||||
rule ReverseStep:
|
||||
ReverseAxis NodeTest {{ return [ReverseAxis, NodeTest] }}
|
||||
| AbbrevReverseStep {{ return AbbrevReverseStep }}
|
||||
|
||||
rule ReverseAxis:
|
||||
REVERSE_AXIS_NAME r'::' {{ return REVERSE_AXIS_NAME }}
|
||||
|
||||
rule AbbrevReverseStep:
|
||||
r'\.\.' {{ return ['parent', None] }}
|
||||
|
||||
rule NodeTest:
|
||||
KindTest {{ return KindTest }}
|
||||
| NameTest {{ return NameTest }}
|
||||
|
||||
rule NameTest:
|
||||
# We also support the XPath 2.0 <name>:*.
|
||||
{{ prefix = None }}
|
||||
WildcardOrNCName {{ localpart = WildcardOrNCName }}
|
||||
[
|
||||
r':' WildcardOrNCName {{ prefix = localpart }}
|
||||
{{ localpart = WildcardOrNCName }}
|
||||
]
|
||||
{{ return X.NameTest(prefix, localpart) }}
|
||||
|
||||
rule WildcardOrNCName:
|
||||
r'\*' {{ return '*' }}
|
||||
| NCNAME {{ return NCNAME }}
|
||||
|
||||
rule FilterExpr:
|
||||
PrimaryExpr
|
||||
[
|
||||
PredicateList
|
||||
{{ PrimaryExpr = X.PredicateList(PrimaryExpr,PredicateList) }}
|
||||
] {{ return PrimaryExpr }}
|
||||
|
||||
rule PredicateList:
|
||||
Predicate {{ predicates = [Predicate] }}
|
||||
(
|
||||
Predicate {{ predicates.append(Predicate) }}
|
||||
)* {{ return predicates }}
|
||||
|
||||
rule Predicate:
|
||||
r'\[' Expr r'\]' {{ return Expr }}
|
||||
|
||||
rule PrimaryExpr:
|
||||
Literal {{ return X.LiteralExpr(Literal) }}
|
||||
| VariableReference {{ return VariableReference }}
|
||||
| r'\(' Expr r'\)' {{ return Expr }}
|
||||
| ContextItemExpr {{ return ContextItemExpr }}
|
||||
| FunctionCall {{ return FunctionCall }}
|
||||
|
||||
rule VariableReference:
|
||||
r'\$' QName
|
||||
{{ return X.VariableReference(*QName) }}
|
||||
|
||||
rule ContextItemExpr:
|
||||
r'\.' {{ return X.AxisStep('self') }}
|
||||
|
||||
rule FunctionCall:
|
||||
FUNCNAME r'\(' {{ args = [] }}
|
||||
[
|
||||
Expr {{ args.append(Expr) }}
|
||||
(
|
||||
r'\,' Expr {{ args.append(Expr) }}
|
||||
)*
|
||||
] r'\)' {{ return X.Function(FUNCNAME, args) }}
|
||||
|
||||
rule KindTest:
|
||||
PITest {{ return PITest }}
|
||||
| CommentTest {{ return CommentTest }}
|
||||
| TextTest {{ return TextTest }}
|
||||
| AnyKindTest {{ return AnyKindTest }}
|
||||
|
||||
rule PITest:
|
||||
r'processing-instruction' {{ name = None }}
|
||||
r'\(' [
|
||||
NCNAME {{ name = NCNAME }}
|
||||
| StringLiteral {{ name = StringLiteral }}
|
||||
] r'\)' {{ return X.PITest(name) }}
|
||||
|
||||
rule CommentTest:
|
||||
r'comment' r'\(' r'\)' {{ return X.CommentTest() }}
|
||||
|
||||
rule TextTest:
|
||||
r'text' r'\(' r'\)' {{ return X.TextTest() }}
|
||||
|
||||
rule AnyKindTest:
|
||||
r'node' r'\(' r'\)' {{ return X.AnyKindTest() }}
|
||||
|
||||
rule Literal:
|
||||
NumericLiteral {{ return NumericLiteral }}
|
||||
| StringLiteral {{ return StringLiteral }}
|
||||
|
||||
rule NumericLiteral:
|
||||
NUMBER {{ return float(NUMBER) }}
|
||||
|
||||
rule StringLiteral:
|
||||
DQUOTE {{ return DQUOTE[1:-1] }}
|
||||
| SQUOTE {{ return SQUOTE[1:-1] }}
|
||||
|
||||
rule QName:
|
||||
NCNAME {{ name = NCNAME }}
|
||||
[
|
||||
r'\:' NCNAME {{ return (name, NCNAME) }}
|
||||
] {{ return (None, name) }}
|
|
@ -1,5 +1,5 @@
|
|||
import expr as X
|
||||
from yappsrt import *
|
||||
import xpath.expr as X
|
||||
from xpath.yappsrt import *
|
||||
|
||||
|
||||
from string import *
|
||||
|
@ -8,10 +8,10 @@ import re
|
|||
class XPathScanner(Scanner):
|
||||
patterns = [
|
||||
("r'\\:'", re.compile('\\:')),
|
||||
("r'node'", re.compile('node')),
|
||||
("r'text'", re.compile('text')),
|
||||
("r'comment'", re.compile('comment')),
|
||||
("r'processing-instruction'", re.compile('processing-instruction')),
|
||||
("r'node\\s*\\('", re.compile('node\\s*\\(')),
|
||||
("r'text\\s*\\('", re.compile('text\\s*\\(')),
|
||||
("r'comment\\s*\\('", re.compile('comment\\s*\\(')),
|
||||
("r'processing-instruction\\s*\\('", re.compile('processing-instruction\\s*\\(')),
|
||||
("r'\\,'", re.compile('\\,')),
|
||||
("r'\\.'", re.compile('\\.')),
|
||||
("r'\\$'", re.compile('\\$')),
|
||||
|
@ -121,7 +121,7 @@ class XPath(Parser):
|
|||
return Expr
|
||||
|
||||
def UnaryExpr(self):
|
||||
_token_ = self._peek("r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek("r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == "r'\\-'":
|
||||
self._scan("r'\\-'")
|
||||
ValueExpr = self.ValueExpr()
|
||||
|
@ -135,11 +135,11 @@ class XPath(Parser):
|
|||
return PathExpr
|
||||
|
||||
def PathExpr(self):
|
||||
_token_ = self._peek("r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek("r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == "r'\\/'":
|
||||
self._scan("r'\\/'")
|
||||
path = None
|
||||
if self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME', "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") not in ["'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'"]:
|
||||
if self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME', "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") not in ["'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'"]:
|
||||
RelativePathExpr = self.RelativePathExpr()
|
||||
path = RelativePathExpr
|
||||
return X.AbsolutePathExpr(path)
|
||||
|
@ -168,7 +168,7 @@ class XPath(Parser):
|
|||
return X.PathExpr(steps)
|
||||
|
||||
def StepExpr(self):
|
||||
_token_ = self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ["r'\\('", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE']:
|
||||
AxisStep = self.AxisStep()
|
||||
return AxisStep
|
||||
|
@ -177,7 +177,7 @@ class XPath(Parser):
|
|||
return FilterExpr
|
||||
|
||||
def AxisStep(self):
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ['REVERSE_AXIS_NAME', "r'\\.\\.'"]:
|
||||
ForwardStep = self.ForwardStep()
|
||||
step = ForwardStep
|
||||
|
@ -191,7 +191,7 @@ class XPath(Parser):
|
|||
return expr
|
||||
|
||||
def ForwardStep(self):
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == 'FORWARD_AXIS_NAME':
|
||||
ForwardAxis = self.ForwardAxis()
|
||||
NodeTest = self.NodeTest()
|
||||
|
@ -207,7 +207,7 @@ class XPath(Parser):
|
|||
|
||||
def AbbrevForwardStep(self):
|
||||
axis = 'child'
|
||||
if self._peek("r'@'", "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME') == "r'@'":
|
||||
if self._peek("r'@'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME') == "r'@'":
|
||||
self._scan("r'@'")
|
||||
axis = 'attribute'
|
||||
NodeTest = self.NodeTest()
|
||||
|
@ -233,7 +233,7 @@ class XPath(Parser):
|
|||
return ['parent', None]
|
||||
|
||||
def NodeTest(self):
|
||||
_token_ = self._peek("r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME')
|
||||
_token_ = self._peek("r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ["r'\\*'", 'NCNAME']:
|
||||
KindTest = self.KindTest()
|
||||
return KindTest
|
||||
|
@ -315,7 +315,7 @@ class XPath(Parser):
|
|||
FUNCNAME = self._scan('FUNCNAME')
|
||||
self._scan("r'\\('")
|
||||
args = []
|
||||
if self._peek("r'\\,'", "r'\\)'", "r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction'", "r'comment'", "r'text'", "r'node'", "r'\\*'", 'NCNAME') not in ["r'\\,'", "r'\\)'"]:
|
||||
if self._peek("r'\\,'", "r'\\)'", "r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME') not in ["r'\\,'", "r'\\)'"]:
|
||||
Expr = self.Expr()
|
||||
args.append(Expr)
|
||||
while self._peek("r'\\,'", "r'\\)'") == "r'\\,'":
|
||||
|
@ -326,24 +326,23 @@ class XPath(Parser):
|
|||
return X.Function(FUNCNAME, args)
|
||||
|
||||
def KindTest(self):
|
||||
_token_ = self._peek("r'processing-instruction'", "r'comment'", "r'text'", "r'node'")
|
||||
if _token_ == "r'processing-instruction'":
|
||||
_token_ = self._peek("r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('")
|
||||
if _token_ == "r'processing-instruction\\s*\\('":
|
||||
PITest = self.PITest()
|
||||
return PITest
|
||||
elif _token_ == "r'comment'":
|
||||
elif _token_ == "r'comment\\s*\\('":
|
||||
CommentTest = self.CommentTest()
|
||||
return CommentTest
|
||||
elif _token_ == "r'text'":
|
||||
elif _token_ == "r'text\\s*\\('":
|
||||
TextTest = self.TextTest()
|
||||
return TextTest
|
||||
else:# == "r'node'"
|
||||
else:# == "r'node\\s*\\('"
|
||||
AnyKindTest = self.AnyKindTest()
|
||||
return AnyKindTest
|
||||
|
||||
def PITest(self):
|
||||
self._scan("r'processing-instruction'")
|
||||
self._scan("r'processing-instruction\\s*\\('")
|
||||
name = None
|
||||
self._scan("r'\\('")
|
||||
if self._peek('NCNAME', "r'\\)'", 'DQUOTE', 'SQUOTE') != "r'\\)'":
|
||||
_token_ = self._peek('NCNAME', 'DQUOTE', 'SQUOTE')
|
||||
if _token_ == 'NCNAME':
|
||||
|
@ -356,20 +355,17 @@ class XPath(Parser):
|
|||
return X.PITest(name)
|
||||
|
||||
def CommentTest(self):
|
||||
self._scan("r'comment'")
|
||||
self._scan("r'\\('")
|
||||
self._scan("r'comment\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.CommentTest()
|
||||
|
||||
def TextTest(self):
|
||||
self._scan("r'text'")
|
||||
self._scan("r'\\('")
|
||||
self._scan("r'text\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.TextTest()
|
||||
|
||||
def AnyKindTest(self):
|
||||
self._scan("r'node'")
|
||||
self._scan("r'\\('")
|
||||
self._scan("r'node\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.AnyKindTest()
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ rm -f .nutools-devel
|
|||
# supprimer fichiers de développement
|
||||
rm -rf lib/pyulib/{build,devel,migrate,test}
|
||||
|
||||
# compiler les modules python de support
|
||||
estep "Compilation des modules python"
|
||||
python -m compileall lib/ulib/support/python
|
||||
|
||||
# liens pour les scripts python
|
||||
for i in plver plbck uencdetect urandomize umail uxpath wofixsql; do
|
||||
ln -s lib/pywrapper "$i"
|
||||
|
@ -21,6 +25,7 @@ done
|
|||
ln -s lib/ulib/support/cgiupload.py
|
||||
ln -s lib/ulib/support/cgiparams.py
|
||||
ln -s lib/ulib/support/cgilsxml.py
|
||||
ln -s lib/ulib/support/xpathtool.py
|
||||
|
||||
# liens pour les scripts shell
|
||||
for i in cg cgs; do
|
||||
|
|
559
lib/ulib/ptools
559
lib/ulib/ptools
|
@ -3,8 +3,9 @@
|
|||
##@cooked nocomments
|
||||
##@include vcs
|
||||
##@include semver
|
||||
##@include xmlsupport
|
||||
uprovide ptools
|
||||
urequire vcs semver
|
||||
urequire vcs semver xmlsupport
|
||||
|
||||
function is_any_branch() {
|
||||
local branch="$1"; shift
|
||||
|
@ -99,43 +100,93 @@ function list_feature_branches() {
|
|||
################################################################################
|
||||
# Outils de haut niveau
|
||||
|
||||
function __pom_get_version() {
|
||||
# obtenir la version dans le pom $1(=pom.xml)
|
||||
local pom="${1:-pom.xml}"
|
||||
awk <"$pom" '/^[ \t]*<version>/ {
|
||||
sub(/^.*<version>/, "")
|
||||
sub(/<\/version>.*$/, "")
|
||||
print
|
||||
exit
|
||||
}'
|
||||
__pver_perror() {
|
||||
local r="$1"; shift
|
||||
[ $# -gt 0 ] || set "Une erreur s'est produite"
|
||||
local m=$r
|
||||
[ $m -gt $# ] && m=$#
|
||||
[ $m -gt 0 ] && eerror "${!m}"
|
||||
return $r
|
||||
}
|
||||
function __pom_set_version() {
|
||||
# modifier la version du le fichier $1(=pom.xml) à la valeur
|
||||
# $2(=1.0.0-SNAPSHOT)
|
||||
|
||||
__pver_unless() {
|
||||
local r m
|
||||
if [[ "$1" == -* ]]; then
|
||||
[ "${@:1:2}" ] 2>/dev/null; r=$?
|
||||
shift; shift
|
||||
else
|
||||
[ "${@:1:3}" ] 2>/dev/null; r=$?
|
||||
shift; shift; shift
|
||||
fi
|
||||
__pver_perror $r "$@"
|
||||
}
|
||||
|
||||
function __pver_get_prel_version() {
|
||||
# retourner la version correspondant à la branche courante si c'est une
|
||||
# branche de release. retourner 1 si la branche courante n'est pas une
|
||||
# branche de release, 2 si on n'est pas dans un dépôt git
|
||||
local branch
|
||||
branch="$(git_get_branch)" || return 2
|
||||
if [[ "$branch" == release-* ]]; then
|
||||
echo "${branch#release-}"
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
function __pver_pom_get_vpath() {
|
||||
# pour le fichier $1(=pom.xml), retourner le chemin dans lequel se trouve la
|
||||
# version du projet
|
||||
local pom="${1:-pom.xml}"
|
||||
if xpathtool -tf "$pom" /project/version 2>/dev/null; then
|
||||
echo /project/version
|
||||
elif xpathtool -tf "$pom" /project/parent/version 2>/dev/null; then
|
||||
echo /project/parent/version
|
||||
else
|
||||
echo /project/version
|
||||
fi
|
||||
}
|
||||
|
||||
function __pver_pom_get_version() {
|
||||
# obtenir la version dans le pom $1(=pom.xml) à partir du chemin $2, qui est
|
||||
# déterminé automatiquement s'il n'est pas spécifié.
|
||||
local pom="${1:-pom.xml}"
|
||||
local vpath="$2"
|
||||
local version
|
||||
if [ -n "$vpath" ]; then
|
||||
xpathtool -f "$pom" -g "$vpath"
|
||||
return
|
||||
fi
|
||||
version="$(xpathtool -f "$pom" -g /project/version 2>/dev/null)"
|
||||
if [ -n "$version" ]; then
|
||||
echo "$version"
|
||||
return
|
||||
fi
|
||||
version="$(xpathtool -f "$pom" -g /project/parent/version 2>/dev/null)"
|
||||
if [ -n "$version" ]; then
|
||||
echo "$version"
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
function __pver_pom_set_version() {
|
||||
# modifier la version dans le pom $1(=pom.xml) à la valeur
|
||||
# $2(=1.0.0-SNAPSHOT) en utilisant le chemin xpath $3, qui est déterminé
|
||||
# automatiquement s'il n'est pas spécifié.
|
||||
# retourner 0 si la version a été mise à jour dans le chemin /project/version
|
||||
# retourner 1 si la version a été mise à jour dans le chemin /project/parent/version
|
||||
# retourner 2 si la version a été mise à jour dans un autre chemin
|
||||
# retourner 3 si une erreur s'est produite
|
||||
local pom="${1:-pom.xml}"
|
||||
local version="${2:-1.0.0-SNAPSHOT}"
|
||||
local tmpfile; ac_set_tmpfile tmpfile
|
||||
awk <"$pom" >"$tmpfile" '
|
||||
BEGIN {
|
||||
version = '"$(qawk "$version")"'
|
||||
found = 0
|
||||
}
|
||||
!found && $0 ~ /^[ \t]*<version>/ {
|
||||
prefix = "<version>"
|
||||
if (match($0, /^.*<version>/)) {
|
||||
prefix = substr($0, RSTART, RLENGTH)
|
||||
}
|
||||
suffix = "</version>"
|
||||
if (match($0, /<\/version>.*$/)) {
|
||||
suffix = substr($0, RSTART, RLENGTH)
|
||||
}
|
||||
print prefix version suffix
|
||||
found = 1
|
||||
next
|
||||
}
|
||||
{ print }'
|
||||
cat "$tmpfile" >"$pom"
|
||||
ac_clean "$tmpfile"
|
||||
local vpath="$3"
|
||||
[ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$pom")"
|
||||
xpathtool -f "$pom" -s "$vpath" "$version" || return 3
|
||||
case "$vpath" in
|
||||
/project/version) return 0;;
|
||||
/project/parent/version) return 1;;
|
||||
*) return 2;;
|
||||
esac
|
||||
}
|
||||
|
||||
function pver() {
|
||||
|
@ -145,92 +196,170 @@ function pver() {
|
|||
local -a args
|
||||
local action=auto
|
||||
local source=auto
|
||||
local file=
|
||||
local git=
|
||||
local version=
|
||||
local allow_empty=
|
||||
local convert=auto
|
||||
local operator=
|
||||
local oversion=
|
||||
local setversion=
|
||||
local incversion=
|
||||
local setprelease=
|
||||
local setalpha=
|
||||
local setbeta=
|
||||
local setrc=
|
||||
local setrelease=
|
||||
local setmetadata= addmetadata=
|
||||
local vcsmetadata=
|
||||
local file git version operator oversion
|
||||
local setversion incversion
|
||||
local setpr setprelease setsnapshot setalpha setbeta setrc setrelease
|
||||
local setmd resetmetadata setmetadata addmetadata vcsmetadata
|
||||
local vpath setmapfile mapfile allow_empty convert=auto maven_update
|
||||
parse_opts "${PRETTYOPTS[@]}" \
|
||||
--help '$exit_with pver_display_help' \
|
||||
-f:,--file: '$set@ file; source=file' \
|
||||
-e:,--maven:,--pom: '$set@ file; source=pom' \
|
||||
-F:,--file-string: '$set@ file; source=file-string' \
|
||||
-g:,--git-string: '$set@ git; source=git-string' \
|
||||
-s:,--string: '$set@ version; source=string' \
|
||||
-w:,--w:,--fw:,--auto-file: '$set@ file; source=auto-file' \
|
||||
--sw:,--auto-string: '$set@ file; source=auto-string' \
|
||||
--gw:,--auto-git-string: '$set@ git; source=auto-git-string' \
|
||||
-e:,--e:,--pom:,--maven: '$set@ file; source=pom' \
|
||||
-E:,--E:,--pom-string:,--maven-string: '$set@ file; source=pom-string' \
|
||||
-f:,--f:,--file: '$set@ file; source=file' \
|
||||
-F:,--F:,--file-string: '$set@ file; source=file-string' \
|
||||
-g:,--g:,--git-file-string:,--git-string: '$set@ git; source=git-file-string' \
|
||||
-G:,--G:,--git-pom-string: '$set@ git; source=git-pom-string' \
|
||||
--git-prel-string source=git-prel-string \
|
||||
-s:,--s:,--string: '$set@ version; source=string' \
|
||||
--show action=show \
|
||||
--allow-empty allow_empty=1 \
|
||||
--show-source action=show-source \
|
||||
--check action=check \
|
||||
--convert convert=1 \
|
||||
--no-convert convert= \
|
||||
--eq: '$action=compare; operator=eq; set@ oversion' \
|
||||
--ne: '$action=compare; operator=ne; set@ oversion' \
|
||||
--lt: '$action=compare; operator=lt; set@ oversion' \
|
||||
--le: '$action=compare; operator=le; set@ oversion' \
|
||||
--gt: '$action=compare; operator=gt; set@ oversion' \
|
||||
--ge: '$action=compare; operator=ge; set@ oversion' \
|
||||
-v:,--set-version: '$action=update; set@ setversion; incversion=' \
|
||||
--prel '$action=update; setversion=prel; incversion=' \
|
||||
-u,--update '$action=update; [ -z "$incversion" ] && incversion=auto' \
|
||||
--menu '$action=update; incversion=menu' \
|
||||
-v:,--set-version: '$action=update; set@ setversion; incversion=' \
|
||||
--prel '$action=update; setversion=prel; incversion=' \
|
||||
-x,--major '$action=update; incversion=major' \
|
||||
-z,--minor '$action=update; incversion=minor' \
|
||||
-p,--patchlevel '$action=update; incversion=patchlevel' \
|
||||
-l:,--prelease:,--prerelease: '$action=update; set@ setprelease; [ -z "$setprelease" ] && { setalpha=; setbeta=; setrc=; setrelease=1; }' \
|
||||
-a,--alpha '$action=update; setalpha=1; setbeta=; setrc=; setrelease=' \
|
||||
-b,--beta '$action=update; setalpha=; setbeta=1; setrc=; setrelease=' \
|
||||
-r,--rc '$action=update; setalpha=; setbeta=; setrc=1; setrelease=' \
|
||||
-R,--release,--final '$action=update; setalpha=; setbeta=; setrc=; setrelease=1' \
|
||||
-m:,--metadata:,--set-metadata: '$action=update; set@ setmetadata' \
|
||||
--add-metadata: '$action=update; set@ addmetadata' \
|
||||
-M,--vcs-metadata '$action=update; vcsmetadata=1' \
|
||||
-k,--keep '$action=update; incversion=' \
|
||||
-l:,--prelease:,--prerelease: '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=; set@ setprelease; [ -z "$setprelease" ] && setrelease=1' \
|
||||
-S,--snapshot '$action=update; setpr=1; setsnapshot=1; setalpha=; setbeta=; setrc=; setrelease=' \
|
||||
-a,--alpha '$action=update; setpr=1; setsnapshot=; setalpha=1; setbeta=; setrc=; setrelease=' \
|
||||
-b,--beta '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=1; setrc=; setrelease=' \
|
||||
-r,--rc '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=1; setrelease=' \
|
||||
-R,--release,--final '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=1' \
|
||||
-m:,--metadata:,--set-metadata: '$action=update; setmd=1; resetmetadata=1; set@ setmetadata' \
|
||||
--add-metadata: '$action=update; setmd=1; set@ addmetadata' \
|
||||
-M,--vcs-metadata '$action=update; setmd=1; vcsmetadata=1' \
|
||||
--vpath: vpath= \
|
||||
--map: '$setmapfile=1; set@ mapfile' \
|
||||
--allow-empty allow_empty=1 \
|
||||
--convert convert=1 \
|
||||
--no-convert convert= \
|
||||
-t,--maven-update maven_update=1 \
|
||||
@ args -- "$@" && set -- "${args[@]}" || { eerror "$args"; return 1; }
|
||||
|
||||
# Calculer la source
|
||||
if [ "$source" == auto-file -o "$source" == auto-string ]; then
|
||||
[ -n "$file" ] || file=.
|
||||
if [ -d "$file" ]; then
|
||||
if [ -f "$file/$DEFAULT_POM" ]; then
|
||||
file="$file/$DEFAULT_POM"
|
||||
elif [ -f "$file/$DEFAULT_FILE" ]; then
|
||||
file="$file/$DEFAULT_FILE"
|
||||
elif [ -f "$file/version.txt" ]; then
|
||||
file="$file/version.txt"
|
||||
else
|
||||
file="$file/$DEFAULT_FILE"
|
||||
fi
|
||||
fi
|
||||
if [ "$source" == auto-file ]; then
|
||||
if [[ "$file" == *.xml ]]; then source=pom
|
||||
else source=file
|
||||
fi
|
||||
elif [ "$source" == auto-string ]; then
|
||||
if [[ "$file" == *.xml ]]; then source=pom-string
|
||||
else source=file-string
|
||||
fi
|
||||
fi
|
||||
edebug "Auto-sélection de $(ppath "$file")"
|
||||
|
||||
elif [ "$source" == auto-git-string ]; then
|
||||
git_check_gitvcs || return 2
|
||||
splitfsep2 "$git" : branch name
|
||||
[ -n "$branch" ] || branch=master
|
||||
if [ "$(git cat-file -t "$branch:$name" 2>/dev/null)" == tree ]; then
|
||||
if git rev-parse --verify --quiet "$branch:${name:+$name/}$DEFAULT_POM" >/dev/null; then
|
||||
name="${name:+$name/}$DEFAULT_POM"
|
||||
elif git rev-parse --verify --quiet "$branch:${name:+$name/}$DEFAULT_FILE" >/dev/null; then
|
||||
name="${name:+$name/}$DEFAULT_FILE"
|
||||
elif git rev-parse --verify --quiet "$branch:${name:+$name/}version.txt" >/dev/null; then
|
||||
name="${name:+$name/}version.txt"
|
||||
fi
|
||||
fi
|
||||
if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
|
||||
if [[ "$name" == *.xml ]]; then source=git-pom-string
|
||||
else source=git-file-string
|
||||
fi
|
||||
git="$branch:$name"
|
||||
edebug "Auto-sélection de $git"
|
||||
else
|
||||
eerror "$name: fichier introuvable sur la branche $branch"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$source" == auto ]; then
|
||||
source=file
|
||||
for i in "$DEFAULT_FILE" version.txt "$DEFAULT_POM"; do
|
||||
for i in "$DEFAULT_POM" "$DEFAULT_FILE" version.txt; do
|
||||
if [ -f "$i" ]; then
|
||||
case "$i" in
|
||||
"$DEFAULT_POM")
|
||||
source=pom
|
||||
file="$i"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
source=file
|
||||
file="$i"
|
||||
break
|
||||
;;
|
||||
"$DEFAULT_POM") source=pom; file="$i"; break;;
|
||||
*) source=file; file="$i"; break;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
elif [ "$source" == file ]; then
|
||||
elif [ "$source" == file -o "$source" == pom ]; then
|
||||
[ "$action" == auto ] && action=update
|
||||
fi
|
||||
[ "$source" == file -a -z "$file" ] && file="$DEFAULT_FILE"
|
||||
[ "$source" == pom -a -z "$file" ] && file="$DEFAULT_POM"
|
||||
[ "$action" == auto ] && action=show
|
||||
|
||||
if [[ "$source" == auto* ]]; then
|
||||
eerror "bug: impossible de déterminer la source"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$action" == show-source ]; then
|
||||
echo "$source"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Lire la version
|
||||
local -a maprules
|
||||
if [ "$source" == file -o "$source" == pom ]; then
|
||||
local mapdir="$(dirname -- "$file")"
|
||||
if [ -z "$setmapfile" ]; then
|
||||
local tmpfile
|
||||
tmpfile="$mapdir/.pver-map"
|
||||
[ -f "$tmpfile" ] && mapfile="$tmpfile"
|
||||
fi
|
||||
if [ -n "$mapfile" ]; then
|
||||
__pver_unless -f "$mapfile" "$mapfile: fichier introuvable" || return
|
||||
|
||||
mapdir="$(dirname -- "$mapfile")"
|
||||
array_from_lines maprules "$(<"$mapfile" filter_conf)"
|
||||
local maprule filespec filevpath filename
|
||||
local -a filenames
|
||||
for maprule in "${maprules[@]}"; do
|
||||
splitpair "$maprule" filespec filevpath
|
||||
[ "$filevpath" != - ] || continue
|
||||
array_lsfiles filenames "$mapdir" "$filespec"
|
||||
[ ${#filenames[*]} -gt 0 ] || continue
|
||||
file="${filenames[0]}"
|
||||
if [[ "$file" == *.xml ]]; then source=pom
|
||||
else source=file
|
||||
fi
|
||||
edebug "Sélection de $file comme fichier de référence"
|
||||
break
|
||||
done
|
||||
fi
|
||||
fi
|
||||
[ "$source" == pom ] && maven_update=1
|
||||
|
||||
if [ "$source" == file ]; then
|
||||
[ -f "$file" ] && version="$(<"$file")"
|
||||
elif [ "$source" == pom ]; then
|
||||
[ -f "$file" ] || {
|
||||
eerror "$file: fichier introuvable"
|
||||
return 1
|
||||
}
|
||||
version="$(__pom_get_version "$file")"
|
||||
|
||||
elif [ "$source" == file-string ]; then
|
||||
if [ -z "$file" ]; then
|
||||
file="$DEFAULT_FILE"
|
||||
|
@ -239,14 +368,51 @@ function pver() {
|
|||
fi
|
||||
[ -f "$file" ] && version="$(<"$file")"
|
||||
file=
|
||||
elif [ "$source" == git-string ]; then
|
||||
|
||||
elif [ "$source" == git-file-string ]; then
|
||||
git_check_gitvcs || return 2
|
||||
splitfsep2 "$git" : branch name
|
||||
[ -n "$branch" ] || branch=master
|
||||
[ -n "$name" ] || name="$DEFAULT_FILE"
|
||||
if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
|
||||
version="$(git cat-file blob "$branch:$name" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
elif [ "$source" == pom ]; then
|
||||
__pver_unless -f "$file" "$file: fichier introuvable" || return
|
||||
[ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$file")"
|
||||
version="$(__pver_pom_get_version "$file" "$vpath")"
|
||||
|
||||
elif [ "$source" == pom-string ]; then
|
||||
if [ -z "$file" ]; then file="$DEFAULT_POM"
|
||||
elif [ -d "$file" ]; then file="$file/$DEFAULT_POM"
|
||||
fi
|
||||
__pver_unless -f "$file" "$file: fichier introuvable" || return
|
||||
|
||||
[ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$file")"
|
||||
version="$(__pver_pom_get_version "$file" "$vpath")"
|
||||
file=
|
||||
|
||||
elif [ "$source" == git-pom-string ]; then
|
||||
git_check_gitvcs || return 2
|
||||
splitfsep2 "$git" : branch name
|
||||
[ -n "$branch" ] || branch=master
|
||||
[ -n "$name" ] || name="$DEFAULT_POM"
|
||||
if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
|
||||
local tmpfile; ac_set_tmpfile tmpfile
|
||||
git cat-file blob "$branch:$name" >"$tmpfile" 2>/dev/null
|
||||
[ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$tmpfile")"
|
||||
version="$(__pver_pom_get_version "$tmpfile" "$vpath")"
|
||||
ac_clean "$tmpfile"
|
||||
else
|
||||
eerror "$name: fichier introuvable sur la branche $branch"
|
||||
return 1
|
||||
fi
|
||||
|
||||
elif [ "$source" == git-prel-string ]; then
|
||||
version="$(__pver_get_prel_version)" || return
|
||||
fi
|
||||
|
||||
[ -n "$version" -o -n "$allow_empty" ] || version=0.0.0
|
||||
|
||||
# Conversion éventuelle du numéro de version
|
||||
|
@ -285,7 +451,7 @@ BEGIN {
|
|||
version = version ".0"
|
||||
}
|
||||
# afficher la version migrée au format semver
|
||||
if (metadata != "") print version "+" metadata
|
||||
if (metadata != "") print version "+r" metadata
|
||||
else print version
|
||||
|
||||
### maven, pom.xml
|
||||
|
@ -339,7 +505,7 @@ BEGIN {
|
|||
fi
|
||||
|
||||
if [ "$action" == check ]; then
|
||||
[ -n "$valid" ] || { eerror "Numéro de version invalide: $version"; return 1; }
|
||||
__pver_unless -n "$valid" "Numéro de version invalide: $version" || return
|
||||
|
||||
elif [ "$action" == compare ]; then
|
||||
psemver_parse "$oversion" o
|
||||
|
@ -423,94 +589,100 @@ BEGIN {
|
|||
|
||||
elif [ "$action" == update ]; then
|
||||
[ -z "$version" -a -n "$allow_empty" ] && return 1
|
||||
[ -n "$valid" ] || { eerror "Numéro de version invalide: $version"; return 1; }
|
||||
__pver_unless -n "$valid" "Numéro de version invalide: $version" || return
|
||||
|
||||
if [ -n "$file" ]; then
|
||||
if [ -f "$file" ]; then
|
||||
if isatty; then
|
||||
estepi "La version actuelle est $version"
|
||||
fi
|
||||
isatty && estepi "La version actuelle est $version"
|
||||
elif [ "$source" == pom ]; then
|
||||
eerror "$file: fichier introuvable"
|
||||
return 1
|
||||
else
|
||||
if isatty; then
|
||||
elif isatty; then
|
||||
ask_yesno "Le fichier $(ppath "$file") n'existe pas. Faut-il le créer?" O || return 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# forcer le numéro de version
|
||||
if [ -n "$setversion" ]; then
|
||||
if [ "$setversion" == prel ]; then
|
||||
local branch; branch="$(git_get_branch)" || return 2
|
||||
if [[ "$branch" == release-* ]]; then
|
||||
setversion="${branch#release-}"
|
||||
else
|
||||
eerror "$branch: n'est pas une release branch"
|
||||
setversion="$(__pver_get_prel_version)"
|
||||
__pver_perror $? \
|
||||
"$(git_get_branch): n'est pas une release branch" \
|
||||
"Dépôt git introuvable" || return
|
||||
fi
|
||||
psemver_setversion "$setversion" "" || {
|
||||
eerror "Numéro de version invalide: $setversion"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
psemver_setversion "$setversion" "" || { eerror "Numéro de version invalide: $setversion"; return 1; }
|
||||
}
|
||||
fi
|
||||
|
||||
# Calculer metadata
|
||||
if [ -n "$vcsmetadata" ]; then
|
||||
resetmetadata=1
|
||||
setmetadata="$(git rev-parse --short HEAD)" || return 1
|
||||
fi
|
||||
|
||||
# incrémenter les numéros de version
|
||||
if [ -n "$maven_update" -a -n "$incversion" ]; then
|
||||
# il y a des règles particulières pour maven
|
||||
if [ -n "$setrelease" -a -z "$prelease" ]; then
|
||||
# on est déjà en release, faire le traitement normal
|
||||
maven_update=
|
||||
elif [ -n "$setsnapshot" -a "$prelease" == SNAPSHOT ]; then
|
||||
# on est déjà en snapshot, faire le traitement normal, mais garder le préfixe SNAPSHOT
|
||||
maven_update=
|
||||
if [ "$incversion" == auto ]; then
|
||||
if [ -n "$setrelease" -o -n "$setprelease" -o -n "$setmetadata" -o -n "$addmetadata" ]; then
|
||||
incversion=
|
||||
else
|
||||
incversion=menu
|
||||
[ -n "$setmd" ] && incversion= || incversion=menu
|
||||
fi
|
||||
elif [ -z "$prelease" ]; then
|
||||
# on est en release, passer en snapshot
|
||||
setsnapshot=1
|
||||
setrelease=
|
||||
if [ "$incversion" == auto ]; then
|
||||
[ -n "$setmd" ] && incversion= || incversion=menu
|
||||
fi
|
||||
elif [ "$prelease" == SNAPSHOT ]; then
|
||||
# on est en snapshot, passer en release
|
||||
setsnapshot=
|
||||
setrelease=1
|
||||
if [ "$incversion" == auto ]; then
|
||||
[ -n "$setmd" ] && incversion= || incversion=menu
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ "$incversion" == auto ]; then
|
||||
[ -n "$setpr" -o -n "$setmd" ] && incversion= || incversion=menu
|
||||
fi
|
||||
if [ -z "$incversion" -a -n "$maven_update" ]; then
|
||||
# on doit incrémenter avec les règles maven, mais aucune des options
|
||||
# -[xzp] n'est spécifiée
|
||||
if [ -n "$setrelease" ]; then
|
||||
incversion=patchlevel
|
||||
elif [ -n "$setsnapshot" ]; then
|
||||
if [ "$patchlevel" -eq 0 ]; then
|
||||
incversion=minor
|
||||
else
|
||||
incversion=patchlevel
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$setrelease" ]; then setprelease=
|
||||
elif [ -n "$setsnapshot" ]; then setprelease=SNAPSHOT
|
||||
fi
|
||||
if [ "$incversion" == menu ]; then
|
||||
psemver_copy x; {
|
||||
psemver_incmajor x
|
||||
psemver_setprelease "$setprelease" x
|
||||
if [ -n "$addmetadata" ]; then
|
||||
[ -n "$setmetadata" ] && psemver_setmetadata "$setmetadata" x
|
||||
psemver_addmetadata "$addmetadata" x
|
||||
else
|
||||
psemver_setmetadata "$setmetadata" x
|
||||
fi
|
||||
psemver_copy x
|
||||
psemver_incsetprmd major x "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||
psemver_setvar versionx x
|
||||
}
|
||||
psemver_copy z; {
|
||||
psemver_incminor z
|
||||
psemver_setprelease "$setprelease" z
|
||||
if [ -n "$addmetadata" ]; then
|
||||
[ -n "$setmetadata" ] && psemver_setmetadata "$setmetadata" z
|
||||
psemver_addmetadata "$addmetadata" z
|
||||
else
|
||||
psemver_setmetadata "$setmetadata" z
|
||||
fi
|
||||
psemver_copy z
|
||||
psemver_incsetprmd minor z "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||
psemver_setvar versionz z
|
||||
}
|
||||
psemver_copy p; {
|
||||
psemver_incpatchlevel p
|
||||
psemver_setprelease "$setprelease" p
|
||||
if [ -n "$addmetadata" ]; then
|
||||
[ -n "$setmetadata" ] && psemver_setmetadata "$setmetadata" p
|
||||
psemver_addmetadata "$addmetadata" p
|
||||
else
|
||||
psemver_setmetadata "$setmetadata" p
|
||||
fi
|
||||
psemver_copy p
|
||||
psemver_incsetprmd patchlevel p "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||
psemver_setvar versionp p
|
||||
}
|
||||
psemver_copy k; {
|
||||
psemver_setprelease "$setprelease" k
|
||||
if [ -n "$addmetadata" ]; then
|
||||
[ -n "$setmetadata" ] && psemver_setmetadata "$setmetadata" k
|
||||
psemver_addmetadata "$addmetadata" k
|
||||
else
|
||||
psemver_setmetadata "$setmetadata" k
|
||||
fi
|
||||
psemver_copy k
|
||||
psemver_incsetprmd "" k "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata" "$maven_update"
|
||||
psemver_setvar versionk k
|
||||
}
|
||||
nextvs=(
|
||||
"$versionx : maj incompatibles de l'API (-x)"
|
||||
"$versionz : maj compatibles de l'API (-z)"
|
||||
|
@ -528,49 +700,74 @@ BEGIN {
|
|||
*) incversion=;;
|
||||
esac
|
||||
fi
|
||||
|
||||
local r
|
||||
if [ -n "$incversion" ]; then
|
||||
case "$incversion" in
|
||||
major) psemver_incmajor;;
|
||||
minor) psemver_incminor;;
|
||||
patchlevel) psemver_incpatchlevel;;
|
||||
psemver_incsetprmd "$incversion" "" "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||
r=$?
|
||||
else
|
||||
psemver_setprmd "" "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata"
|
||||
r=$?
|
||||
fi
|
||||
case $r in
|
||||
2) eerror "Identifiant de pre-release invalide: $setprelease"; return 1;;
|
||||
3) eerror "Identifiant de build invalide: $setmetadata"; return 1;;
|
||||
4) eerror "Identifiant de build invalide: $addmetadata"; return 1;;
|
||||
esac
|
||||
# Quand on incrémente, réinitialiser la valeur de prérelease et metadata
|
||||
psemver_setprelease
|
||||
[ -z "$addmetadata" ] && psemver_setmetadata
|
||||
fi
|
||||
|
||||
# spécifier prerelease
|
||||
if [ -n "$setrelease" ]; then
|
||||
psemver_setprelease ""
|
||||
elif [ -n "$setprelease" ]; then
|
||||
psemver_setprelease "$setprelease" || { eerror "Identifiant de pre-release invalide: $setprelease"; return 1; }
|
||||
fi
|
||||
if [ -n "$setalpha" ]; then
|
||||
: #XXX
|
||||
elif [ -n "$setbeta" ]; then
|
||||
: #XXX
|
||||
elif [ -n "$setrc" ]; then
|
||||
: #XXX
|
||||
fi
|
||||
|
||||
# spécifier metadata
|
||||
if [ -n "$setmetadata" ]; then
|
||||
psemver_setmetadata "$setmetadata" || { eerror "Identifiant de build invalide: $setmetadata"; return 1; }
|
||||
fi
|
||||
if [ -n "$addmetadata" ]; then
|
||||
psemver_addmetadata "$addmetadata" || { eerror "Identifiant de build invalide: $addmetadata"; return 1; }
|
||||
fi
|
||||
|
||||
# afficher le résultat final
|
||||
local -a depfiles
|
||||
psemver_setvar version
|
||||
if [ -n "$file" ]; then
|
||||
case "$source" in
|
||||
file) echo "$version" >"$file";;
|
||||
pom) __pom_set_version "$file" "$version";;
|
||||
if [ "$source" == file ]; then
|
||||
echo "$version" >"$file"
|
||||
elif [ "$source" == pom ]; then
|
||||
__pver_pom_set_version "$file" "$version"
|
||||
[ $? -eq 3 ] && return 1
|
||||
fi
|
||||
if [ ${#maprules[*]} -gt 0 ]; then
|
||||
# mettre à jour les fichiers mentionnés dans mapfile
|
||||
local -a donefiles
|
||||
for maprule in "${maprules[@]}"; do
|
||||
splitpair "$maprule" filespec filevpath
|
||||
array_lsfiles filenames "$mapdir" "$filespec"
|
||||
for file in "${filenames[@]}"; do
|
||||
file="$(abspath "$file")"
|
||||
edebug "Examen de $file"
|
||||
# si c'est un wildcard, ne traiter que si le fichier n'a
|
||||
# pas encore été traité
|
||||
case "$filespec" in *\**|*\?*) array_contains donefiles "$file" && break;; esac
|
||||
if [ "$filevpath" != - ]; then
|
||||
if [[ "$file" == *.xml ]]; then
|
||||
edebug "Maj version de $file au chemin XPATH ${filevpath:-par défaut}"
|
||||
__pver_pom_set_version "$file" "$version" "$filevpath"
|
||||
case $? in
|
||||
0|1) :;;
|
||||
2) array_addu depfiles "$file";;
|
||||
*) return 1;;
|
||||
esac
|
||||
else
|
||||
edebug "Maj version de $file"
|
||||
echo "$version" >"$file"
|
||||
fi
|
||||
else
|
||||
edebug "Fichier $file ignoré"
|
||||
fi
|
||||
array_addu donefiles "$file"
|
||||
done
|
||||
done
|
||||
fi
|
||||
fi
|
||||
if isatty; then
|
||||
estepn "La nouvelle version est $version"
|
||||
if [ ${#depfiles[*]} -gt 0 ]; then
|
||||
local msg="Les fichiers suivants ont été modifiés, et leur version doit être mise à jour:"
|
||||
for file in "${depfiles[@]}"; do
|
||||
msg="$msg
|
||||
$(qvals pver -uzw "$file" -R --menu)"
|
||||
done
|
||||
eimportant "$msg"
|
||||
fi
|
||||
else
|
||||
echo "$version"
|
||||
fi
|
||||
|
|
|
@ -10,6 +10,7 @@ function __semver_check_prelease() { [ -z "${1//[a-zA-Z0-9.-]/}" ]; }
|
|||
function __semver_check_metadata() { [ -z "${1//[a-zA-Z0-9.-]/}" ]; }
|
||||
|
||||
function semver_parse() {
|
||||
# args: version majorV minorV patchlevelV preleaseV metadataV validV
|
||||
local __p_ver="$1"
|
||||
local __p_ma="${2:-major}" __p_mi="${3:-minor}" __p_pl="${4:-patchlevel}"
|
||||
local __p_pr="${5:-prelease}" __p_md="${6:-metadata}" __p_va="${7:-valid}"
|
||||
|
@ -84,34 +85,79 @@ function semver_parse() {
|
|||
}
|
||||
|
||||
function semver_incmajor() {
|
||||
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||
if [ -z "$6" ]; then
|
||||
setv "$1" $((${!1} + 1))
|
||||
setv "$2" 0
|
||||
setv "$3" 0
|
||||
array_new "$4"
|
||||
elif [ -z "$7" ]; then
|
||||
# maven snapshot --> release
|
||||
if [ ${!2} -ne 0 -o ${!3} -ne 0 ]; then
|
||||
setv "$1" $((${!1} + 1))
|
||||
setv "$2" 0
|
||||
setv "$3" 0
|
||||
fi
|
||||
array_new "$4"
|
||||
else
|
||||
# maven release --> snapshot
|
||||
setv "$2" $((${!2} + 1))
|
||||
setv "$3" 0
|
||||
array_split "$4" "$setprelease" .
|
||||
fi
|
||||
}
|
||||
|
||||
function semver_incminor() {
|
||||
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||
if [ -z "$6" ]; then
|
||||
setv "$2" $((${!2} + 1))
|
||||
setv "$3" 0
|
||||
array_new "$4"
|
||||
elif [ -z "$7" ]; then
|
||||
# maven snapshot --> release
|
||||
if [ ${!3} -ne 0 ]; then
|
||||
setv "$2" $((${!2} + 1))
|
||||
setv "$3" 0
|
||||
fi
|
||||
array_new "$4"
|
||||
else
|
||||
# maven release --> snapshot
|
||||
setv "$2" $((${!2} + 1))
|
||||
setv "$3" 0
|
||||
array_split "$4" "$setprelease" .
|
||||
fi
|
||||
}
|
||||
|
||||
function semver_incpatchlevel() {
|
||||
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||
if [ -z "$6" ]; then
|
||||
setv "$3" $((${!3} + 1))
|
||||
array_new "$4"
|
||||
elif [ -z "$7" ]; then
|
||||
# maven snapshot --> release
|
||||
:
|
||||
else
|
||||
# maven release --> snapshot
|
||||
setv "$3" $((${!3} + 1))
|
||||
array_split "$4" "$setprelease" .
|
||||
fi
|
||||
}
|
||||
|
||||
function semver_setversion() {
|
||||
# args: version majorV minorV patchlevelV preleaseV metadataV
|
||||
local __sv_ma __sv_mi __sv_svl __sv_svr __sv_md __sv_va
|
||||
semver_parse "$1" __sv_ma __sv_mi __sv_pl __sv_pr __sv_md __sv_va
|
||||
[ -n "$__sv_va" ] || return 1
|
||||
setv "$2" "$__sv_ma"
|
||||
setv "$3" "$__sv_mi"
|
||||
setv "$4" "$__sv_pl"
|
||||
array_copy "$5" __sv_pr
|
||||
array_copy "$6" __sv_md
|
||||
return 0
|
||||
}
|
||||
|
||||
function semver_setprelease() {
|
||||
# args: setprelease majorV minorV patchlevelV preleaseV metadataV
|
||||
if [ -n "$1" ]; then
|
||||
__semver_check_prelease "$1" || return 1
|
||||
array_split "$5" "$1" .
|
||||
|
@ -122,6 +168,7 @@ function semver_setprelease() {
|
|||
}
|
||||
|
||||
function semver_compare_prelease() {
|
||||
# args: prelease1 prelease2
|
||||
local -a __cp_pr1 __cp_pr2 __cp_len i __cp_v1 __cp_v2
|
||||
array_copy __cp_pr1 "$1"
|
||||
array_copy __cp_pr2 "$2"
|
||||
|
@ -179,6 +226,7 @@ function semver_compare_prelease() {
|
|||
}
|
||||
|
||||
function semver_setmetadata() {
|
||||
# args: setmetadata majorV minorV patchlevelV preleaseV metadataV
|
||||
if [ -n "$1" ]; then
|
||||
__semver_check_metadata "$1" || return 1
|
||||
array_split "$6" "$1" .
|
||||
|
@ -189,6 +237,7 @@ function semver_setmetadata() {
|
|||
}
|
||||
|
||||
function semver_addmetadata() {
|
||||
# args: addmetadata majorV minorV patchlevelV preleaseV metadataV
|
||||
if [ -n "$1" ]; then
|
||||
__semver_check_metadata "$1" || return 1
|
||||
local -a __sam_metadata
|
||||
|
@ -199,11 +248,13 @@ function semver_addmetadata() {
|
|||
}
|
||||
|
||||
function semver_compare_metadata() {
|
||||
# args: metadata1 metadata2
|
||||
# même algo que pour prelease
|
||||
semver_compare_prelease "$@"
|
||||
}
|
||||
|
||||
function semver_copy() {
|
||||
# args: majorDV minorDV patchlevelDV preleaseDV metadataDV majorSV minorSV patchlevelSV preleaseSV metadataSV
|
||||
setv "$1" "${!6}"
|
||||
setv "$2" "${!7}"
|
||||
setv "$3" "${!8}"
|
||||
|
@ -212,6 +263,7 @@ function semver_copy() {
|
|||
}
|
||||
|
||||
function semver_build() {
|
||||
# args: majorV minorV patchlevelV preleaseV metadataV
|
||||
echo_ "${!1}.${!2}.${!3}"
|
||||
array_isempty "$4" || recho_ "-$(array_join "$4" .)"
|
||||
array_isempty "$5" || recho_ "+$(array_join "$5" .)"
|
||||
|
@ -219,6 +271,7 @@ function semver_build() {
|
|||
}
|
||||
|
||||
function semver_setvar() {
|
||||
# args: versionV majorV minorV patchlevelV preleaseV metadataV
|
||||
setv "$1" "$(semver_build "$2" "$3" "$4" "$5" "$6")"
|
||||
}
|
||||
|
||||
|
@ -228,9 +281,9 @@ function semver_setvar() {
|
|||
# uniquement un préfixe pour les noms de variable
|
||||
|
||||
function psemver_parse() { semver_parse "$1" "${2}major" "${2}minor" "${2}patchlevel" "${2}prelease" "${2}metadata" "${2}valid"; }
|
||||
function psemver_incmajor() { semver_incmajor "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${1}metadata"; }
|
||||
function psemver_incminor() { semver_incminor "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${1}metadata"; }
|
||||
function psemver_incpatchlevel() { semver_incpatchlevel "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${1}metadata"; }
|
||||
function psemver_incmajor() { semver_incmajor "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${2}metadata" "$2" "$3"; }
|
||||
function psemver_incminor() { semver_incminor "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${2}metadata" "$2" "$3"; }
|
||||
function psemver_incpatchlevel() { semver_incpatchlevel "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${2}metadata" "$2" "$3"; }
|
||||
function psemver_setversion() { semver_setversion "$1" "${2}major" "${2}minor" "${2}patchlevel" "${2}prelease" "${2}metadata"; }
|
||||
function psemver_setprelease() { semver_setprelease "$1" "${2}major" "${2}minor" "${2}patchlevel" "${2}prelease" "${2}metadata"; }
|
||||
function psemver_compare_prelease() { semver_compare_prelease "${1}prelease" "${2}prelease"; }
|
||||
|
@ -240,3 +293,32 @@ function psemver_compare_metadata() { semver_compare_metadata "${1}metadata" "${
|
|||
function psemver_copy() { semver_copy "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${1}metadata" "${2}major" "${2}minor" "${2}patchlevel" "${2}prelease" "${2}metadata"; }
|
||||
function psemver_build() { semver_build "${1}major" "${1}minor" "${1}patchlevel" "${1}prelease" "${1}metadata"; }
|
||||
function psemver_setvar() { semver_setvar "$1" "${2}major" "${2}minor" "${2}patchlevel" "${2}prelease" "${2}metadata"; }
|
||||
|
||||
function psemver_setprmd() {
|
||||
local setprelease="$2" resetmetadata="$3" setmetadata="$4" addmetadata="$5"
|
||||
|
||||
psemver_setprelease "$setprelease" "$1" || return 2
|
||||
# XXX pas encore implémenté
|
||||
local setalpha setbeta setrc
|
||||
if [ -n "$setalpha" ]; then :
|
||||
elif [ -n "$setbeta" ]; then :
|
||||
elif [ -n "$setrc" ]; then :
|
||||
fi
|
||||
|
||||
[ -n "$resetmetadata" ] && psemver_setmetadata "" "$1"
|
||||
if [ -n "$setmetadata" ]; then
|
||||
psemver_setmetadata "$setmetadata" "$1" || return 3
|
||||
fi
|
||||
if [ -n "$addmetadata" ]; then
|
||||
psemver_addmetadata "$addmetadata" "$1" || return 4
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function psemver_incsetprmd() {
|
||||
local setprelease="$3" resetmetadata="$4" setmetadata="$5" addmetadata="$6" maven_update="$7"
|
||||
[ -n "$1" ] && "psemver_inc$1" "$2" "$maven_update" "$setprelease"
|
||||
shift
|
||||
psemver_setprmd "$@"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import expr as E
|
||||
import parser as P
|
||||
import yappsrt as Y
|
||||
from xpath.exceptions import *
|
||||
import xpath.exceptions
|
||||
import xpath.expr
|
||||
import xpath.parser
|
||||
import xpath.yappsrt
|
||||
|
||||
from exceptions import *
|
||||
__all__ = ['find', 'findnode', 'findvalue', 'XPathContext', 'XPath']
|
||||
__all__.extend((x for x in dir(xpath.exceptions) if not x.startswith('_')))
|
||||
|
||||
def api(f):
|
||||
"""Decorator for functions and methods that are part of the external
|
||||
|
@ -60,19 +63,19 @@ class XPathContext(object):
|
|||
|
||||
@api
|
||||
def find(self, expr, node, **kwargs):
|
||||
return XPath.get(expr).find(node, context=self, **kwargs)
|
||||
return xpath.find(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findnode(self, expr, node, **kwargs):
|
||||
return XPath.get(expr).findnode(node, context=self, **kwargs)
|
||||
return xpath.findnode(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalue(self, expr, node, **kwargs):
|
||||
return XPath.get(expr).findvalue(node, context=self, **kwargs)
|
||||
return xpath.findvalue(expr, node, context=self, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalues(self, expr, node, **kwargs):
|
||||
return XPath.get(expr).findvalues(node, context=self, **kwargs)
|
||||
return xpath.findvalues(expr, node, context=self, **kwargs)
|
||||
|
||||
class XPath():
|
||||
_max_cache = 100
|
||||
|
@ -82,9 +85,9 @@ class XPath():
|
|||
"""Init docs.
|
||||
"""
|
||||
try:
|
||||
parser = P.XPath(P.XPathScanner(str(expr)))
|
||||
parser = xpath.parser.XPath(xpath.parser.XPathScanner(str(expr)))
|
||||
self.expr = parser.XPath()
|
||||
except Y.SyntaxError, e:
|
||||
except xpath.yappsrt.SyntaxError, e:
|
||||
raise XPathParseError(str(expr), e.pos, e.msg)
|
||||
|
||||
@classmethod
|
||||
|
@ -112,7 +115,7 @@ class XPath():
|
|||
@api
|
||||
def findnode(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if not E.nodesetp(result):
|
||||
if not xpath.expr.nodesetp(result):
|
||||
raise XPathTypeError("expression is not a node-set")
|
||||
if len(result) == 0:
|
||||
return None
|
||||
|
@ -121,18 +124,18 @@ class XPath():
|
|||
@api
|
||||
def findvalue(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if E.nodesetp(result):
|
||||
if xpath.expr.nodesetp(result):
|
||||
if len(result) == 0:
|
||||
return None
|
||||
result = E.string(result)
|
||||
result = xpath.expr.string(result)
|
||||
return result
|
||||
|
||||
@api
|
||||
def findvalues(self, node, context=None, **kwargs):
|
||||
result = self.find(node, context, **kwargs)
|
||||
if not E.nodesetp(result):
|
||||
if not xpath.expr.nodesetp(result):
|
||||
raise XPathTypeError("expression is not a node-set")
|
||||
return [E.string_value(x) for x in result]
|
||||
return [xpath.expr.string_value(x) for x in result]
|
||||
|
||||
def __repr__(self):
|
||||
return '%s.%s(%s)' % (self.__class__.__module__,
|
||||
|
@ -141,3 +144,19 @@ class XPath():
|
|||
|
||||
def __str__(self):
|
||||
return str(self.expr)
|
||||
|
||||
@api
|
||||
def find(expr, node, **kwargs):
|
||||
return XPath.get(expr).find(node, **kwargs)
|
||||
|
||||
@api
|
||||
def findnode(expr, node, **kwargs):
|
||||
return XPath.get(expr).findnode(node, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalue(expr, node, **kwargs):
|
||||
return XPath.get(expr).findvalue(node, **kwargs)
|
||||
|
||||
@api
|
||||
def findvalues(expr, node, **kwargs):
|
||||
return XPath.get(expr).findvalues(node, **kwargs)
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
class XPathError(Exception):
|
||||
"""Base exception class used for all XPath exceptions."""
|
||||
|
||||
class XPathNotImplementedError(XPathError):
|
||||
"""Raised when an XPath expression contains a feature of XPath which
|
||||
has not been implemented.
|
||||
|
||||
"""
|
||||
|
||||
class XPathParseError(XPathError):
|
||||
"""Raised when an XPath expression could not be parsed."""
|
||||
|
||||
def __init__(self, expr, pos, message):
|
||||
XPathError.__init__(self)
|
||||
self.expr = expr
|
||||
self.pos = pos
|
||||
self.err = message
|
||||
|
||||
def __str__(self):
|
||||
return ("Syntax error:\n" +
|
||||
self.expr.replace("\n", " ") + "\n" +
|
||||
("-" * self.pos) + "^")
|
||||
|
||||
class XPathTypeError(XPathError):
|
||||
"""Raised when an XPath expression is found to contain a type error.
|
||||
For example, the expression "string()/node()" contains a type error
|
||||
because the "string()" function does not return a node-set.
|
||||
|
||||
"""
|
||||
|
||||
class XPathUnknownFunctionError(XPathError):
|
||||
"""Raised when an XPath expression contains a function that has no
|
||||
binding in the expression context.
|
||||
|
||||
"""
|
||||
|
||||
class XPathUnknownPrefixError(XPathError):
|
||||
"""Raised when an XPath expression contains a QName with a namespace
|
||||
prefix that has no corresponding namespace declaration in the expression
|
||||
context.
|
||||
|
||||
"""
|
||||
|
||||
class XPathUnknownVariableError(XPathError):
|
||||
"""Raised when an XPath expression contains a variable that has no
|
||||
binding in the expression context.
|
||||
|
||||
"""
|
|
@ -0,0 +1,903 @@
|
|||
from __future__ import division
|
||||
from itertools import *
|
||||
import math
|
||||
import operator
|
||||
import re
|
||||
import xml.dom
|
||||
import weakref
|
||||
|
||||
from xpath.exceptions import *
|
||||
import xpath
|
||||
|
||||
|
||||
#
|
||||
# Data model functions.
|
||||
#
|
||||
|
||||
def string_value(node):
|
||||
"""Compute the string-value of a node."""
|
||||
if (node.nodeType == node.DOCUMENT_NODE or
|
||||
node.nodeType == node.ELEMENT_NODE):
|
||||
s = u''
|
||||
for n in axes['descendant'](node):
|
||||
if n.nodeType == n.TEXT_NODE:
|
||||
s += n.data
|
||||
elif n.nodeType == n.CDATA_SECTION_NODE:
|
||||
s += n.nodeValue
|
||||
return s
|
||||
|
||||
elif node.nodeType == node.ATTRIBUTE_NODE:
|
||||
return node.value
|
||||
|
||||
elif (node.nodeType == node.PROCESSING_INSTRUCTION_NODE or
|
||||
node.nodeType == node.COMMENT_NODE or
|
||||
node.nodeType == node.TEXT_NODE):
|
||||
return node.data
|
||||
|
||||
elif node.nodeType == node.CDATA_SECTION_NODE:
|
||||
return node.nodeValue
|
||||
|
||||
def document_order(node):
|
||||
"""Compute a document order value for the node.
|
||||
|
||||
cmp(document_order(a), document_order(b)) will return -1, 0, or 1 if
|
||||
a is before, identical to, or after b in the document respectively.
|
||||
|
||||
We represent document order as a list of sibling indexes. That is,
|
||||
the third child of the document node has an order of [2]. The first
|
||||
child of that node has an order of [2,0].
|
||||
|
||||
Attributes have a sibling index of -1 (coming before all children of
|
||||
their node) and are further ordered by name--e.g., [2,0,-1,'href'].
|
||||
|
||||
"""
|
||||
|
||||
# Attributes: parent-order + [-1, attribute-name]
|
||||
if node.nodeType == node.ATTRIBUTE_NODE:
|
||||
order = document_order(node.ownerElement)
|
||||
order.extend((-1, node.name))
|
||||
return order
|
||||
|
||||
# The document root (hopefully): []
|
||||
if node.parentNode is None:
|
||||
return []
|
||||
|
||||
# Determine which child this is of its parent.
|
||||
sibpos = 0
|
||||
sib = node
|
||||
while sib.previousSibling is not None:
|
||||
sibpos += 1
|
||||
sib = sib.previousSibling
|
||||
|
||||
# Order: parent-order + [sibling-position]
|
||||
order = document_order(node.parentNode)
|
||||
order.append(sibpos)
|
||||
return order
|
||||
|
||||
#
|
||||
# Type functions, operating on the various XPath types.
|
||||
#
|
||||
# Internally, we use the following representations:
|
||||
# nodeset - list of DOM tree nodes in document order
|
||||
# string - str or unicode
|
||||
# boolean - bool
|
||||
# number - int or float
|
||||
#
|
||||
|
||||
def nodeset(v):
|
||||
"""Convert a value to a nodeset."""
|
||||
if not nodesetp(v):
|
||||
raise XPathTypeError, "value is not a node-set"
|
||||
return v
|
||||
|
||||
def nodesetp(v):
|
||||
"""Return true iff 'v' is a node-set."""
|
||||
if isinstance(v, list):
|
||||
return True
|
||||
|
||||
def string(v):
|
||||
"""Convert a value to a string."""
|
||||
if nodesetp(v):
|
||||
if not v:
|
||||
return u''
|
||||
return string_value(v[0])
|
||||
elif numberp(v):
|
||||
if v == float('inf'):
|
||||
return u'Infinity'
|
||||
elif v == float('-inf'):
|
||||
return u'-Infinity'
|
||||
elif str(v) == 'nan':
|
||||
return u'NaN'
|
||||
elif int(v) == v and v <= 0xffffffff:
|
||||
v = int(v)
|
||||
return unicode(v)
|
||||
elif booleanp(v):
|
||||
return u'true' if v else u'false'
|
||||
return v
|
||||
|
||||
def stringp(v):
|
||||
"""Return true iff 'v' is a string."""
|
||||
return isinstance(v, basestring)
|
||||
|
||||
def boolean(v):
|
||||
"""Convert a value to a boolean."""
|
||||
if nodesetp(v):
|
||||
return len(v) > 0
|
||||
elif numberp(v):
|
||||
if v == 0 or v != v:
|
||||
return False
|
||||
return True
|
||||
elif stringp(v):
|
||||
return v != ''
|
||||
return v
|
||||
|
||||
def booleanp(v):
|
||||
"""Return true iff 'v' is a boolean."""
|
||||
return isinstance(v, bool)
|
||||
|
||||
def number(v):
|
||||
"""Convert a value to a number."""
|
||||
if nodesetp(v):
|
||||
v = string(v)
|
||||
try:
|
||||
return float(v)
|
||||
except ValueError:
|
||||
return float('NaN')
|
||||
|
||||
def numberp(v):
|
||||
"""Return true iff 'v' is a number."""
|
||||
return (not(isinstance(v, bool)) and
|
||||
(isinstance(v, int) or isinstance(v, float)))
|
||||
|
||||
class Expr(object):
|
||||
"""Abstract base class for XPath expressions."""
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
"""Evaluate the expression.
|
||||
|
||||
The context node, context position, and context size are passed as
|
||||
arguments.
|
||||
|
||||
Returns an XPath value: a nodeset, string, boolean, or number.
|
||||
|
||||
"""
|
||||
|
||||
class BinaryOperatorExpr(Expr):
|
||||
"""Base class for all binary operators."""
|
||||
|
||||
def __init__(self, op, left, right):
|
||||
self.op = op
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
# Subclasses either override evaluate() or implement operate().
|
||||
return self.operate(self.left.evaluate(node, pos, size, context),
|
||||
self.right.evaluate(node, pos, size, context))
|
||||
|
||||
def __str__(self):
|
||||
return '(%s %s %s)' % (self.left, self.op, self.right)
|
||||
|
||||
class AndExpr(BinaryOperatorExpr):
|
||||
"""<x> and <y>"""
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
# Note that XPath boolean operations short-circuit.
|
||||
return (boolean(self.left.evaluate(node, pos, size, context) and
|
||||
boolean(self.right.evaluate(node, pos, size, context))))
|
||||
|
||||
class OrExpr(BinaryOperatorExpr):
|
||||
"""<x> or <y>"""
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
# Note that XPath boolean operations short-circuit.
|
||||
return (boolean(self.left.evaluate(node, pos, size, context) or
|
||||
boolean(self.right.evaluate(node, pos, size, context))))
|
||||
|
||||
class EqualityExpr(BinaryOperatorExpr):
|
||||
"""<x> = <y>, <x> != <y>, etc."""
|
||||
|
||||
operators = {
|
||||
'=' : operator.eq,
|
||||
'!=' : operator.ne,
|
||||
'<=' : operator.le,
|
||||
'<' : operator.lt,
|
||||
'>=' : operator.ge,
|
||||
'>' : operator.gt,
|
||||
}
|
||||
|
||||
def operate(self, a, b):
|
||||
if nodesetp(a):
|
||||
for node in a:
|
||||
if self.operate(string_value(node), b):
|
||||
return True
|
||||
return False
|
||||
|
||||
if nodesetp(b):
|
||||
for node in b:
|
||||
if self.operate(a, string_value(node)):
|
||||
return True
|
||||
return False
|
||||
|
||||
if self.op in ('=', '!='):
|
||||
if booleanp(a) or booleanp(b):
|
||||
convert = boolean
|
||||
elif numberp(a) or numberp(b):
|
||||
convert = number
|
||||
else:
|
||||
convert = string
|
||||
else:
|
||||
convert = number
|
||||
|
||||
a, b = convert(a), convert(b)
|
||||
return self.operators[self.op](a, b)
|
||||
|
||||
def divop(x, y):
|
||||
try:
|
||||
return x / y
|
||||
except ZeroDivisionError:
|
||||
if x == 0 and y == 0:
|
||||
return float('nan')
|
||||
if x < 0:
|
||||
return float('-inf')
|
||||
return float('inf')
|
||||
|
||||
class ArithmeticalExpr(BinaryOperatorExpr):
|
||||
"""<x> + <y>, <x> - <y>, etc."""
|
||||
|
||||
# Note that we must use math.fmod for the correct modulo semantics.
|
||||
operators = {
|
||||
'+' : operator.add,
|
||||
'-' : operator.sub,
|
||||
'*' : operator.mul,
|
||||
'div' : divop,
|
||||
'mod' : math.fmod
|
||||
}
|
||||
|
||||
def operate(self, a, b):
|
||||
return self.operators[self.op](number(a), number(b))
|
||||
|
||||
class UnionExpr(BinaryOperatorExpr):
|
||||
"""<x> | <y>"""
|
||||
|
||||
def operate(self, a, b):
|
||||
if not nodesetp(a) or not nodesetp(b):
|
||||
raise XPathTypeError("union operand is not a node-set")
|
||||
|
||||
# Need to sort the result to preserve document order.
|
||||
return sorted(set(chain(a, b)), key=document_order)
|
||||
|
||||
class NegationExpr(Expr):
|
||||
"""- <x>"""
|
||||
|
||||
def __init__(self, expr):
|
||||
self.expr = expr
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
return -number(self.expr.evaluate(node, pos, size, context))
|
||||
|
||||
def __str__(self):
|
||||
return '(-%s)' % self.expr
|
||||
|
||||
class LiteralExpr(Expr):
|
||||
"""Literals--either numbers or strings."""
|
||||
|
||||
def __init__(self, literal):
|
||||
self.literal = literal
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
return self.literal
|
||||
|
||||
def __str__(self):
|
||||
if stringp(self.literal):
|
||||
if "'" in self.literal:
|
||||
return '"%s"' % self.literal
|
||||
else:
|
||||
return "'%s'" % self.literal
|
||||
return string(self.literal)
|
||||
|
||||
class VariableReference(Expr):
|
||||
"""Variable references."""
|
||||
|
||||
def __init__(self, prefix, name):
|
||||
self.prefix = prefix
|
||||
self.name = name
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
try:
|
||||
if self.prefix is not None:
|
||||
try:
|
||||
namespaceURI = context.namespaces[self.prefix]
|
||||
except KeyError:
|
||||
raise XPathUnknownPrefixError(self.prefix)
|
||||
return context.variables[(namespaceURI, self.name)]
|
||||
else:
|
||||
return context.variables[self.name]
|
||||
except KeyError:
|
||||
raise XPathUnknownVariableError(str(self))
|
||||
|
||||
def __str__(self):
|
||||
if self.prefix is None:
|
||||
return '$%s' % self.name
|
||||
else:
|
||||
return '$%s:%s' % (self.prefix, self.name)
|
||||
|
||||
class Function(Expr):
|
||||
"""Functions."""
|
||||
|
||||
def __init__(self, name, args):
|
||||
self.name = name
|
||||
self.args = args
|
||||
self.evaluate = getattr(self, 'f_%s' % name.replace('-', '_'), None)
|
||||
if self.evaluate is None:
|
||||
raise XPathUnknownFunctionError, 'unknown function "%s()"' % name
|
||||
|
||||
if len(self.args) < self.evaluate.minargs:
|
||||
raise XPathTypeError, 'too few arguments for "%s()"' % name
|
||||
if (self.evaluate.maxargs is not None and
|
||||
len(self.args) > self.evaluate.maxargs):
|
||||
raise XPathTypeError, 'too many arguments for "%s()"' % name
|
||||
|
||||
#
|
||||
# XPath functions are implemented by methods of the Function class.
|
||||
#
|
||||
# A method implementing an XPath function is decorated with the function
|
||||
# decorator, and receives the evaluated function arguments as positional
|
||||
# parameters.
|
||||
#
|
||||
|
||||
def function(minargs, maxargs, implicit=False, first=False, convert=None):
|
||||
"""Function decorator.
|
||||
|
||||
minargs -- Minimum number of arguments taken by the function.
|
||||
maxargs -- Maximum number of arguments taken by the function.
|
||||
implicit -- True for functions which operate on a nodeset consisting
|
||||
of the current context node when passed no argument.
|
||||
(e.g., string() and number().)
|
||||
convert -- When non-None, a function used to filter function arguments.
|
||||
"""
|
||||
def decorator(f):
|
||||
def new_f(self, node, pos, size, context):
|
||||
if implicit and len(self.args) == 0:
|
||||
args = [[node]]
|
||||
else:
|
||||
args = [x.evaluate(node, pos, size, context)
|
||||
for x in self.args]
|
||||
if first:
|
||||
args[0] = nodeset(args[0])
|
||||
if len(args[0]) > 0:
|
||||
args[0] = args[0][0]
|
||||
else:
|
||||
args[0] = None
|
||||
if convert is not None:
|
||||
args = [convert(x) for x in args]
|
||||
return f(self, node, pos, size, context, *args)
|
||||
|
||||
new_f.minargs = minargs
|
||||
new_f.maxargs = maxargs
|
||||
new_f.__name__ = f.__name__
|
||||
new_f.__doc__ = f.__doc__
|
||||
return new_f
|
||||
return decorator
|
||||
|
||||
# Node Set Functions
|
||||
|
||||
@function(0, 0)
|
||||
def f_last(self, node, pos, size, context):
|
||||
return size
|
||||
|
||||
@function(0, 0)
|
||||
def f_position(self, node, pos, size, context):
|
||||
return pos
|
||||
|
||||
@function(1, 1, convert=nodeset)
|
||||
def f_count(self, node, pos, size, context, nodes):
|
||||
return len(nodes)
|
||||
|
||||
@function(1, 1)
|
||||
def f_id(self, node, pos, size, context, arg):
|
||||
if nodesetp(arg):
|
||||
ids = (string_value(x) for x in arg)
|
||||
else:
|
||||
ids = [string(arg)]
|
||||
if node.nodeType != node.DOCUMENT_NODE:
|
||||
node = node.ownerDocument
|
||||
return list(filter(None, (node.getElementById(id) for id in ids)))
|
||||
|
||||
@function(0, 1, implicit=True, first=True)
|
||||
def f_local_name(self, node, pos, size, context, argnode):
|
||||
if argnode is None:
|
||||
return ''
|
||||
if (argnode.nodeType == argnode.ELEMENT_NODE or
|
||||
argnode.nodeType == argnode.ATTRIBUTE_NODE):
|
||||
return argnode.localName
|
||||
elif argnode.nodeType == argnode.PROCESSING_INSTRUCTION_NODE:
|
||||
return argnode.target
|
||||
return ''
|
||||
|
||||
@function(0, 1, implicit=True, first=True)
|
||||
def f_namespace_uri(self, node, pos, size, context, argnode):
|
||||
if argnode is None:
|
||||
return ''
|
||||
return argnode.namespaceURI
|
||||
|
||||
@function(0, 1, implicit=True, first=True)
|
||||
def f_name(self, node, pos, size, context, argnode):
|
||||
if argnode is None:
|
||||
return ''
|
||||
if argnode.nodeType == argnode.ELEMENT_NODE:
|
||||
return argnode.tagName
|
||||
elif argnode.nodeType == argnode.ATTRIBUTE_NODE:
|
||||
return argnode.name
|
||||
elif argnode.nodeType == argnode.PROCESSING_INSTRUCTION_NODE:
|
||||
return argnode.target
|
||||
return ''
|
||||
|
||||
# String Functions
|
||||
|
||||
@function(0, 1, implicit=True, convert=string)
|
||||
def f_string(self, node, pos, size, context, arg):
|
||||
return arg
|
||||
|
||||
@function(2, None, convert=string)
|
||||
def f_concat(self, node, pos, size, context, *args):
|
||||
return ''.join((x for x in args))
|
||||
|
||||
@function(2, 2, convert=string)
|
||||
def f_starts_with(self, node, pos, size, context, a, b):
|
||||
return a.startswith(b)
|
||||
|
||||
@function(2, 2, convert=string)
|
||||
def f_contains(self, node, pos, size, context, a, b):
|
||||
return b in a
|
||||
|
||||
@function(2, 2, convert=string)
|
||||
def f_substring_before(self, node, pos, size, context, a, b):
|
||||
try:
|
||||
return a[0:a.index(b)]
|
||||
except ValueError:
|
||||
return ''
|
||||
|
||||
@function(2, 2, convert=string)
|
||||
def f_substring_after(self, node, pos, size, context, a, b):
|
||||
try:
|
||||
return a[a.index(b)+len(b):]
|
||||
except ValueError:
|
||||
return ''
|
||||
|
||||
@function(2, 3)
|
||||
def f_substring(self, node, pos, size, context, s, start, count=None):
|
||||
s = string(s)
|
||||
start = round(number(start))
|
||||
if start != start:
|
||||
# Catch NaN
|
||||
return ''
|
||||
|
||||
if count is None:
|
||||
end = len(s) + 1
|
||||
else:
|
||||
end = start + round(number(count))
|
||||
if end != end:
|
||||
# Catch NaN
|
||||
return ''
|
||||
if end > len(s):
|
||||
end = len(s)+1
|
||||
|
||||
if start < 1:
|
||||
start = 1
|
||||
if start > len(s):
|
||||
return ''
|
||||
if end <= start:
|
||||
return ''
|
||||
return s[int(start)-1:int(end)-1]
|
||||
|
||||
@function(0, 1, implicit=True, convert=string)
|
||||
def f_string_length(self, node, pos, size, context, s):
|
||||
return len(s)
|
||||
|
||||
@function(0, 1, implicit=True, convert=string)
|
||||
def f_normalize_space(self, node, pos, size, context, s):
|
||||
return re.sub(r'\s+', ' ', s.strip())
|
||||
|
||||
@function(3, 3, convert=lambda x: unicode(string(x)))
|
||||
def f_translate(self, node, pos, size, context, s, source, target):
|
||||
# str.translate() and unicode.translate() are completely different.
|
||||
# The translate() arguments are coerced to unicode.
|
||||
table = {}
|
||||
for schar, tchar in izip(source, target):
|
||||
schar = ord(schar)
|
||||
if schar not in table:
|
||||
table[schar] = tchar
|
||||
if len(source) > len(target):
|
||||
for schar in source[len(target):]:
|
||||
schar = ord(schar)
|
||||
if schar not in table:
|
||||
table[schar] = None
|
||||
return s.translate(table)
|
||||
|
||||
# Boolean functions
|
||||
|
||||
@function(1, 1, convert=boolean)
|
||||
def f_boolean(self, node, pos, size, context, b):
|
||||
return b
|
||||
|
||||
@function(1, 1, convert=boolean)
|
||||
def f_not(self, node, pos, size, context, b):
|
||||
return not b
|
||||
|
||||
@function(0, 0)
|
||||
def f_true(self, node, pos, size, context):
|
||||
return True
|
||||
|
||||
@function(0, 0)
|
||||
def f_false(self, node, pos, size, context):
|
||||
return False
|
||||
|
||||
@function(1, 1, convert=string)
|
||||
def f_lang(self, node, pos, size, context, s):
|
||||
s = s.lower()
|
||||
for n in axes['ancestor-or-self'](node):
|
||||
if n.nodeType == n.ELEMENT_NODE and n.hasAttribute('xml:lang'):
|
||||
lang = n.getAttribute('xml:lang').lower()
|
||||
if s == lang or lang.startswith(s + u'-'):
|
||||
return True
|
||||
break
|
||||
return False
|
||||
|
||||
# Number functions
|
||||
|
||||
@function(0, 1, implicit=True, convert=number)
|
||||
def f_number(self, node, pos, size, context, n):
|
||||
return n
|
||||
|
||||
@function(1, 1, convert=nodeset)
|
||||
def f_sum(self, node, pos, size, context, nodes):
|
||||
return sum((number(string_value(x)) for x in nodes))
|
||||
|
||||
@function(1, 1, convert=number)
|
||||
def f_floor(self, node, pos, size, context, n):
|
||||
return math.floor(n)
|
||||
|
||||
@function(1, 1, convert=number)
|
||||
def f_ceiling(self, node, pos, size, context, n):
|
||||
return math.ceil(n)
|
||||
|
||||
@function(1, 1, convert=number)
|
||||
def f_round(self, node, pos, size, context, n):
|
||||
# XXX round(-0.0) should be -0.0, not 0.0.
|
||||
# XXX round(-1.5) should be -1.0, not -2.0.
|
||||
return round(n)
|
||||
|
||||
def __str__(self):
|
||||
return '%s(%s)' % (self.name, ', '.join((str(x) for x in self.args)))
|
||||
|
||||
#
|
||||
# XPath axes.
|
||||
#
|
||||
|
||||
# Dictionary of all axis functions.
|
||||
axes = {}
|
||||
|
||||
def axisfn(reverse=False, principal_node_type=xml.dom.Node.ELEMENT_NODE):
|
||||
"""Axis function decorator.
|
||||
|
||||
An axis function will take a node as an argument and return a sequence
|
||||
over the nodes along an XPath axis. Axis functions have two extra
|
||||
attributes indicating the axis direction and principal node type.
|
||||
"""
|
||||
def decorate(f):
|
||||
f.__name__ = f.__name__.replace('_', '-')
|
||||
f.reverse = reverse
|
||||
f.principal_node_type = principal_node_type
|
||||
return f
|
||||
return decorate
|
||||
|
||||
def make_axes():
|
||||
"""Define functions to walk each of the possible XPath axes."""
|
||||
|
||||
@axisfn()
|
||||
def child(node):
|
||||
return node.childNodes
|
||||
|
||||
@axisfn()
|
||||
def descendant(node):
|
||||
for child in node.childNodes:
|
||||
for node in descendant_or_self(child):
|
||||
yield node
|
||||
|
||||
@axisfn()
|
||||
def parent(node):
|
||||
if node.parentNode is not None:
|
||||
yield node.parentNode
|
||||
|
||||
@axisfn(reverse=True)
|
||||
def ancestor(node):
|
||||
while node.parentNode is not None:
|
||||
node = node.parentNode
|
||||
yield node
|
||||
|
||||
@axisfn()
|
||||
def following_sibling(node):
|
||||
while node.nextSibling is not None:
|
||||
node = node.nextSibling
|
||||
yield node
|
||||
|
||||
@axisfn(reverse=True)
|
||||
def preceding_sibling(node):
|
||||
while node.previousSibling is not None:
|
||||
node = node.previousSibling
|
||||
yield node
|
||||
|
||||
@axisfn()
|
||||
def following(node):
|
||||
while node is not None:
|
||||
while node.nextSibling is not None:
|
||||
node = node.nextSibling
|
||||
for n in descendant_or_self(node):
|
||||
yield n
|
||||
node = node.parentNode
|
||||
|
||||
@axisfn(reverse=True)
|
||||
def preceding(node):
|
||||
while node is not None:
|
||||
while node.previousSibling is not None:
|
||||
node = node.previousSibling
|
||||
# Could be more efficient here.
|
||||
for n in reversed(list(descendant_or_self(node))):
|
||||
yield n
|
||||
node = node.parentNode
|
||||
|
||||
@axisfn(principal_node_type=xml.dom.Node.ATTRIBUTE_NODE)
|
||||
def attribute(node):
|
||||
if node.attributes is not None:
|
||||
return (node.attributes.item(i)
|
||||
for i in xrange(node.attributes.length))
|
||||
return ()
|
||||
|
||||
@axisfn()
|
||||
def namespace(node):
|
||||
raise XPathNotImplementedError("namespace axis is not implemented")
|
||||
|
||||
@axisfn()
|
||||
def self(node):
|
||||
yield node
|
||||
|
||||
@axisfn()
|
||||
def descendant_or_self(node):
|
||||
yield node
|
||||
for child in node.childNodes:
|
||||
for node in descendant_or_self(child):
|
||||
yield node
|
||||
|
||||
@axisfn(reverse=True)
|
||||
def ancestor_or_self(node):
|
||||
return chain([node], ancestor(node))
|
||||
|
||||
# Place each axis function defined here into the 'axes' dict.
|
||||
for axis in locals().values():
|
||||
axes[axis.__name__] = axis
|
||||
|
||||
make_axes()
|
||||
|
||||
def merge_into_nodeset(target, source):
|
||||
"""Place all the nodes from the source node-set into the target
|
||||
node-set, preserving document order. Both node-sets must be in
|
||||
document order to begin with.
|
||||
|
||||
"""
|
||||
if len(target) == 0:
|
||||
target.extend(source)
|
||||
return
|
||||
|
||||
source = [n for n in source if n not in target]
|
||||
if len(source) == 0:
|
||||
return
|
||||
|
||||
# If the last node in the target set comes before the first node in the
|
||||
# source set, then we can just concatenate the sets. Otherwise, we
|
||||
# will need to sort. (We could also check to see if the last node in
|
||||
# the source set comes before the first node in the target set, but this
|
||||
# situation is very unlikely in practice.)
|
||||
if document_order(target[-1]) < document_order(source[0]):
|
||||
target.extend(source)
|
||||
else:
|
||||
target.extend(source)
|
||||
target.sort(key=document_order)
|
||||
|
||||
class AbsolutePathExpr(Expr):
|
||||
"""Absolute location paths."""
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
if node.nodeType != node.DOCUMENT_NODE:
|
||||
node = node.ownerDocument
|
||||
if self.path is None:
|
||||
return [node]
|
||||
return self.path.evaluate(node, 1, 1, context)
|
||||
|
||||
def __str__(self):
|
||||
return '/%s' % (self.path or '')
|
||||
|
||||
class PathExpr(Expr):
|
||||
"""Location path expressions."""
|
||||
|
||||
def __init__(self, steps):
|
||||
self.steps = steps
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
# The first step in the path is evaluated in the current context.
|
||||
# If this is the only step in the path, the return value is
|
||||
# unimportant. If there are other steps, however, it must be a
|
||||
# node-set.
|
||||
result = self.steps[0].evaluate(node, pos, size, context)
|
||||
if len(self.steps) > 1 and not nodesetp(result):
|
||||
raise XPathTypeError("path step is not a node-set")
|
||||
|
||||
# Subsequent steps are evaluated for each node in the node-set
|
||||
# resulting from the previous step.
|
||||
for step in self.steps[1:]:
|
||||
aggregate = []
|
||||
for i in xrange(len(result)):
|
||||
nodes = step.evaluate(result[i], i+1, len(result), context)
|
||||
if not nodesetp(nodes):
|
||||
raise XPathTypeError("path step is not a node-set")
|
||||
merge_into_nodeset(aggregate, nodes)
|
||||
result = aggregate
|
||||
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
return '/'.join((str(s) for s in self.steps))
|
||||
|
||||
class PredicateList(Expr):
|
||||
"""A list of predicates.
|
||||
|
||||
Predicates are handled as an expression wrapping the expression
|
||||
filtered by the predicates.
|
||||
|
||||
"""
|
||||
def __init__(self, expr, predicates, axis='child'):
|
||||
self.predicates = predicates
|
||||
self.expr = expr
|
||||
self.axis = axes[axis]
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
result = self.expr.evaluate(node, pos, size, context)
|
||||
if not nodesetp(result):
|
||||
raise XPathTypeError("predicate input is not a node-set")
|
||||
|
||||
if self.axis.reverse:
|
||||
result.reverse()
|
||||
|
||||
for pred in self.predicates:
|
||||
match = []
|
||||
for i, node in izip(count(1), result):
|
||||
r = pred.evaluate(node, i, len(result), context)
|
||||
|
||||
# If a predicate evaluates to a number, select the node
|
||||
# with that position. Otherwise, select nodes for which
|
||||
# the boolean value of the predicate is true.
|
||||
if numberp(r):
|
||||
if r == i:
|
||||
match.append(node)
|
||||
elif boolean(r):
|
||||
match.append(node)
|
||||
result = match
|
||||
|
||||
if self.axis.reverse:
|
||||
result.reverse()
|
||||
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
s = str(self.expr)
|
||||
if '/' in s:
|
||||
s = '(%s)' % s
|
||||
return s + ''.join(('[%s]' % x for x in self.predicates))
|
||||
|
||||
class AxisStep(Expr):
|
||||
"""One step in a location path expression."""
|
||||
|
||||
def __init__(self, axis, test=None, predicates=None):
|
||||
if test is None:
|
||||
test = AnyKindTest()
|
||||
self.axis = axes[axis]
|
||||
self.test = test
|
||||
|
||||
def evaluate(self, node, pos, size, context):
|
||||
match = []
|
||||
for n in self.axis(node):
|
||||
if self.test.match(n, self.axis, context):
|
||||
match.append(n)
|
||||
|
||||
if self.axis.reverse:
|
||||
match.reverse()
|
||||
|
||||
return match
|
||||
|
||||
def __str__(self):
|
||||
return '%s::%s' % (self.axis.__name__, self.test)
|
||||
|
||||
#
|
||||
# Node tests.
|
||||
#
|
||||
|
||||
class Test(object):
|
||||
"""Abstract base class for node tests."""
|
||||
|
||||
def match(self, node, axis, context):
|
||||
"""Return True if 'node' matches the test along 'axis'."""
|
||||
|
||||
class NameTest(object):
|
||||
def __init__(self, prefix, localpart):
|
||||
self.prefix = prefix
|
||||
self.localName = localpart
|
||||
if self.prefix == None and self.localName == '*':
|
||||
self.prefix = '*'
|
||||
|
||||
def match(self, node, axis, context):
|
||||
if node.nodeType != axis.principal_node_type:
|
||||
return False
|
||||
|
||||
if self.prefix != '*':
|
||||
namespaceURI = None
|
||||
if self.prefix is not None:
|
||||
try:
|
||||
namespaceURI = context.namespaces[self.prefix]
|
||||
except KeyError:
|
||||
raise XPathUnknownPrefixError(self.prefix)
|
||||
elif axis.principal_node_type == node.ELEMENT_NODE:
|
||||
namespaceURI = context.default_namespace
|
||||
if namespaceURI != node.namespaceURI:
|
||||
return False
|
||||
if self.localName != '*':
|
||||
if self.localName != node.localName:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
if self.prefix is not None:
|
||||
return '%s:%s' % (self.prefix, self.localName)
|
||||
else:
|
||||
return self.localName
|
||||
|
||||
class PITest(object):
|
||||
def __init__(self, name=None):
|
||||
self.name = name
|
||||
|
||||
def match(self, node, axis, context):
|
||||
return (node.nodeType == node.PROCESSING_INSTRUCTION_NODE and
|
||||
(self.name is None or node.target == self.name))
|
||||
|
||||
def __str__(self):
|
||||
if self.name is None:
|
||||
name = ''
|
||||
elif "'" in self.name:
|
||||
name = '"%s"' % self.name
|
||||
else:
|
||||
name = "'%s'" % self.name
|
||||
return 'processing-instruction(%s)' % name
|
||||
|
||||
class CommentTest(object):
|
||||
def match(self, node, axis, context):
|
||||
return node.nodeType == node.COMMENT_NODE
|
||||
|
||||
def __str__(self):
|
||||
return 'comment()'
|
||||
|
||||
class TextTest(object):
|
||||
def match(self, node, axis, context):
|
||||
return (node.nodeType == node.TEXT_NODE or
|
||||
node.nodeType == node.CDATA_SECTION_NODE)
|
||||
|
||||
def __str__(self):
|
||||
return 'text()'
|
||||
|
||||
class AnyKindTest(object):
|
||||
def match(self, node, axis, context):
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
return 'node()'
|
|
@ -0,0 +1,416 @@
|
|||
import xpath.expr as X
|
||||
from xpath.yappsrt import *
|
||||
|
||||
|
||||
from string import *
|
||||
import re
|
||||
|
||||
class XPathScanner(Scanner):
|
||||
patterns = [
|
||||
("r'\\:'", re.compile('\\:')),
|
||||
("r'node\\s*\\('", re.compile('node\\s*\\(')),
|
||||
("r'text\\s*\\('", re.compile('text\\s*\\(')),
|
||||
("r'comment\\s*\\('", re.compile('comment\\s*\\(')),
|
||||
("r'processing-instruction\\s*\\('", re.compile('processing-instruction\\s*\\(')),
|
||||
("r'\\,'", re.compile('\\,')),
|
||||
("r'\\.'", re.compile('\\.')),
|
||||
("r'\\$'", re.compile('\\$')),
|
||||
("r'\\)'", re.compile('\\)')),
|
||||
("r'\\('", re.compile('\\(')),
|
||||
("r'\\]'", re.compile('\\]')),
|
||||
("r'\\['", re.compile('\\[')),
|
||||
("r'\\*'", re.compile('\\*')),
|
||||
("r':'", re.compile(':')),
|
||||
("r'\\.\\.'", re.compile('\\.\\.')),
|
||||
("r'@'", re.compile('@')),
|
||||
("r'::'", re.compile('::')),
|
||||
("r'\\/\\/'", re.compile('\\/\\/')),
|
||||
("r'\\/'", re.compile('\\/')),
|
||||
("r'\\-'", re.compile('\\-')),
|
||||
("'\\|'", re.compile('\\|')),
|
||||
("r'and'", re.compile('and')),
|
||||
("r'or'", re.compile('or')),
|
||||
('\\s+', re.compile('\\s+')),
|
||||
('END', re.compile('$')),
|
||||
('FORWARD_AXIS_NAME', re.compile('child|descendant-or-self|attribute|self|descendant|following-sibling|following|namespace')),
|
||||
('REVERSE_AXIS_NAME', re.compile('parent|preceding-sibling|preceding|ancestor-or-self|ancestor')),
|
||||
('NCNAME', re.compile('[a-zA-Z_][a-zA-Z0-9_\\-\\.\\w]*(?!\\()')),
|
||||
('FUNCNAME', re.compile('[a-zA-Z_][a-zA-Z0-9_\\-\\.\\w]*')),
|
||||
('DQUOTE', re.compile('\\"(?:[^\\"])*\\"')),
|
||||
('SQUOTE', re.compile("\\'(?:[^\\'])*\\'")),
|
||||
('NUMBER', re.compile('((\\.[0-9]+)|([0-9]+(\\.[0-9]*)?))([eE][\\+\\-]?[0-9]+)?')),
|
||||
('EQ_COMP', re.compile('\\!?\\=')),
|
||||
('REL_COMP', re.compile('[\\<\\>]\\=?')),
|
||||
('ADD_COMP', re.compile('[\\+\\-]')),
|
||||
('MUL_COMP', re.compile('\\*|div|mod')),
|
||||
]
|
||||
def __init__(self, str):
|
||||
Scanner.__init__(self,None,['\\s+'],str)
|
||||
|
||||
class XPath(Parser):
|
||||
def XPath(self):
|
||||
Expr = self.Expr()
|
||||
END = self._scan('END')
|
||||
return Expr
|
||||
|
||||
def Expr(self):
|
||||
OrExpr = self.OrExpr()
|
||||
return OrExpr
|
||||
|
||||
def OrExpr(self):
|
||||
AndExpr = self.AndExpr()
|
||||
Expr = AndExpr
|
||||
while self._peek("r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'or'":
|
||||
self._scan("r'or'")
|
||||
AndExpr = self.AndExpr()
|
||||
Expr = X.OrExpr('or', Expr, AndExpr)
|
||||
return Expr
|
||||
|
||||
def AndExpr(self):
|
||||
EqualityExpr = self.EqualityExpr()
|
||||
Expr = EqualityExpr
|
||||
while self._peek("r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'and'":
|
||||
self._scan("r'and'")
|
||||
EqualityExpr = self.EqualityExpr()
|
||||
Expr = X.AndExpr('and', Expr, EqualityExpr)
|
||||
return Expr
|
||||
|
||||
def EqualityExpr(self):
|
||||
RelationalExpr = self.RelationalExpr()
|
||||
Expr = RelationalExpr
|
||||
while self._peek('EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == 'EQ_COMP':
|
||||
EQ_COMP = self._scan('EQ_COMP')
|
||||
RelationalExpr = self.RelationalExpr()
|
||||
Expr = X.EqualityExpr(EQ_COMP, Expr, RelationalExpr)
|
||||
return Expr
|
||||
|
||||
def RelationalExpr(self):
|
||||
AdditiveExpr = self.AdditiveExpr()
|
||||
Expr = AdditiveExpr
|
||||
while self._peek('REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == 'REL_COMP':
|
||||
REL_COMP = self._scan('REL_COMP')
|
||||
AdditiveExpr = self.AdditiveExpr()
|
||||
Expr = X.EqualityExpr(REL_COMP, Expr, AdditiveExpr)
|
||||
return Expr
|
||||
|
||||
def AdditiveExpr(self):
|
||||
MultiplicativeExpr = self.MultiplicativeExpr()
|
||||
Expr = MultiplicativeExpr
|
||||
while self._peek('ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == 'ADD_COMP':
|
||||
ADD_COMP = self._scan('ADD_COMP')
|
||||
MultiplicativeExpr = self.MultiplicativeExpr()
|
||||
Expr = X.ArithmeticalExpr(ADD_COMP, Expr, MultiplicativeExpr)
|
||||
return Expr
|
||||
|
||||
def MultiplicativeExpr(self):
|
||||
UnionExpr = self.UnionExpr()
|
||||
Expr = UnionExpr
|
||||
while self._peek('MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == 'MUL_COMP':
|
||||
MUL_COMP = self._scan('MUL_COMP')
|
||||
UnionExpr = self.UnionExpr()
|
||||
Expr = X.ArithmeticalExpr(MUL_COMP, Expr, UnionExpr)
|
||||
return Expr
|
||||
|
||||
def UnionExpr(self):
|
||||
UnaryExpr = self.UnaryExpr()
|
||||
Expr = UnaryExpr
|
||||
while self._peek("'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "'\\|'":
|
||||
self._scan("'\\|'")
|
||||
UnaryExpr = self.UnaryExpr()
|
||||
Expr = X.UnionExpr('|', Expr, UnaryExpr)
|
||||
return Expr
|
||||
|
||||
def UnaryExpr(self):
|
||||
_token_ = self._peek("r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == "r'\\-'":
|
||||
self._scan("r'\\-'")
|
||||
ValueExpr = self.ValueExpr()
|
||||
return X.NegationExpr(ValueExpr)
|
||||
else:
|
||||
ValueExpr = self.ValueExpr()
|
||||
return ValueExpr
|
||||
|
||||
def ValueExpr(self):
|
||||
PathExpr = self.PathExpr()
|
||||
return PathExpr
|
||||
|
||||
def PathExpr(self):
|
||||
_token_ = self._peek("r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == "r'\\/'":
|
||||
self._scan("r'\\/'")
|
||||
path = None
|
||||
if self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME', "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") not in ["'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'"]:
|
||||
RelativePathExpr = self.RelativePathExpr()
|
||||
path = RelativePathExpr
|
||||
return X.AbsolutePathExpr(path)
|
||||
elif _token_ == "r'\\/\\/'":
|
||||
self._scan("r'\\/\\/'")
|
||||
RelativePathExpr = self.RelativePathExpr()
|
||||
step = X.AxisStep('descendant-or-self')
|
||||
RelativePathExpr.steps.insert(0, step)
|
||||
return X.AbsolutePathExpr(RelativePathExpr)
|
||||
else:
|
||||
RelativePathExpr = self.RelativePathExpr()
|
||||
return RelativePathExpr
|
||||
|
||||
def RelativePathExpr(self):
|
||||
StepExpr = self.StepExpr()
|
||||
steps = [StepExpr]
|
||||
while self._peek("r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") in ["r'\\/'", "r'\\/\\/'"]:
|
||||
_token_ = self._peek("r'\\/'", "r'\\/\\/'")
|
||||
if _token_ == "r'\\/'":
|
||||
self._scan("r'\\/'")
|
||||
else:# == "r'\\/\\/'"
|
||||
self._scan("r'\\/\\/'")
|
||||
steps.append(X.AxisStep('descendant-or-self'))
|
||||
StepExpr = self.StepExpr()
|
||||
steps.append(StepExpr)
|
||||
return X.PathExpr(steps)
|
||||
|
||||
def StepExpr(self):
|
||||
_token_ = self._peek("r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ["r'\\('", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE']:
|
||||
AxisStep = self.AxisStep()
|
||||
return AxisStep
|
||||
else:
|
||||
FilterExpr = self.FilterExpr()
|
||||
return FilterExpr
|
||||
|
||||
def AxisStep(self):
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ['REVERSE_AXIS_NAME', "r'\\.\\.'"]:
|
||||
ForwardStep = self.ForwardStep()
|
||||
step = ForwardStep
|
||||
else:# in ['REVERSE_AXIS_NAME', "r'\\.\\.'"]
|
||||
ReverseStep = self.ReverseStep()
|
||||
step = ReverseStep
|
||||
expr = X.AxisStep(*step)
|
||||
if self._peek("r'\\['", "r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'\\['":
|
||||
PredicateList = self.PredicateList()
|
||||
expr = X.PredicateList(expr, PredicateList, step[0])
|
||||
return expr
|
||||
|
||||
def ForwardStep(self):
|
||||
_token_ = self._peek('FORWARD_AXIS_NAME', "r'@'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ == 'FORWARD_AXIS_NAME':
|
||||
ForwardAxis = self.ForwardAxis()
|
||||
NodeTest = self.NodeTest()
|
||||
return [ForwardAxis, NodeTest]
|
||||
else:
|
||||
AbbrevForwardStep = self.AbbrevForwardStep()
|
||||
return AbbrevForwardStep
|
||||
|
||||
def ForwardAxis(self):
|
||||
FORWARD_AXIS_NAME = self._scan('FORWARD_AXIS_NAME')
|
||||
self._scan("r'::'")
|
||||
return FORWARD_AXIS_NAME
|
||||
|
||||
def AbbrevForwardStep(self):
|
||||
axis = 'child'
|
||||
if self._peek("r'@'", "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME') == "r'@'":
|
||||
self._scan("r'@'")
|
||||
axis = 'attribute'
|
||||
NodeTest = self.NodeTest()
|
||||
return [axis, NodeTest]
|
||||
|
||||
def ReverseStep(self):
|
||||
_token_ = self._peek('REVERSE_AXIS_NAME', "r'\\.\\.'")
|
||||
if _token_ == 'REVERSE_AXIS_NAME':
|
||||
ReverseAxis = self.ReverseAxis()
|
||||
NodeTest = self.NodeTest()
|
||||
return [ReverseAxis, NodeTest]
|
||||
else:# == "r'\\.\\.'"
|
||||
AbbrevReverseStep = self.AbbrevReverseStep()
|
||||
return AbbrevReverseStep
|
||||
|
||||
def ReverseAxis(self):
|
||||
REVERSE_AXIS_NAME = self._scan('REVERSE_AXIS_NAME')
|
||||
self._scan("r'::'")
|
||||
return REVERSE_AXIS_NAME
|
||||
|
||||
def AbbrevReverseStep(self):
|
||||
self._scan("r'\\.\\.'")
|
||||
return ['parent', None]
|
||||
|
||||
def NodeTest(self):
|
||||
_token_ = self._peek("r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME')
|
||||
if _token_ not in ["r'\\*'", 'NCNAME']:
|
||||
KindTest = self.KindTest()
|
||||
return KindTest
|
||||
else:# in ["r'\\*'", 'NCNAME']
|
||||
NameTest = self.NameTest()
|
||||
return NameTest
|
||||
|
||||
def NameTest(self):
|
||||
prefix = None
|
||||
WildcardOrNCName = self.WildcardOrNCName()
|
||||
localpart = WildcardOrNCName
|
||||
if self._peek("r':'", "r'\\['", "r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r':'":
|
||||
self._scan("r':'")
|
||||
WildcardOrNCName = self.WildcardOrNCName()
|
||||
prefix = localpart
|
||||
localpart = WildcardOrNCName
|
||||
return X.NameTest(prefix, localpart)
|
||||
|
||||
def WildcardOrNCName(self):
|
||||
_token_ = self._peek("r'\\*'", 'NCNAME')
|
||||
if _token_ == "r'\\*'":
|
||||
self._scan("r'\\*'")
|
||||
return '*'
|
||||
else:# == 'NCNAME'
|
||||
NCNAME = self._scan('NCNAME')
|
||||
return NCNAME
|
||||
|
||||
def FilterExpr(self):
|
||||
PrimaryExpr = self.PrimaryExpr()
|
||||
if self._peek("r'\\['", "r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'\\['":
|
||||
PredicateList = self.PredicateList()
|
||||
PrimaryExpr = X.PredicateList(PrimaryExpr,PredicateList)
|
||||
return PrimaryExpr
|
||||
|
||||
def PredicateList(self):
|
||||
Predicate = self.Predicate()
|
||||
predicates = [Predicate]
|
||||
while self._peek("r'\\['", "r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'\\['":
|
||||
Predicate = self.Predicate()
|
||||
predicates.append(Predicate)
|
||||
return predicates
|
||||
|
||||
def Predicate(self):
|
||||
self._scan("r'\\['")
|
||||
Expr = self.Expr()
|
||||
self._scan("r'\\]'")
|
||||
return Expr
|
||||
|
||||
def PrimaryExpr(self):
|
||||
_token_ = self._peek("r'\\('", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE')
|
||||
if _token_ not in ["r'\\('", "r'\\$'", "r'\\.'", 'FUNCNAME']:
|
||||
Literal = self.Literal()
|
||||
return X.LiteralExpr(Literal)
|
||||
elif _token_ == "r'\\$'":
|
||||
VariableReference = self.VariableReference()
|
||||
return VariableReference
|
||||
elif _token_ == "r'\\('":
|
||||
self._scan("r'\\('")
|
||||
Expr = self.Expr()
|
||||
self._scan("r'\\)'")
|
||||
return Expr
|
||||
elif _token_ == "r'\\.'":
|
||||
ContextItemExpr = self.ContextItemExpr()
|
||||
return ContextItemExpr
|
||||
else:# == 'FUNCNAME'
|
||||
FunctionCall = self.FunctionCall()
|
||||
return FunctionCall
|
||||
|
||||
def VariableReference(self):
|
||||
self._scan("r'\\$'")
|
||||
QName = self.QName()
|
||||
return X.VariableReference(*QName)
|
||||
|
||||
def ContextItemExpr(self):
|
||||
self._scan("r'\\.'")
|
||||
return X.AxisStep('self')
|
||||
|
||||
def FunctionCall(self):
|
||||
FUNCNAME = self._scan('FUNCNAME')
|
||||
self._scan("r'\\('")
|
||||
args = []
|
||||
if self._peek("r'\\,'", "r'\\)'", "r'\\-'", "r'\\/'", "r'\\/\\/'", "r'\\('", 'FORWARD_AXIS_NAME', "r'@'", 'REVERSE_AXIS_NAME', "r'\\.\\.'", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE', "r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('", "r'\\*'", 'NCNAME') not in ["r'\\,'", "r'\\)'"]:
|
||||
Expr = self.Expr()
|
||||
args.append(Expr)
|
||||
while self._peek("r'\\,'", "r'\\)'") == "r'\\,'":
|
||||
self._scan("r'\\,'")
|
||||
Expr = self.Expr()
|
||||
args.append(Expr)
|
||||
self._scan("r'\\)'")
|
||||
return X.Function(FUNCNAME, args)
|
||||
|
||||
def KindTest(self):
|
||||
_token_ = self._peek("r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('")
|
||||
if _token_ == "r'processing-instruction\\s*\\('":
|
||||
PITest = self.PITest()
|
||||
return PITest
|
||||
elif _token_ == "r'comment\\s*\\('":
|
||||
CommentTest = self.CommentTest()
|
||||
return CommentTest
|
||||
elif _token_ == "r'text\\s*\\('":
|
||||
TextTest = self.TextTest()
|
||||
return TextTest
|
||||
else:# == "r'node\\s*\\('"
|
||||
AnyKindTest = self.AnyKindTest()
|
||||
return AnyKindTest
|
||||
|
||||
def PITest(self):
|
||||
self._scan("r'processing-instruction\\s*\\('")
|
||||
name = None
|
||||
if self._peek('NCNAME', "r'\\)'", 'DQUOTE', 'SQUOTE') != "r'\\)'":
|
||||
_token_ = self._peek('NCNAME', 'DQUOTE', 'SQUOTE')
|
||||
if _token_ == 'NCNAME':
|
||||
NCNAME = self._scan('NCNAME')
|
||||
name = NCNAME
|
||||
else:# in ['DQUOTE', 'SQUOTE']
|
||||
StringLiteral = self.StringLiteral()
|
||||
name = StringLiteral
|
||||
self._scan("r'\\)'")
|
||||
return X.PITest(name)
|
||||
|
||||
def CommentTest(self):
|
||||
self._scan("r'comment\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.CommentTest()
|
||||
|
||||
def TextTest(self):
|
||||
self._scan("r'text\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.TextTest()
|
||||
|
||||
def AnyKindTest(self):
|
||||
self._scan("r'node\\s*\\('")
|
||||
self._scan("r'\\)'")
|
||||
return X.AnyKindTest()
|
||||
|
||||
def Literal(self):
|
||||
_token_ = self._peek('NUMBER', 'DQUOTE', 'SQUOTE')
|
||||
if _token_ == 'NUMBER':
|
||||
NumericLiteral = self.NumericLiteral()
|
||||
return NumericLiteral
|
||||
else:# in ['DQUOTE', 'SQUOTE']
|
||||
StringLiteral = self.StringLiteral()
|
||||
return StringLiteral
|
||||
|
||||
def NumericLiteral(self):
|
||||
NUMBER = self._scan('NUMBER')
|
||||
return float(NUMBER)
|
||||
|
||||
def StringLiteral(self):
|
||||
_token_ = self._peek('DQUOTE', 'SQUOTE')
|
||||
if _token_ == 'DQUOTE':
|
||||
DQUOTE = self._scan('DQUOTE')
|
||||
return DQUOTE[1:-1]
|
||||
else:# == 'SQUOTE'
|
||||
SQUOTE = self._scan('SQUOTE')
|
||||
return SQUOTE[1:-1]
|
||||
|
||||
def QName(self):
|
||||
NCNAME = self._scan('NCNAME')
|
||||
name = NCNAME
|
||||
if self._peek("r'\\:'", "r'\\['", "r'\\/'", "r'\\/\\/'", "'\\|'", 'MUL_COMP', 'ADD_COMP', 'REL_COMP', 'EQ_COMP', "r'and'", "r'or'", 'END', "r'\\]'", "r'\\)'", "r'\\,'") == "r'\\:'":
|
||||
self._scan("r'\\:'")
|
||||
NCNAME = self._scan('NCNAME')
|
||||
return (name, NCNAME)
|
||||
return (None, name)
|
||||
|
||||
|
||||
def parse(rule, text):
|
||||
P = XPath(XPathScanner(text))
|
||||
return wrap_error_reporter(P, rule)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv, stdin
|
||||
if len(argv) >= 2:
|
||||
if len(argv) >= 3:
|
||||
f = open(argv[2],'r')
|
||||
else:
|
||||
f = stdin
|
||||
print parse(argv[1], f.read())
|
||||
else: print 'Args: <rule> [<filename>]'
|
|
@ -0,0 +1,174 @@
|
|||
# Yapps 2.0 Runtime
|
||||
#
|
||||
# This module is needed to run generated parsers.
|
||||
|
||||
from string import join, count, find, rfind
|
||||
import re
|
||||
|
||||
class SyntaxError(Exception):
|
||||
"""When we run into an unexpected token, this is the exception to use"""
|
||||
def __init__(self, pos=-1, msg="Bad Token"):
|
||||
Exception.__init__(self)
|
||||
self.pos = pos
|
||||
self.msg = msg
|
||||
def __repr__(self):
|
||||
if self.pos < 0: return "#<syntax-error>"
|
||||
else: return "SyntaxError[@ char %s: %s]" % (repr(self.pos), self.msg)
|
||||
|
||||
class NoMoreTokens(Exception):
|
||||
"""Another exception object, for when we run out of tokens"""
|
||||
pass
|
||||
|
||||
class Scanner:
|
||||
def __init__(self, patterns, ignore, input):
|
||||
"""Patterns is [(terminal,regex)...]
|
||||
Ignore is [terminal,...];
|
||||
Input is a string"""
|
||||
self.tokens = []
|
||||
self.restrictions = []
|
||||
self.input = input
|
||||
self.pos = 0
|
||||
self.ignore = ignore
|
||||
# The stored patterns are a pair (compiled regex,source
|
||||
# regex). If the patterns variable passed in to the
|
||||
# constructor is None, we assume that the class already has a
|
||||
# proper .patterns list constructed
|
||||
if patterns is not None:
|
||||
self.patterns = []
|
||||
for k, r in patterns:
|
||||
self.patterns.append( (k, re.compile(r)) )
|
||||
|
||||
def token(self, i, restrict=0):
|
||||
"""Get the i'th token, and if i is one past the end, then scan
|
||||
for another token; restrict is a list of tokens that
|
||||
are allowed, or 0 for any token."""
|
||||
if i == len(self.tokens): self.scan(restrict)
|
||||
if i < len(self.tokens):
|
||||
# Make sure the restriction is more restricted
|
||||
if restrict and self.restrictions[i]:
|
||||
for r in restrict:
|
||||
if r not in self.restrictions[i]:
|
||||
raise NotImplementedError("Unimplemented: restriction set changed")
|
||||
return self.tokens[i]
|
||||
raise NoMoreTokens()
|
||||
|
||||
def __repr__(self):
|
||||
"""Print the last 10 tokens that have been scanned in"""
|
||||
output = ''
|
||||
for t in self.tokens[-10:]:
|
||||
output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3]))
|
||||
return output
|
||||
|
||||
def scan(self, restrict):
|
||||
"""Should scan another token and add it to the list, self.tokens,
|
||||
and add the restriction to self.restrictions"""
|
||||
# Keep looking for a token, ignoring any in self.ignore
|
||||
while 1:
|
||||
# Search the patterns for the longest match, with earlier
|
||||
# tokens in the list having preference
|
||||
best_match = -1
|
||||
best_pat = '(error)'
|
||||
for p, regexp in self.patterns:
|
||||
# First check to see if we're ignoring this token
|
||||
if restrict and p not in restrict and p not in self.ignore:
|
||||
continue
|
||||
m = regexp.match(self.input, self.pos)
|
||||
if m and len(m.group(0)) > best_match:
|
||||
# We got a match that's better than the previous one
|
||||
best_pat = p
|
||||
best_match = len(m.group(0))
|
||||
|
||||
# If we didn't find anything, raise an error
|
||||
if best_pat == '(error)' and best_match < 0:
|
||||
msg = "Bad Token"
|
||||
if restrict:
|
||||
msg = "Trying to find one of "+join(restrict,", ")
|
||||
raise SyntaxError(self.pos, msg)
|
||||
|
||||
# If we found something that isn't to be ignored, return it
|
||||
if best_pat not in self.ignore:
|
||||
# Create a token with this data
|
||||
token = (self.pos, self.pos+best_match, best_pat,
|
||||
self.input[self.pos:self.pos+best_match])
|
||||
self.pos = self.pos + best_match
|
||||
# Only add this token if it's not in the list
|
||||
# (to prevent looping)
|
||||
if not self.tokens or token != self.tokens[-1]:
|
||||
self.tokens.append(token)
|
||||
self.restrictions.append(restrict)
|
||||
return
|
||||
else:
|
||||
# This token should be ignored ..
|
||||
self.pos = self.pos + best_match
|
||||
|
||||
class Parser:
|
||||
def __init__(self, scanner):
|
||||
self._scanner = scanner
|
||||
self._pos = 0
|
||||
|
||||
def _peek(self, *types):
|
||||
"""Returns the token type for lookahead; if there are any args
|
||||
then the list of args is the set of token types to allow"""
|
||||
tok = self._scanner.token(self._pos, types)
|
||||
return tok[2]
|
||||
|
||||
def _scan(self, type):
|
||||
"""Returns the matched text, and moves to the next token"""
|
||||
tok = self._scanner.token(self._pos, [type])
|
||||
if tok[2] != type:
|
||||
raise SyntaxError(tok[0], 'Trying to find '+type)
|
||||
self._pos = 1+self._pos
|
||||
return tok[3]
|
||||
|
||||
|
||||
|
||||
def print_error(input, err, scanner):
|
||||
"""This is a really dumb long function to print error messages nicely."""
|
||||
p = err.pos
|
||||
# Figure out the line number
|
||||
line = count(input[:p], '\n')
|
||||
print err.msg+" on line "+repr(line+1)+":"
|
||||
# Now try printing part of the line
|
||||
text = input[max(p-80, 0):p+80]
|
||||
p = p - max(p-80, 0)
|
||||
|
||||
# Strip to the left
|
||||
i = rfind(text[:p], '\n')
|
||||
j = rfind(text[:p], '\r')
|
||||
if i < 0 or (0 <= j < i): i = j
|
||||
if 0 <= i < p:
|
||||
p = p - i - 1
|
||||
text = text[i+1:]
|
||||
|
||||
# Strip to the right
|
||||
i = find(text,'\n', p)
|
||||
j = find(text,'\r', p)
|
||||
if i < 0 or (0 <= j < i): i = j
|
||||
if i >= 0:
|
||||
text = text[:i]
|
||||
|
||||
# Now shorten the text
|
||||
while len(text) > 70 and p > 60:
|
||||
# Cut off 10 chars
|
||||
text = "..." + text[10:]
|
||||
p = p - 7
|
||||
|
||||
# Now print the string, along with an indicator
|
||||
print '> ',text
|
||||
print '> ',' '*p + '^'
|
||||
print 'List of nearby tokens:', scanner
|
||||
|
||||
def wrap_error_reporter(parser, rule):
|
||||
return_value = None
|
||||
try:
|
||||
return_value = getattr(parser, rule)()
|
||||
except SyntaxError, s:
|
||||
input = parser._scanner.input
|
||||
try:
|
||||
print_error(input, s, parser._scanner)
|
||||
except ImportError:
|
||||
print 'Syntax Error',s.msg,'on line',1+count(input[:s.pos], '\n')
|
||||
except NoMoreTokens:
|
||||
print 'Could not complete parsing; stopped around here:'
|
||||
print parser._scanner
|
||||
return return_value
|
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
|
||||
u"""Ce script permet d'obtenir ou de modifier un élément identifié par une expression XPATH
|
||||
"""
|
||||
|
||||
import os, sys, re, types, tempfile, codecs, shutil
|
||||
from os import path
|
||||
sys.path.insert(0, path.join(path.dirname(__file__), 'python'))
|
||||
from xml.dom import Node, minidom
|
||||
import xpath
|
||||
|
||||
def get_text(node, as_xml=False):
|
||||
if isinstance(node, Node):
|
||||
if node.nodeType == Node.ELEMENT_NODE:
|
||||
if as_xml: return node.toxml("utf-8")
|
||||
else: return xpath.expr.string_value(node).encode("utf-8")
|
||||
elif node.nodeType == Node.ATTRIBUTE_NODE:
|
||||
return node.value.encode("utf-8")
|
||||
elif node.nodeType == Node.TEXT_NODE or node.nodeType == Node.CDATA_SECTION_NODE:
|
||||
return node.data.encode("utf-8")
|
||||
elif type(node) is types.UnicodeType:
|
||||
return node.encode("utf-8")
|
||||
else:
|
||||
return str(node)
|
||||
|
||||
def set_text(node, value, doc):
|
||||
if not isinstance(node, Node):
|
||||
raise ValueError("L'expression ne désigne pas un noeud XML")
|
||||
if node.nodeType == Node.ELEMENT_NODE:
|
||||
firstChild = node.firstChild
|
||||
if value is not None:
|
||||
textNode = doc.createTextNode(value)
|
||||
if firstChild is None:
|
||||
node.appendChild(textNode)
|
||||
elif firstChild.nodeType == Node.TEXT_NODE or firstChild.nodeType == Node.CDATA_SECTION_NODE:
|
||||
node.replaceChild(textNode, firstChild)
|
||||
else:
|
||||
node.insertBefore(textNode, firstChild)
|
||||
elif firstChild is not None:
|
||||
if firstChild.nodeType == Node.TEXT_NODE or firstChild.nodeType == Node.CDATA_SECTION_NODE:
|
||||
node.removeChild(firstChild)
|
||||
elif node.nodeType == Node.ATTRIBUTE_NODE:
|
||||
if value is not None: node.value = value
|
||||
else: pass # impossible d'accéder au parent d'un attribut
|
||||
elif node.nodeType == Node.TEXT_NODE or node.nodeType == Node.CDATA_SECTION_NODE:
|
||||
if value is not None: node.data = value
|
||||
else: node.parentNode.removeChild(node)
|
||||
else:
|
||||
raise ValueError("Type de noeud non supporté: %s" % node.nodeType)
|
||||
|
||||
RE_PARENT0 = re.compile(r'(^|/)parent\[')
|
||||
RE_PARENT1 = re.compile(r'(^|/)parent(?=/|$)')
|
||||
def py_dom_xpath_compat(expr):
|
||||
expr = RE_PARENT0.sub(r"\1*[local-name()='parent' and ", expr)
|
||||
expr = RE_PARENT1.sub(r"\1*[local-name()='parent']", expr)
|
||||
return expr
|
||||
|
||||
def run_xpathtool():
|
||||
from optparse import OptionParser
|
||||
OP = OptionParser(usage=u"\n\t%prog -g XPATH [INPUT [OUTPUT]]\n\t%prog -s XPATH VALUE [INPUT [OUTPUT]]", description=__doc__)
|
||||
OP.add_option('-f', '--input', dest='inf',
|
||||
help=u"Spécifier le fichier en entrée")
|
||||
OP.add_option('-o', '--output', dest='outf',
|
||||
help=u"Spécifier le fichier en sortie")
|
||||
OP.add_option('-g', '--get', dest='mode', action='store_const', const='get',
|
||||
help=u"Forcer l'affichage de la valeur. "
|
||||
+ u"Par défaut, ce mode est sélectionné s'il n'y a aucun argument après XPATH")
|
||||
OP.add_option('-t', '--exist', dest='mode', action='store_const', const='exist',
|
||||
help=u"Tester l'existence du chemin spécifié.")
|
||||
OP.add_option('-s', '--set', dest='mode', action='store_const', const='set',
|
||||
help=u"Forcer la modification de la valeur. "
|
||||
+ u"Par défaut, ce mode est sélectionné s'il y a un argument VALUE après XPATH")
|
||||
OP.add_option('-x', '--as-xml', dest='as_xml', action='store_true',
|
||||
help=u"Retourner le résultat de l'expression en XML")
|
||||
OP.add_option('--no-compat', dest='compat', action='store_false', default=True,
|
||||
help=u"Ne pas transfomer certaines expression en un équivalent compatible avec py-dom-xpath. "
|
||||
+ u"Par exemple, par défaut \"/parent\" est transformé en \"/*[local-name='parent']\". "
|
||||
+ u"Cette option désactive ce comportement.")
|
||||
o, args = OP.parse_args()
|
||||
inf = o.inf
|
||||
outf = o.outf
|
||||
mode = o.mode
|
||||
as_xml = o.as_xml
|
||||
compat = o.compat
|
||||
|
||||
count = len(args)
|
||||
if count == 0: raise ValueError("Vous devez spécifier l'expression XPATH")
|
||||
expr = args[0]
|
||||
if compat: expr = py_dom_xpath_compat(expr)
|
||||
value = None
|
||||
|
||||
args = args[1:]
|
||||
count = len(args)
|
||||
if mode is None:
|
||||
if count == 0: # xpathtool.py XPATH
|
||||
mode = 'get'
|
||||
elif inf is None:
|
||||
if count == 1: # xpathtool.py XPATH INPUT
|
||||
mode = 'get'
|
||||
inf = args[0]
|
||||
elif count >= 2: # xpathtool.py XPATH VALUE INPUT [OUTPUT]
|
||||
mode = 'set'
|
||||
value = args[0]
|
||||
inf = args[1]
|
||||
if count > 2: outf = args[2]
|
||||
elif inf is not None: # xpathtool.py XPATH VALUE -f INPUT
|
||||
mode = 'set'
|
||||
value = args[0]
|
||||
elif mode == 'get':
|
||||
if inf is None: # xpathtool.py -g XPATH [INPUT]
|
||||
if count > 0: inf = args[0]
|
||||
elif mode == 'set':
|
||||
if count > 0: value = args[0]
|
||||
if inf is None: # xpathtool.py -s XPATH VALUE [INPUT [OUTPUT]]
|
||||
if count > 1: inf = args[1]
|
||||
if count > 2: outf = args[2]
|
||||
|
||||
if inf == '-': inf = None
|
||||
if outf == '-': outf = sys.stdout
|
||||
if inf is None:
|
||||
inf = sys.stdin
|
||||
if outf is None: outf = sys.stdout
|
||||
elif outf is None:
|
||||
outf = inf
|
||||
|
||||
doc = minidom.parse(inf)
|
||||
if mode == 'get' or mode == 'exist':
|
||||
#print "search %r from %r" % (expr, inf) #DEBUG
|
||||
nodes = xpath.find(expr, doc)
|
||||
if mode == 'get':
|
||||
for node in nodes:
|
||||
print get_text(node, as_xml)
|
||||
if nodes: r = 0
|
||||
else: r = 1
|
||||
sys.exit(r)
|
||||
elif mode == 'set':
|
||||
if value is not None and not type(value) is types.UnicodeType:
|
||||
value = unicode(value, "utf-8")
|
||||
#print "search %r in %r, replace with %r then write in %r" % (expr, inf, value, outf) #DEBUG
|
||||
for node in xpath.find(expr, doc):
|
||||
set_text(node, value, doc)
|
||||
#print "writing to %r" % outf #DEBUG
|
||||
if type(outf) in types.StringTypes:
|
||||
fd, tmpf = tempfile.mkstemp()
|
||||
try:
|
||||
os.close(fd)
|
||||
out = codecs.open(tmpf, "w", "utf-8")
|
||||
doc.writexml(out, encoding="utf-8")
|
||||
out.close()
|
||||
shutil.copyfile(tmpf, outf)
|
||||
finally:
|
||||
os.remove(tmpf)
|
||||
else:
|
||||
doc.writexml(outf, encoding="utf-8")
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_xpathtool()
|
|
@ -610,7 +610,7 @@ __VCS_GIT_ADVANCED=(
|
|||
git_is_merged
|
||||
)
|
||||
function git_check_gitvcs() {
|
||||
[ "$(_vcs_get_type "$(_vcs_get_dir)")" == git ]
|
||||
git rev-parse --show-toplevel >&/dev/null
|
||||
}
|
||||
function git_ensure_gitvcs() {
|
||||
git_check_gitvcs || die "Ce n'est pas un dépôt git"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
## Fonction de support pour gérer des fichiers XML
|
||||
##@cooked nocomments
|
||||
##@require ulib
|
||||
uprovide xmlsupport
|
||||
urequire ulib
|
||||
|
||||
function xpathtool() { "$ULIBDIR/support/xpathtool.py" "$@"; }
|
61
prel
61
prel
|
@ -94,7 +94,7 @@ OPTIONS
|
|||
-m, --merge
|
||||
Si la branche actuelle est une branche de release, ou s'il existe une
|
||||
branche de release, la merger dans master, puis dans develop, puis la
|
||||
supprimer. Puis basculer sur la branche master.
|
||||
supprimer. A l'issu de cette opération, rester sur la branche develop.
|
||||
S'il n'existe pas de branche de release, proposer de fusionner les
|
||||
modifications de la branche develop dans la branche master, sans
|
||||
préparer de branche de release au préalable.
|
||||
|
@ -114,13 +114,18 @@ OPTIONS
|
|||
release par rapport à develop.
|
||||
-d, --diff
|
||||
Afficher les modifications actuellement effectuée dans la branche de
|
||||
release par rapport à develop, sous forme de diff."
|
||||
release par rapport à develop, sous forme de diff.
|
||||
|
||||
OPTIONS AVANCEES
|
||||
--uc, --upgrade-changes
|
||||
Convertir un fichier CHANGES.txt en CHANGES.md"
|
||||
}
|
||||
|
||||
function show_summary() {
|
||||
git log --oneline --graph "$@" |
|
||||
grep -vF '|\' | grep -vF '|/' | sed 's/\* //; s/^ /+ /' |
|
||||
grep -v "Intégration de la branche release-"
|
||||
grep -v "Intégration de la branche release-" |
|
||||
grep -v "Branche develop en version .*-SNAPSHOT"
|
||||
}
|
||||
|
||||
function format_md() {
|
||||
|
@ -143,6 +148,21 @@ $1 == "|" {
|
|||
'
|
||||
}
|
||||
|
||||
function __get_newver_from_release() {
|
||||
local relver filever
|
||||
is_release_branch "$release" && relver="${release#release-}"
|
||||
setx filever=pver --sw "" --allow-empty
|
||||
if [ -n "$relver" -a "$filever" != "$relver" ]; then
|
||||
newver="$filever"
|
||||
ewarn "La version de la branche de release est différente de la version dans le fichier"
|
||||
enote "La version effectivement sélectionnée est $newver"
|
||||
elif [ -n "$filever" ]; then
|
||||
newver="$filever"
|
||||
elif [ -n "$relver" ]; then
|
||||
newver="$relver"
|
||||
fi
|
||||
}
|
||||
|
||||
projdir=
|
||||
origin=origin
|
||||
action=auto
|
||||
|
@ -208,6 +228,9 @@ fi
|
|||
|
||||
git_ensure_gitvcs
|
||||
|
||||
setx vertype=pver --sw "" --show-source
|
||||
[[ "$vertype" == pom* ]] && maven_update=1 || maven_update=
|
||||
|
||||
push_branches=()
|
||||
push_tags=()
|
||||
push_deferred=
|
||||
|
@ -216,14 +239,20 @@ push_deferred=
|
|||
|
||||
setx branch=git_get_branch
|
||||
|
||||
update_opt=
|
||||
if [ "$action" == update ]; then
|
||||
setx oldver=pver -g ""
|
||||
if [ -n "$maven_update" ]; then
|
||||
setx oldver=pver --gw develop:
|
||||
enote "La version de la branche develop est $oldver"
|
||||
else
|
||||
setx oldver=pver --gw master:
|
||||
fi
|
||||
newver=
|
||||
|
||||
if [ "$incversion" == auto ]; then
|
||||
if [ ${#pver_opts[*]} -gt 0 ]; then
|
||||
# des options ont été spécifiées, les honorer
|
||||
setx newver=pver -s "$oldver" "${pver_opts[@]}"
|
||||
setx newver=pver -s "$oldver" ${maven_update:+--maven-update -R} "${pver_opts[@]}"
|
||||
release="release-$newver"
|
||||
else
|
||||
# sinon, prendre une décision en fonction des branches de release
|
||||
|
@ -246,6 +275,7 @@ if [ "$action" == update ]; then
|
|||
fi
|
||||
fi
|
||||
fi
|
||||
pver_opts=(${maven_update:+--maven-update -R} "${pver_opts[@]}")
|
||||
case "$incversion" in
|
||||
menu)
|
||||
setx majorv=pver -s "$oldver" -ux "${pver_opts[@]}"
|
||||
|
@ -257,18 +287,28 @@ if [ "$action" == update ]; then
|
|||
-t "Basculer vers une nouvelle branche de release" \
|
||||
-m "Veuillez choisir la branche à créer"
|
||||
[ "$release" != master ] && newver="${release#release-}"
|
||||
if [ "$release" == "release-$majorv" ]; then
|
||||
update_opt=-x
|
||||
elif [ "$release" == "release-$minorv" ]; then
|
||||
update_opt=-z
|
||||
elif [ "$release" == "release-$patchlevelv" ]; then
|
||||
update_opt=-p
|
||||
fi
|
||||
;;
|
||||
major)
|
||||
setx newver=pver -s "$oldver" -ux "${pver_opts[@]}"
|
||||
release="release-$newver"
|
||||
update_opt=-x
|
||||
;;
|
||||
minor)
|
||||
setx newver=pver -s "$oldver" -uz "${pver_opts[@]}"
|
||||
release="release-$newver"
|
||||
update_opt=-z
|
||||
;;
|
||||
patchlevel)
|
||||
setx newver=pver -s "$oldver" -up "${pver_opts[@]}"
|
||||
release="release-$newver"
|
||||
update_opt=-p
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -331,7 +371,7 @@ Vous allez créer la nouvelle branche de release ${COULEUR_VERTE}$release${COULE
|
|||
|
||||
if [ -z "$newver" ]; then
|
||||
# le cas échéant, tenter de calculer la version en fonction de la release
|
||||
is_release_branch "$release" && newver="${release#release-}"
|
||||
__get_newver_from_release
|
||||
fi
|
||||
|
||||
if [ "$r" -eq 0 -a -n "$write" ]; then
|
||||
|
@ -445,7 +485,7 @@ if [ "$action" == merge ]; then
|
|||
|
||||
if [ -z "$newver" ]; then
|
||||
# le cas échéant, tenter de calculer la version en fonction de la release
|
||||
is_release_branch "$release" && newver="${release#release-}"
|
||||
__get_newver_from_release
|
||||
fi
|
||||
|
||||
if [ -n "$newver" ]; then
|
||||
|
@ -469,6 +509,13 @@ ou celle-ci pour pour pousser TOUS les tags:
|
|||
estepn "Intégration ${COULEUR_VERTE}$release${COULEUR_NORMALE} --> ${COULEUR_BLEUE}develop${COULEUR_NORMALE}"
|
||||
git checkout develop
|
||||
git merge "$release" -m "Intégration de la branche $release" --no-ff || die
|
||||
|
||||
if [ -n "$maven_update" ]; then
|
||||
[ -n "$update_opt" ] || update_opt=-z
|
||||
pver -u $update_opt -S
|
||||
git add -A
|
||||
git commit -m "Branche develop en version $(pver --show)" || die
|
||||
fi
|
||||
fi
|
||||
|
||||
# mettre à jour la branche sur laquelle on se trouve
|
||||
|
|
159
pver
159
pver
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
|
||||
urequire DEFAULTS ptools
|
||||
urequire DEFAULTS ptools xmlsupport
|
||||
|
||||
function pver_display_help() {
|
||||
uecho "$scriptname: gérer des numéros de version selon les règles du versionage sémantique v2.0.0 (http://semver.org/)
|
||||
|
@ -10,38 +10,55 @@ USAGE
|
|||
$scriptname [options]
|
||||
|
||||
OPTIONS
|
||||
-w, --auto-file DIR
|
||||
Gérer le numéro de version du répertoire spécifié. Si un fichier pom.xml
|
||||
existe dans ce répertoire, alors c'est l'option '-e DIR/pom.xml' qui est
|
||||
activé. Si un fichier VERSION.txt existe dans ce répertoire, alors c'est
|
||||
l'option '-f DIR/VERSION.txt' qui est activée. Sinon, un nouveau fichier
|
||||
VERSION.txt est créé dans ce répertoire. C'est l'option par défaut.
|
||||
--sw, --auto-string DIR
|
||||
Prendre pour valeur de départ la version du répertoire spécifié. Si un
|
||||
fichier pom.xml existe dans ce répertoire, alors c'est l'option -E qui
|
||||
est activé. Si un fichier VERSION.txt existe dans ce répertoire, alors
|
||||
c'est l'option -F qui est activée.
|
||||
--gw, --auto-git-string [BRANCH:]DIR
|
||||
Prendre pour valeur de départ la version du répertoire spécifié dans la
|
||||
branche BRANCH (qui vaut par défaut master) du dépôt git. Si un fichier
|
||||
pom.xml existe dans ce répertoire, alors c'est l'option -g qui est
|
||||
activé. Si un fichier VERSION.txt existe dans ce répertoire, alors c'est
|
||||
l'option -G qui est activée.
|
||||
-e, --pom POMFILE
|
||||
Gérer le numéro de version se trouvant dans le fichier pom.xml spécifié.
|
||||
Le fichier DOIT exister. Implique --maven-update
|
||||
-E, --pom-string POMFILE
|
||||
Prendre pour valeur de départ la version contenue dans le fichier
|
||||
pom.xml spécifié. Le fichier DOIT exister. Implique --maven-update
|
||||
-f, --file VERSIONFILE
|
||||
Gérer le numéro de version se trouvant dans le fichier spécifié. Le
|
||||
fichier est créé si nécessaire. C'est l'option par défaut si un fichier
|
||||
nommé VERSION.txt se trouve dans le répertoire courant.
|
||||
-e, --maven POMFILE
|
||||
Gérer le numéro de version se trouvant dans le fichier pom.xml spécifié.
|
||||
Le fichier DOIT exister. C'est l'option par défaut si un fichier nommé
|
||||
pom.xml se trouve dans le répertoire courant.
|
||||
fichier est créé si nécessaire.
|
||||
-F, --file-string VERSIONFILE
|
||||
Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
|
||||
vaut par défaut VERSION.txt)
|
||||
-g, --git-string [branch:]VERSIONFILE
|
||||
Prendre pour valeur de départ le contenu du fichier VERSIONFILE.
|
||||
-g, --git-file-string [BRANCH:]VERSIONFILE
|
||||
Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
|
||||
vaut par défaut VERSION.txt) dans la branche BRANCH (qui vaut par défaut
|
||||
master) du dépôt git situé dans le répertoire courant.
|
||||
master) du dépôt git. Retourner 2 si on n'est pas situé dans un dépôt
|
||||
git.
|
||||
-G, --git-pom-string [BRANCH:]POMFILE
|
||||
Prendre pour valeur de départ la version du fichier POMFILE (qui vaut
|
||||
par défaut pom.xml) dans la branche BRANCH (qui vaut par défaut master)
|
||||
du dépôt git. Retourner 2 si on n'est pas situé dans un dépôt git.
|
||||
--git-prel-string
|
||||
Prendre pour valeur de départ le numéro de version correspondant à la
|
||||
branche de release courante. Retourner 1 si la branche courante n'est
|
||||
pas une branche de release, 2 si on n'est pas situé dans un dépôt git.
|
||||
-s, --string VERSION
|
||||
Prendre pour valeur de départ le numéro de version spécifié
|
||||
|
||||
--show
|
||||
Afficher le numéro de version. C'est l'action par défaut
|
||||
--allow-empty
|
||||
Supporter que la version puisse ne pas être spécifiée ni trouvée. Dans
|
||||
ce cas, ne pas assumer que la version effective est 0.0.0
|
||||
Avec --show et --update, ne rien afficher si la version est vide.
|
||||
--check
|
||||
Vérifier que le numéro de version est conforme aux règles du versionage
|
||||
sémantique
|
||||
--convert
|
||||
--no-convert
|
||||
Activer (resp. désactiver) la conversion automatique. Par défaut, si la
|
||||
version est au format classique 'x.z[.p]-rDD/MM/YYYY', elle est
|
||||
convertie automatiquement au format sémantique x.z.p+rYYYYMMDD
|
||||
--eq VERSION
|
||||
--ne VERSION
|
||||
--lt VERSION
|
||||
|
@ -54,6 +71,10 @@ OPTIONS
|
|||
--le, --gt, et --ge ignorent l'identifiant de build (comme le demande la
|
||||
règle du versionage sémantique). Les opérateurs --same et --diff
|
||||
comparent aussi les identifiants de build.
|
||||
-u, --update
|
||||
Mettre à jour le numéro de version.
|
||||
|
||||
Les options suivantes impliquent --update:
|
||||
-v, --set-version VERSION
|
||||
Spécifier un nouveau numéro de version qui écrase la valeur actuelle.
|
||||
Cette option ne devrait pas être utilisée en temps normal parce que cela
|
||||
|
@ -62,18 +83,20 @@ OPTIONS
|
|||
Spécifier un nouveau numéro de version qui écrase la valeur actuelle. Le
|
||||
numéro de version est obtenu à partir du nom de la branche git courante,
|
||||
qui doit être de la forme release-VERSION
|
||||
-u, --update
|
||||
Mettre à jour le numéro de version.
|
||||
|
||||
--menu
|
||||
Afficher un menu permettant de choisir le composant de la version à
|
||||
incrémenter
|
||||
incrémenter.
|
||||
-x, --major
|
||||
Augmenter le numéro de version majeure
|
||||
Augmenter le numéro de version majeure.
|
||||
-z, --minor
|
||||
Augmenter le numéro de version mineure. C'est la valeur par défaut.
|
||||
-p, --patchlevel
|
||||
Augmenter le numéro de patch
|
||||
Augmenter le numéro de patch.
|
||||
-k, --keep
|
||||
Ne pas augmenter le numéro de version. Cette option est surtout utile
|
||||
pour *convertir* un numéro de version existant et mettre à jour le
|
||||
fichier correspondant. Elle est assumée si aucune option -[xzp] n'est
|
||||
spécifiée et qu'une des options -[labrSRmM] est utilisée.
|
||||
|
||||
-l, --prelease ID
|
||||
Spécifier un identifiant de pré-release, à ajouter au numéro de version.
|
||||
|
@ -85,17 +108,95 @@ OPTIONS
|
|||
de l'identifiant, e.g. alpha deviant alpha.1, beta-1.2 devient beta-1.3,
|
||||
rc1 devient rc2
|
||||
XXX ces fonctions ne sont pas encore implémentées
|
||||
-S, --snapshot
|
||||
Ajouter l'identifiant SNAPSHOT, utilisé par Maven
|
||||
-R, --final, --release
|
||||
Supprimer l'identifiant de prérelease
|
||||
Supprimer l'identifiant de prérelease, utilisé par Maven
|
||||
|
||||
-m, --metadata ID
|
||||
Spécifier un identifiant de build, à ajouter au numéro de version.
|
||||
-M, --vcs-metadata
|
||||
Spécifier l'identifiant à partir de la révision actuelle dans le
|
||||
Calculer l'identifiant de build à partir de la révision actuelle dans le
|
||||
gestionnaire de version. Note: pour le moment, seul git est supporté.
|
||||
--add-metadata ID
|
||||
Ajouter l'identifiant spécifié à la valeur actuelle, au lieu de la
|
||||
remplacer. Séparer l'identifiant de la valeur précédente avec un '.'"
|
||||
remplacer. Séparer l'identifiant de la valeur précédente avec un '.'
|
||||
|
||||
OPTIONS AVANCEES
|
||||
--show-source
|
||||
Afficher le type de source qui sera traité, i.e. pom, file, pom-string,
|
||||
file-string, git-pom-string, git-file-string
|
||||
--vpath VPATH
|
||||
Pour les options -e et -E, spécifier le chemin XPATH du tag qui contient
|
||||
le numéro de version.
|
||||
--map MAPFILE
|
||||
Cette option permet de spécifier un fichier de règles qui indique les
|
||||
fichiers pom.xml et VERSION.txt qui doivent être mis à jour dans un
|
||||
projet multi-modules pour lequel les versions doivent être mises à jour
|
||||
en même temps.
|
||||
Par défaut, si un fichier nommé .pver-map existe dans le répertoire de
|
||||
{POM,VERSION}FILE, cette option est automatiquement activée. Ainsi, on
|
||||
n'aura besoin d'utiliser cette option que si l'on désire charger un
|
||||
fichier alternatif ou ignorer le fichier par défaut.
|
||||
Si une valeur vide est fournie, seul le fichier {POM,VERSION}FILE est
|
||||
traité. Sinon, {POM,VERSION}FILE est utilisé uniquement pour chercher le
|
||||
fichier .pver-map et seuls les fichiers mentionnés dans MAPFILE sont
|
||||
traités.
|
||||
Le fichier MAPFILE est constitué d'un ensemble de lignes de la forme
|
||||
FILESPEC:VPATH
|
||||
FILESPEC est requis et prend la forme d'une spécification de chemin
|
||||
relatif au répertoire de MAPFILE et identifiant un ensemble de fichiers
|
||||
de version. Si FILESPEC contient des wildcards, alors les fichiers
|
||||
identifiés par ce chemin sont ignorés s'ils ont déjà été traités par une
|
||||
règle précédente. Si FILESPEC ne contient pas de wildcards, alors le
|
||||
fichier est systématiquement traité.
|
||||
VPATH désigne le chemin XPATH vers le numéro de version qu'il faut
|
||||
mettre à jour dans les fichiers pom.xml. Si VPATH vaut -, alors le
|
||||
fichier pom.xml correspondant n'est pas modifié (il est ignoré). Si
|
||||
VPATH est vide alors le chemin par défaut est utilisé pour ce
|
||||
fichier. Pour les fichiers VERSION.txt, VPATH doit être vide
|
||||
Le fichier de version correspondant au premier fichier de la première
|
||||
ligne de MAPFILE contient la version de référence, qui est dupliquée
|
||||
dans tous les autres fichiers.
|
||||
--allow-empty
|
||||
Supporter que la version puisse ne pas être spécifiée ni trouvée. Sans
|
||||
cette option, on assume que la version effective est 0.0.0 si elle n'est
|
||||
pas spécifiée ni trouvée.
|
||||
Avec --show et --update, ne rien afficher si la version est vide.
|
||||
--convert
|
||||
--no-convert
|
||||
Activer (resp. désactiver) la conversion automatique. Par défaut, si la
|
||||
version est au format classique 'x.z[.p]-rDD/MM/YYYY', elle est
|
||||
convertie automatiquement au format sémantique x.z.p+rYYYYMMDD
|
||||
-t, --maven-update
|
||||
Mettre à jour le numéro de version selons les règles de Maven. Cette
|
||||
option est automatiquement activée si -e est sélectionné. Elle n'est
|
||||
prise en compte qu'avec l'option -u
|
||||
Si les options -R et -S ne sont pas spécifiée, alors une release est
|
||||
transformée en snapshot et une snapshot en release. Avec -R, une
|
||||
snapshot est transformée en release, et une release est traitée /
|
||||
incrémentée normalement. Avec -S une release est transformée en
|
||||
snapshot, et un snapshot est traité / incrémentée normalement.
|
||||
Si l'une des options -x, -z, -p est utilisée, alors la partie spécifiée
|
||||
est incrémentée selon les règles suivantes. Dans les exemples suivants,
|
||||
A est un nombre quelconque, B = A + 1, et x, y et z sont des nombres
|
||||
quelconques.
|
||||
Avec l'option -x:
|
||||
A.0.0-SNAPSHOT --> A.0.0
|
||||
A.x.y-SNAPSHOT --> B.0.0
|
||||
x.A.y --> x.B.0-SNAPSHOT
|
||||
Avec l'option -z:
|
||||
x.A.0-SNAPSHOT --> x.A.0
|
||||
x.A.y-SNAPSHOT --> x.B.0
|
||||
x.A.y --> x.B.0-SNAPSHOT
|
||||
Avec l'option -p:
|
||||
x.y.z-SNAPSHOT --> x.y.z
|
||||
x.y.A --> x.y.B-SNAPSHOT
|
||||
Si aucune des options -x, -z, -p n'est utilisée, alors les parties sont
|
||||
incrémentées selon les règles suivantes:
|
||||
x.y.z-SNAPSHOT --> x.y.z (comme -p)
|
||||
x.A.0 --> x.B.0-SNAPSHOT (comme -z)
|
||||
x.y.A --> x.y.B-SNAPSHOT (comme -p)"
|
||||
}
|
||||
|
||||
pver "$@"
|
||||
|
|
Loading…
Reference in New Issue