pver supporte la gestion des versions maven
This commit is contained in:
parent
190519d968
commit
2980d15769
|
@ -217,7 +217,7 @@ Expression Context Objects
|
||||||
The context contains the following attributes and methods:
|
The context contains the following attributes and methods:
|
||||||
|
|
||||||
.. attribute:: default_namespace
|
.. attribute:: default_namespace
|
||||||
|
|
||||||
The default namespace URI.
|
The default namespace URI.
|
||||||
|
|
||||||
.. attribute:: namespaces
|
.. attribute:: namespaces
|
||||||
|
|
|
@ -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
|
__all__ = ['find', 'findnode', 'findvalue', 'XPathContext', 'XPath']
|
||||||
from exceptions import *
|
__all__.extend((x for x in dir(xpath.exceptions) if not x.startswith('_')))
|
||||||
|
|
||||||
__all__ = ['find', 'findnode', 'findvalue', 'findvalues', 'XPathContext', 'XPath']
|
def api(f):
|
||||||
__all__.extend((x for x in dir(exceptions) if not x.startswith('_')))
|
"""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
|
@api
|
||||||
def find(expr, node, **kwargs):
|
def find(expr, node, **kwargs):
|
||||||
|
|
|
@ -15,7 +15,7 @@ class XPathParseError(XPathError):
|
||||||
XPathError.__init__(self)
|
XPathError.__init__(self)
|
||||||
self.expr = expr
|
self.expr = expr
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
self.message = message
|
self.err = message
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ("Syntax error:\n" +
|
return ("Syntax error:\n" +
|
||||||
|
|
|
@ -6,7 +6,8 @@ import re
|
||||||
import xml.dom
|
import xml.dom
|
||||||
import weakref
|
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):
|
for n in axes['descendant'](node):
|
||||||
if n.nodeType == n.TEXT_NODE:
|
if n.nodeType == n.TEXT_NODE:
|
||||||
s += n.data
|
s += n.data
|
||||||
|
elif n.nodeType == n.CDATA_SECTION_NODE:
|
||||||
|
s += n.nodeValue
|
||||||
return s
|
return s
|
||||||
|
|
||||||
elif node.nodeType == node.ATTRIBUTE_NODE:
|
elif node.nodeType == node.ATTRIBUTE_NODE:
|
||||||
|
@ -31,9 +34,12 @@ def string_value(node):
|
||||||
node.nodeType == node.TEXT_NODE):
|
node.nodeType == node.TEXT_NODE):
|
||||||
return node.data
|
return node.data
|
||||||
|
|
||||||
|
elif node.nodeType == node.CDATA_SECTION_NODE:
|
||||||
|
return node.nodeValue
|
||||||
|
|
||||||
def document_order(node):
|
def document_order(node):
|
||||||
"""Compute a document order value for the node.
|
"""Compute a document order value for the node.
|
||||||
|
|
||||||
cmp(document_order(a), document_order(b)) will return -1, 0, or 1 if
|
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.
|
a is before, identical to, or after b in the document respectively.
|
||||||
|
|
||||||
|
@ -100,10 +106,10 @@ def string(v):
|
||||||
return u'Infinity'
|
return u'Infinity'
|
||||||
elif v == float('-inf'):
|
elif v == float('-inf'):
|
||||||
return u'-Infinity'
|
return u'-Infinity'
|
||||||
elif int(v) == v and v <= 0xffffffff:
|
|
||||||
v = int(v)
|
|
||||||
elif str(v) == 'nan':
|
elif str(v) == 'nan':
|
||||||
return u'NaN'
|
return u'NaN'
|
||||||
|
elif int(v) == v and v <= 0xffffffff:
|
||||||
|
v = int(v)
|
||||||
return unicode(v)
|
return unicode(v)
|
||||||
elif booleanp(v):
|
elif booleanp(v):
|
||||||
return u'true' if v else u'false'
|
return u'true' if v else u'false'
|
||||||
|
@ -747,7 +753,7 @@ class PathExpr(Expr):
|
||||||
|
|
||||||
class PredicateList(Expr):
|
class PredicateList(Expr):
|
||||||
"""A list of predicates.
|
"""A list of predicates.
|
||||||
|
|
||||||
Predicates are handled as an expression wrapping the expression
|
Predicates are handled as an expression wrapping the expression
|
||||||
filtered by the predicates.
|
filtered by the predicates.
|
||||||
|
|
||||||
|
@ -883,7 +889,8 @@ class CommentTest(object):
|
||||||
|
|
||||||
class TextTest(object):
|
class TextTest(object):
|
||||||
def match(self, node, axis, context):
|
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):
|
def __str__(self):
|
||||||
return 'text()'
|
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
|
import xpath.expr as X
|
||||||
from yappsrt import *
|
from xpath.yappsrt import *
|
||||||
|
|
||||||
|
|
||||||
from string import *
|
from string import *
|
||||||
|
@ -8,10 +8,10 @@ import re
|
||||||
class XPathScanner(Scanner):
|
class XPathScanner(Scanner):
|
||||||
patterns = [
|
patterns = [
|
||||||
("r'\\:'", re.compile('\\:')),
|
("r'\\:'", re.compile('\\:')),
|
||||||
("r'node'", re.compile('node')),
|
("r'node\\s*\\('", re.compile('node\\s*\\(')),
|
||||||
("r'text'", re.compile('text')),
|
("r'text\\s*\\('", re.compile('text\\s*\\(')),
|
||||||
("r'comment'", re.compile('comment')),
|
("r'comment\\s*\\('", re.compile('comment\\s*\\(')),
|
||||||
("r'processing-instruction'", re.compile('processing-instruction')),
|
("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('\\$')),
|
||||||
|
@ -121,7 +121,7 @@ class XPath(Parser):
|
||||||
return Expr
|
return Expr
|
||||||
|
|
||||||
def UnaryExpr(self):
|
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'\\-'":
|
if _token_ == "r'\\-'":
|
||||||
self._scan("r'\\-'")
|
self._scan("r'\\-'")
|
||||||
ValueExpr = self.ValueExpr()
|
ValueExpr = self.ValueExpr()
|
||||||
|
@ -135,11 +135,11 @@ class XPath(Parser):
|
||||||
return PathExpr
|
return PathExpr
|
||||||
|
|
||||||
def PathExpr(self):
|
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'\\/'":
|
if _token_ == "r'\\/'":
|
||||||
self._scan("r'\\/'")
|
self._scan("r'\\/'")
|
||||||
path = None
|
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()
|
RelativePathExpr = self.RelativePathExpr()
|
||||||
path = RelativePathExpr
|
path = RelativePathExpr
|
||||||
return X.AbsolutePathExpr(path)
|
return X.AbsolutePathExpr(path)
|
||||||
|
@ -168,7 +168,7 @@ class XPath(Parser):
|
||||||
return X.PathExpr(steps)
|
return X.PathExpr(steps)
|
||||||
|
|
||||||
def StepExpr(self):
|
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']:
|
if _token_ not in ["r'\\('", "r'\\$'", "r'\\.'", 'FUNCNAME', 'NUMBER', 'DQUOTE', 'SQUOTE']:
|
||||||
AxisStep = self.AxisStep()
|
AxisStep = self.AxisStep()
|
||||||
return AxisStep
|
return AxisStep
|
||||||
|
@ -177,7 +177,7 @@ class XPath(Parser):
|
||||||
return FilterExpr
|
return FilterExpr
|
||||||
|
|
||||||
def AxisStep(self):
|
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'\\.\\.'"]:
|
if _token_ not in ['REVERSE_AXIS_NAME', "r'\\.\\.'"]:
|
||||||
ForwardStep = self.ForwardStep()
|
ForwardStep = self.ForwardStep()
|
||||||
step = ForwardStep
|
step = ForwardStep
|
||||||
|
@ -191,7 +191,7 @@ class XPath(Parser):
|
||||||
return expr
|
return expr
|
||||||
|
|
||||||
def ForwardStep(self):
|
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':
|
if _token_ == 'FORWARD_AXIS_NAME':
|
||||||
ForwardAxis = self.ForwardAxis()
|
ForwardAxis = self.ForwardAxis()
|
||||||
NodeTest = self.NodeTest()
|
NodeTest = self.NodeTest()
|
||||||
|
@ -207,7 +207,7 @@ class XPath(Parser):
|
||||||
|
|
||||||
def AbbrevForwardStep(self):
|
def AbbrevForwardStep(self):
|
||||||
axis = 'child'
|
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'@'")
|
self._scan("r'@'")
|
||||||
axis = 'attribute'
|
axis = 'attribute'
|
||||||
NodeTest = self.NodeTest()
|
NodeTest = self.NodeTest()
|
||||||
|
@ -233,7 +233,7 @@ class XPath(Parser):
|
||||||
return ['parent', None]
|
return ['parent', None]
|
||||||
|
|
||||||
def NodeTest(self):
|
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']:
|
if _token_ not in ["r'\\*'", 'NCNAME']:
|
||||||
KindTest = self.KindTest()
|
KindTest = self.KindTest()
|
||||||
return KindTest
|
return KindTest
|
||||||
|
@ -315,7 +315,7 @@ class XPath(Parser):
|
||||||
FUNCNAME = self._scan('FUNCNAME')
|
FUNCNAME = self._scan('FUNCNAME')
|
||||||
self._scan("r'\\('")
|
self._scan("r'\\('")
|
||||||
args = []
|
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()
|
Expr = self.Expr()
|
||||||
args.append(Expr)
|
args.append(Expr)
|
||||||
while self._peek("r'\\,'", "r'\\)'") == "r'\\,'":
|
while self._peek("r'\\,'", "r'\\)'") == "r'\\,'":
|
||||||
|
@ -326,24 +326,23 @@ class XPath(Parser):
|
||||||
return X.Function(FUNCNAME, args)
|
return X.Function(FUNCNAME, args)
|
||||||
|
|
||||||
def KindTest(self):
|
def KindTest(self):
|
||||||
_token_ = self._peek("r'processing-instruction'", "r'comment'", "r'text'", "r'node'")
|
_token_ = self._peek("r'processing-instruction\\s*\\('", "r'comment\\s*\\('", "r'text\\s*\\('", "r'node\\s*\\('")
|
||||||
if _token_ == "r'processing-instruction'":
|
if _token_ == "r'processing-instruction\\s*\\('":
|
||||||
PITest = self.PITest()
|
PITest = self.PITest()
|
||||||
return PITest
|
return PITest
|
||||||
elif _token_ == "r'comment'":
|
elif _token_ == "r'comment\\s*\\('":
|
||||||
CommentTest = self.CommentTest()
|
CommentTest = self.CommentTest()
|
||||||
return CommentTest
|
return CommentTest
|
||||||
elif _token_ == "r'text'":
|
elif _token_ == "r'text\\s*\\('":
|
||||||
TextTest = self.TextTest()
|
TextTest = self.TextTest()
|
||||||
return TextTest
|
return TextTest
|
||||||
else:# == "r'node'"
|
else:# == "r'node\\s*\\('"
|
||||||
AnyKindTest = self.AnyKindTest()
|
AnyKindTest = self.AnyKindTest()
|
||||||
return AnyKindTest
|
return AnyKindTest
|
||||||
|
|
||||||
def PITest(self):
|
def PITest(self):
|
||||||
self._scan("r'processing-instruction'")
|
self._scan("r'processing-instruction\\s*\\('")
|
||||||
name = None
|
name = None
|
||||||
self._scan("r'\\('")
|
|
||||||
if self._peek('NCNAME', "r'\\)'", 'DQUOTE', 'SQUOTE') != "r'\\)'":
|
if self._peek('NCNAME', "r'\\)'", 'DQUOTE', 'SQUOTE') != "r'\\)'":
|
||||||
_token_ = self._peek('NCNAME', 'DQUOTE', 'SQUOTE')
|
_token_ = self._peek('NCNAME', 'DQUOTE', 'SQUOTE')
|
||||||
if _token_ == 'NCNAME':
|
if _token_ == 'NCNAME':
|
||||||
|
@ -356,20 +355,17 @@ class XPath(Parser):
|
||||||
return X.PITest(name)
|
return X.PITest(name)
|
||||||
|
|
||||||
def CommentTest(self):
|
def CommentTest(self):
|
||||||
self._scan("r'comment'")
|
self._scan("r'comment\\s*\\('")
|
||||||
self._scan("r'\\('")
|
|
||||||
self._scan("r'\\)'")
|
self._scan("r'\\)'")
|
||||||
return X.CommentTest()
|
return X.CommentTest()
|
||||||
|
|
||||||
def TextTest(self):
|
def TextTest(self):
|
||||||
self._scan("r'text'")
|
self._scan("r'text\\s*\\('")
|
||||||
self._scan("r'\\('")
|
|
||||||
self._scan("r'\\)'")
|
self._scan("r'\\)'")
|
||||||
return X.TextTest()
|
return X.TextTest()
|
||||||
|
|
||||||
def AnyKindTest(self):
|
def AnyKindTest(self):
|
||||||
self._scan("r'node'")
|
self._scan("r'node\\s*\\('")
|
||||||
self._scan("r'\\('")
|
|
||||||
self._scan("r'\\)'")
|
self._scan("r'\\)'")
|
||||||
return X.AnyKindTest()
|
return X.AnyKindTest()
|
||||||
|
|
||||||
|
|
|
@ -51,14 +51,14 @@ class Scanner:
|
||||||
raise NotImplementedError("Unimplemented: restriction set changed")
|
raise NotImplementedError("Unimplemented: restriction set changed")
|
||||||
return self.tokens[i]
|
return self.tokens[i]
|
||||||
raise NoMoreTokens()
|
raise NoMoreTokens()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Print the last 10 tokens that have been scanned in"""
|
"""Print the last 10 tokens that have been scanned in"""
|
||||||
output = ''
|
output = ''
|
||||||
for t in self.tokens[-10:]:
|
for t in self.tokens[-10:]:
|
||||||
output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3]))
|
output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3]))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def scan(self, restrict):
|
def scan(self, restrict):
|
||||||
"""Should scan another token and add it to the list, self.tokens,
|
"""Should scan another token and add it to the list, self.tokens,
|
||||||
and add the restriction to self.restrictions"""
|
and add the restriction to self.restrictions"""
|
||||||
|
@ -77,7 +77,7 @@ class Scanner:
|
||||||
# We got a match that's better than the previous one
|
# We got a match that's better than the previous one
|
||||||
best_pat = p
|
best_pat = p
|
||||||
best_match = len(m.group(0))
|
best_match = len(m.group(0))
|
||||||
|
|
||||||
# If we didn't find anything, raise an error
|
# If we didn't find anything, raise an error
|
||||||
if best_pat == '(error)' and best_match < 0:
|
if best_pat == '(error)' and best_match < 0:
|
||||||
msg = "Bad Token"
|
msg = "Bad Token"
|
||||||
|
@ -105,13 +105,13 @@ class Parser:
|
||||||
def __init__(self, scanner):
|
def __init__(self, scanner):
|
||||||
self._scanner = scanner
|
self._scanner = scanner
|
||||||
self._pos = 0
|
self._pos = 0
|
||||||
|
|
||||||
def _peek(self, *types):
|
def _peek(self, *types):
|
||||||
"""Returns the token type for lookahead; if there are any args
|
"""Returns the token type for lookahead; if there are any args
|
||||||
then the list of args is the set of token types to allow"""
|
then the list of args is the set of token types to allow"""
|
||||||
tok = self._scanner.token(self._pos, types)
|
tok = self._scanner.token(self._pos, types)
|
||||||
return tok[2]
|
return tok[2]
|
||||||
|
|
||||||
def _scan(self, type):
|
def _scan(self, type):
|
||||||
"""Returns the matched text, and moves to the next token"""
|
"""Returns the matched text, and moves to the next token"""
|
||||||
tok = self._scanner.token(self._pos, [type])
|
tok = self._scanner.token(self._pos, [type])
|
||||||
|
|
|
@ -14,6 +14,10 @@ rm -f .nutools-devel
|
||||||
# supprimer fichiers de développement
|
# supprimer fichiers de développement
|
||||||
rm -rf lib/pyulib/{build,devel,migrate,test}
|
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
|
# liens pour les scripts python
|
||||||
for i in plver plbck uencdetect urandomize umail uxpath wofixsql; do
|
for i in plver plbck uencdetect urandomize umail uxpath wofixsql; do
|
||||||
ln -s lib/pywrapper "$i"
|
ln -s lib/pywrapper "$i"
|
||||||
|
@ -21,6 +25,7 @@ done
|
||||||
ln -s lib/ulib/support/cgiupload.py
|
ln -s lib/ulib/support/cgiupload.py
|
||||||
ln -s lib/ulib/support/cgiparams.py
|
ln -s lib/ulib/support/cgiparams.py
|
||||||
ln -s lib/ulib/support/cgilsxml.py
|
ln -s lib/ulib/support/cgilsxml.py
|
||||||
|
ln -s lib/ulib/support/xpathtool.py
|
||||||
|
|
||||||
# liens pour les scripts shell
|
# liens pour les scripts shell
|
||||||
for i in cg cgs; do
|
for i in cg cgs; do
|
||||||
|
|
573
lib/ulib/ptools
573
lib/ulib/ptools
|
@ -3,8 +3,9 @@
|
||||||
##@cooked nocomments
|
##@cooked nocomments
|
||||||
##@include vcs
|
##@include vcs
|
||||||
##@include semver
|
##@include semver
|
||||||
|
##@include xmlsupport
|
||||||
uprovide ptools
|
uprovide ptools
|
||||||
urequire vcs semver
|
urequire vcs semver xmlsupport
|
||||||
|
|
||||||
function is_any_branch() {
|
function is_any_branch() {
|
||||||
local branch="$1"; shift
|
local branch="$1"; shift
|
||||||
|
@ -99,43 +100,93 @@ function list_feature_branches() {
|
||||||
################################################################################
|
################################################################################
|
||||||
# Outils de haut niveau
|
# Outils de haut niveau
|
||||||
|
|
||||||
function __pom_get_version() {
|
__pver_perror() {
|
||||||
# obtenir la version dans le pom $1(=pom.xml)
|
local r="$1"; shift
|
||||||
local pom="${1:-pom.xml}"
|
[ $# -gt 0 ] || set "Une erreur s'est produite"
|
||||||
awk <"$pom" '/^[ \t]*<version>/ {
|
local m=$r
|
||||||
sub(/^.*<version>/, "")
|
[ $m -gt $# ] && m=$#
|
||||||
sub(/<\/version>.*$/, "")
|
[ $m -gt 0 ] && eerror "${!m}"
|
||||||
print
|
return $r
|
||||||
exit
|
|
||||||
}'
|
|
||||||
}
|
}
|
||||||
function __pom_set_version() {
|
|
||||||
# modifier la version du le fichier $1(=pom.xml) à la valeur
|
__pver_unless() {
|
||||||
# $2(=1.0.0-SNAPSHOT)
|
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 pom="${1:-pom.xml}"
|
||||||
local version="${2:-1.0.0-SNAPSHOT}"
|
local version="${2:-1.0.0-SNAPSHOT}"
|
||||||
local tmpfile; ac_set_tmpfile tmpfile
|
local vpath="$3"
|
||||||
awk <"$pom" >"$tmpfile" '
|
[ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$pom")"
|
||||||
BEGIN {
|
xpathtool -f "$pom" -s "$vpath" "$version" || return 3
|
||||||
version = '"$(qawk "$version")"'
|
case "$vpath" in
|
||||||
found = 0
|
/project/version) return 0;;
|
||||||
}
|
/project/parent/version) return 1;;
|
||||||
!found && $0 ~ /^[ \t]*<version>/ {
|
*) return 2;;
|
||||||
prefix = "<version>"
|
esac
|
||||||
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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pver() {
|
function pver() {
|
||||||
|
@ -145,92 +196,170 @@ function pver() {
|
||||||
local -a args
|
local -a args
|
||||||
local action=auto
|
local action=auto
|
||||||
local source=auto
|
local source=auto
|
||||||
local file=
|
local file git version operator oversion
|
||||||
local git=
|
local setversion incversion
|
||||||
local version=
|
local setpr setprelease setsnapshot setalpha setbeta setrc setrelease
|
||||||
local allow_empty=
|
local setmd resetmetadata setmetadata addmetadata vcsmetadata
|
||||||
local convert=auto
|
local vpath setmapfile mapfile allow_empty convert=auto maven_update
|
||||||
local operator=
|
|
||||||
local oversion=
|
|
||||||
local setversion=
|
|
||||||
local incversion=
|
|
||||||
local setprelease=
|
|
||||||
local setalpha=
|
|
||||||
local setbeta=
|
|
||||||
local setrc=
|
|
||||||
local setrelease=
|
|
||||||
local setmetadata= addmetadata=
|
|
||||||
local vcsmetadata=
|
|
||||||
parse_opts "${PRETTYOPTS[@]}" \
|
parse_opts "${PRETTYOPTS[@]}" \
|
||||||
--help '$exit_with pver_display_help' \
|
--help '$exit_with pver_display_help' \
|
||||||
-f:,--file: '$set@ file; source=file' \
|
-w:,--w:,--fw:,--auto-file: '$set@ file; source=auto-file' \
|
||||||
-e:,--maven:,--pom: '$set@ file; source=pom' \
|
--sw:,--auto-string: '$set@ file; source=auto-string' \
|
||||||
-F:,--file-string: '$set@ file; source=file-string' \
|
--gw:,--auto-git-string: '$set@ git; source=auto-git-string' \
|
||||||
-g:,--git-string: '$set@ git; source=git-string' \
|
-e:,--e:,--pom:,--maven: '$set@ file; source=pom' \
|
||||||
-s:,--string: '$set@ version; source=string' \
|
-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 \
|
--show action=show \
|
||||||
--allow-empty allow_empty=1 \
|
--show-source action=show-source \
|
||||||
--check action=check \
|
--check action=check \
|
||||||
--convert convert=1 \
|
|
||||||
--no-convert convert= \
|
|
||||||
--eq: '$action=compare; operator=eq; set@ oversion' \
|
--eq: '$action=compare; operator=eq; set@ oversion' \
|
||||||
--ne: '$action=compare; operator=ne; set@ oversion' \
|
--ne: '$action=compare; operator=ne; set@ oversion' \
|
||||||
--lt: '$action=compare; operator=lt; set@ oversion' \
|
--lt: '$action=compare; operator=lt; set@ oversion' \
|
||||||
--le: '$action=compare; operator=le; set@ oversion' \
|
--le: '$action=compare; operator=le; set@ oversion' \
|
||||||
--gt: '$action=compare; operator=gt; set@ oversion' \
|
--gt: '$action=compare; operator=gt; set@ oversion' \
|
||||||
--ge: '$action=compare; operator=ge; 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' \
|
-u,--update '$action=update; [ -z "$incversion" ] && incversion=auto' \
|
||||||
--menu '$action=update; incversion=menu' \
|
--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' \
|
-x,--major '$action=update; incversion=major' \
|
||||||
-z,--minor '$action=update; incversion=minor' \
|
-z,--minor '$action=update; incversion=minor' \
|
||||||
-p,--patchlevel '$action=update; incversion=patchlevel' \
|
-p,--patchlevel '$action=update; incversion=patchlevel' \
|
||||||
-l:,--prelease:,--prerelease: '$action=update; set@ setprelease; [ -z "$setprelease" ] && { setalpha=; setbeta=; setrc=; setrelease=1; }' \
|
-k,--keep '$action=update; incversion=' \
|
||||||
-a,--alpha '$action=update; setalpha=1; setbeta=; setrc=; setrelease=' \
|
-l:,--prelease:,--prerelease: '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=; set@ setprelease; [ -z "$setprelease" ] && setrelease=1' \
|
||||||
-b,--beta '$action=update; setalpha=; setbeta=1; setrc=; setrelease=' \
|
-S,--snapshot '$action=update; setpr=1; setsnapshot=1; setalpha=; setbeta=; setrc=; setrelease=' \
|
||||||
-r,--rc '$action=update; setalpha=; setbeta=; setrc=1; setrelease=' \
|
-a,--alpha '$action=update; setpr=1; setsnapshot=; setalpha=1; setbeta=; setrc=; setrelease=' \
|
||||||
-R,--release,--final '$action=update; setalpha=; setbeta=; setrc=; setrelease=1' \
|
-b,--beta '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=1; setrc=; setrelease=' \
|
||||||
-m:,--metadata:,--set-metadata: '$action=update; set@ setmetadata' \
|
-r,--rc '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=1; setrelease=' \
|
||||||
--add-metadata: '$action=update; set@ addmetadata' \
|
-R,--release,--final '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=1' \
|
||||||
-M,--vcs-metadata '$action=update; vcsmetadata=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; }
|
@ args -- "$@" && set -- "${args[@]}" || { eerror "$args"; return 1; }
|
||||||
|
|
||||||
# Calculer la source
|
# 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
|
if [ "$source" == auto ]; then
|
||||||
source=file
|
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
|
if [ -f "$i" ]; then
|
||||||
case "$i" in
|
case "$i" in
|
||||||
"$DEFAULT_POM")
|
"$DEFAULT_POM") source=pom; file="$i"; break;;
|
||||||
source=pom
|
*) source=file; file="$i"; break;;
|
||||||
file="$i"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
source=file
|
|
||||||
file="$i"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
elif [ "$source" == file ]; then
|
elif [ "$source" == file -o "$source" == pom ]; then
|
||||||
[ "$action" == auto ] && action=update
|
[ "$action" == auto ] && action=update
|
||||||
fi
|
fi
|
||||||
[ "$source" == file -a -z "$file" ] && file="$DEFAULT_FILE"
|
[ "$source" == file -a -z "$file" ] && file="$DEFAULT_FILE"
|
||||||
[ "$source" == pom -a -z "$file" ] && file="$DEFAULT_POM"
|
[ "$source" == pom -a -z "$file" ] && file="$DEFAULT_POM"
|
||||||
[ "$action" == auto ] && action=show
|
[ "$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
|
# 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
|
if [ "$source" == file ]; then
|
||||||
[ -f "$file" ] && version="$(<"$file")"
|
[ -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
|
elif [ "$source" == file-string ]; then
|
||||||
if [ -z "$file" ]; then
|
if [ -z "$file" ]; then
|
||||||
file="$DEFAULT_FILE"
|
file="$DEFAULT_FILE"
|
||||||
|
@ -239,14 +368,51 @@ function pver() {
|
||||||
fi
|
fi
|
||||||
[ -f "$file" ] && version="$(<"$file")"
|
[ -f "$file" ] && version="$(<"$file")"
|
||||||
file=
|
file=
|
||||||
elif [ "$source" == git-string ]; then
|
|
||||||
|
elif [ "$source" == git-file-string ]; then
|
||||||
|
git_check_gitvcs || return 2
|
||||||
splitfsep2 "$git" : branch name
|
splitfsep2 "$git" : branch name
|
||||||
[ -n "$branch" ] || branch=master
|
[ -n "$branch" ] || branch=master
|
||||||
[ -n "$name" ] || name="$DEFAULT_FILE"
|
[ -n "$name" ] || name="$DEFAULT_FILE"
|
||||||
if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
|
if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
|
||||||
version="$(git cat-file blob "$branch:$name" 2>/dev/null)"
|
version="$(git cat-file blob "$branch:$name" 2>/dev/null)"
|
||||||
fi
|
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
|
fi
|
||||||
|
|
||||||
[ -n "$version" -o -n "$allow_empty" ] || version=0.0.0
|
[ -n "$version" -o -n "$allow_empty" ] || version=0.0.0
|
||||||
|
|
||||||
# Conversion éventuelle du numéro de version
|
# Conversion éventuelle du numéro de version
|
||||||
|
@ -285,7 +451,7 @@ BEGIN {
|
||||||
version = version ".0"
|
version = version ".0"
|
||||||
}
|
}
|
||||||
# afficher la version migrée au format semver
|
# afficher la version migrée au format semver
|
||||||
if (metadata != "") print version "+" metadata
|
if (metadata != "") print version "+r" metadata
|
||||||
else print version
|
else print version
|
||||||
|
|
||||||
### maven, pom.xml
|
### maven, pom.xml
|
||||||
|
@ -339,7 +505,7 @@ BEGIN {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$action" == check ]; then
|
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
|
elif [ "$action" == compare ]; then
|
||||||
psemver_parse "$oversion" o
|
psemver_parse "$oversion" o
|
||||||
|
@ -423,94 +589,100 @@ BEGIN {
|
||||||
|
|
||||||
elif [ "$action" == update ]; then
|
elif [ "$action" == update ]; then
|
||||||
[ -z "$version" -a -n "$allow_empty" ] && return 1
|
[ -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 [ -n "$file" ]; then
|
||||||
if [ -f "$file" ]; then
|
if [ -f "$file" ]; then
|
||||||
if isatty; then
|
isatty && estepi "La version actuelle est $version"
|
||||||
estepi "La version actuelle est $version"
|
|
||||||
fi
|
|
||||||
elif [ "$source" == pom ]; then
|
elif [ "$source" == pom ]; then
|
||||||
eerror "$file: fichier introuvable"
|
eerror "$file: fichier introuvable"
|
||||||
return 1
|
return 1
|
||||||
else
|
elif isatty; then
|
||||||
if isatty; then
|
ask_yesno "Le fichier $(ppath "$file") n'existe pas. Faut-il le créer?" O || return 1
|
||||||
ask_yesno "Le fichier $(ppath "$file") n'existe pas. Faut-il le créer?" O || return 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# forcer le numéro de version
|
# forcer le numéro de version
|
||||||
if [ -n "$setversion" ]; then
|
if [ -n "$setversion" ]; then
|
||||||
if [ "$setversion" == prel ]; then
|
if [ "$setversion" == prel ]; then
|
||||||
local branch; branch="$(git_get_branch)" || return 2
|
setversion="$(__pver_get_prel_version)"
|
||||||
if [[ "$branch" == release-* ]]; then
|
__pver_perror $? \
|
||||||
setversion="${branch#release-}"
|
"$(git_get_branch): n'est pas une release branch" \
|
||||||
else
|
"Dépôt git introuvable" || return
|
||||||
eerror "$branch: n'est pas une release branch"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
psemver_setversion "$setversion" "" || { eerror "Numéro de version invalide: $setversion"; return 1; }
|
psemver_setversion "$setversion" "" || {
|
||||||
|
eerror "Numéro de version invalide: $setversion"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Calculer metadata
|
# Calculer metadata
|
||||||
if [ -n "$vcsmetadata" ]; then
|
if [ -n "$vcsmetadata" ]; then
|
||||||
|
resetmetadata=1
|
||||||
setmetadata="$(git rev-parse --short HEAD)" || return 1
|
setmetadata="$(git rev-parse --short HEAD)" || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# incrémenter les numéros de version
|
# incrémenter les numéros de version
|
||||||
if [ "$incversion" == auto ]; then
|
if [ -n "$maven_update" -a -n "$incversion" ]; then
|
||||||
if [ -n "$setrelease" -o -n "$setprelease" -o -n "$setmetadata" -o -n "$addmetadata" ]; then
|
# il y a des règles particulières pour maven
|
||||||
incversion=
|
if [ -n "$setrelease" -a -z "$prelease" ]; then
|
||||||
else
|
# on est déjà en release, faire le traitement normal
|
||||||
incversion=menu
|
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
|
||||||
|
[ -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
|
||||||
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
|
if [ "$incversion" == menu ]; then
|
||||||
psemver_copy x; {
|
psemver_copy x
|
||||||
psemver_incmajor x
|
psemver_incsetprmd major x "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||||
psemver_setprelease "$setprelease" x
|
psemver_setvar versionx x
|
||||||
if [ -n "$addmetadata" ]; then
|
psemver_copy z
|
||||||
[ -n "$setmetadata" ] && psemver_setmetadata "$setmetadata" x
|
psemver_incsetprmd minor z "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||||
psemver_addmetadata "$addmetadata" x
|
psemver_setvar versionz z
|
||||||
else
|
psemver_copy p
|
||||||
psemver_setmetadata "$setmetadata" x
|
psemver_incsetprmd patchlevel p "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||||
fi
|
psemver_setvar versionp p
|
||||||
psemver_setvar versionx x
|
psemver_copy k
|
||||||
}
|
psemver_incsetprmd "" k "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata" "$maven_update"
|
||||||
psemver_copy z; {
|
psemver_setvar versionk k
|
||||||
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_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_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_setvar versionk k
|
|
||||||
}
|
|
||||||
nextvs=(
|
nextvs=(
|
||||||
"$versionx : maj incompatibles de l'API (-x)"
|
"$versionx : maj incompatibles de l'API (-x)"
|
||||||
"$versionz : maj compatibles de l'API (-z)"
|
"$versionz : maj compatibles de l'API (-z)"
|
||||||
|
@ -528,49 +700,74 @@ BEGIN {
|
||||||
*) incversion=;;
|
*) incversion=;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local r
|
||||||
if [ -n "$incversion" ]; then
|
if [ -n "$incversion" ]; then
|
||||||
case "$incversion" in
|
psemver_incsetprmd "$incversion" "" "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
|
||||||
major) psemver_incmajor;;
|
r=$?
|
||||||
minor) psemver_incminor;;
|
else
|
||||||
patchlevel) psemver_incpatchlevel;;
|
psemver_setprmd "" "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata"
|
||||||
esac
|
r=$?
|
||||||
# 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
|
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
|
||||||
|
|
||||||
# afficher le résultat final
|
# afficher le résultat final
|
||||||
|
local -a depfiles
|
||||||
psemver_setvar version
|
psemver_setvar version
|
||||||
if [ -n "$file" ]; then
|
if [ -n "$file" ]; then
|
||||||
case "$source" in
|
if [ "$source" == file ]; then
|
||||||
file) echo "$version" >"$file";;
|
echo "$version" >"$file"
|
||||||
pom) __pom_set_version "$file" "$version";;
|
elif [ "$source" == pom ]; then
|
||||||
esac
|
__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
|
fi
|
||||||
if isatty; then
|
if isatty; then
|
||||||
estepn "La nouvelle version est $version"
|
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
|
else
|
||||||
echo "$version"
|
echo "$version"
|
||||||
fi
|
fi
|
||||||
|
|
106
lib/ulib/semver
106
lib/ulib/semver
|
@ -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_check_metadata() { [ -z "${1//[a-zA-Z0-9.-]/}" ]; }
|
||||||
|
|
||||||
function semver_parse() {
|
function semver_parse() {
|
||||||
|
# args: version majorV minorV patchlevelV preleaseV metadataV validV
|
||||||
local __p_ver="$1"
|
local __p_ver="$1"
|
||||||
local __p_ma="${2:-major}" __p_mi="${3:-minor}" __p_pl="${4:-patchlevel}"
|
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}"
|
local __p_pr="${5:-prelease}" __p_md="${6:-metadata}" __p_va="${7:-valid}"
|
||||||
|
@ -84,34 +85,79 @@ function semver_parse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_incmajor() {
|
function semver_incmajor() {
|
||||||
setv "$1" $((${!1} + 1))
|
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||||
setv "$2" 0
|
if [ -z "$6" ]; then
|
||||||
setv "$3" 0
|
setv "$1" $((${!1} + 1))
|
||||||
array_new "$4"
|
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() {
|
function semver_incminor() {
|
||||||
setv "$2" $((${!2} + 1))
|
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||||
setv "$3" 0
|
if [ -z "$6" ]; then
|
||||||
array_new "$4"
|
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() {
|
function semver_incpatchlevel() {
|
||||||
setv "$3" $((${!3} + 1))
|
# args: majorV minorV patchlevelV preleaseV metadataV maven_update setprelease
|
||||||
array_new "$4"
|
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() {
|
function semver_setversion() {
|
||||||
|
# args: version majorV minorV patchlevelV preleaseV metadataV
|
||||||
local __sv_ma __sv_mi __sv_svl __sv_svr __sv_md __sv_va
|
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
|
semver_parse "$1" __sv_ma __sv_mi __sv_pl __sv_pr __sv_md __sv_va
|
||||||
[ -n "$__sv_va" ] || return 1
|
[ -n "$__sv_va" ] || return 1
|
||||||
setv "$2" "$__sv_ma"
|
setv "$2" "$__sv_ma"
|
||||||
setv "$3" "$__sv_mi"
|
setv "$3" "$__sv_mi"
|
||||||
setv "$4" "$__sv_pl"
|
setv "$4" "$__sv_pl"
|
||||||
|
array_copy "$5" __sv_pr
|
||||||
|
array_copy "$6" __sv_md
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_setprelease() {
|
function semver_setprelease() {
|
||||||
|
# args: setprelease majorV minorV patchlevelV preleaseV metadataV
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ]; then
|
||||||
__semver_check_prelease "$1" || return 1
|
__semver_check_prelease "$1" || return 1
|
||||||
array_split "$5" "$1" .
|
array_split "$5" "$1" .
|
||||||
|
@ -122,6 +168,7 @@ function semver_setprelease() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_compare_prelease() {
|
function semver_compare_prelease() {
|
||||||
|
# args: prelease1 prelease2
|
||||||
local -a __cp_pr1 __cp_pr2 __cp_len i __cp_v1 __cp_v2
|
local -a __cp_pr1 __cp_pr2 __cp_len i __cp_v1 __cp_v2
|
||||||
array_copy __cp_pr1 "$1"
|
array_copy __cp_pr1 "$1"
|
||||||
array_copy __cp_pr2 "$2"
|
array_copy __cp_pr2 "$2"
|
||||||
|
@ -179,6 +226,7 @@ function semver_compare_prelease() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_setmetadata() {
|
function semver_setmetadata() {
|
||||||
|
# args: setmetadata majorV minorV patchlevelV preleaseV metadataV
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ]; then
|
||||||
__semver_check_metadata "$1" || return 1
|
__semver_check_metadata "$1" || return 1
|
||||||
array_split "$6" "$1" .
|
array_split "$6" "$1" .
|
||||||
|
@ -189,6 +237,7 @@ function semver_setmetadata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_addmetadata() {
|
function semver_addmetadata() {
|
||||||
|
# args: addmetadata majorV minorV patchlevelV preleaseV metadataV
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ]; then
|
||||||
__semver_check_metadata "$1" || return 1
|
__semver_check_metadata "$1" || return 1
|
||||||
local -a __sam_metadata
|
local -a __sam_metadata
|
||||||
|
@ -199,11 +248,13 @@ function semver_addmetadata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_compare_metadata() {
|
function semver_compare_metadata() {
|
||||||
|
# args: metadata1 metadata2
|
||||||
# même algo que pour prelease
|
# même algo que pour prelease
|
||||||
semver_compare_prelease "$@"
|
semver_compare_prelease "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_copy() {
|
function semver_copy() {
|
||||||
|
# args: majorDV minorDV patchlevelDV preleaseDV metadataDV majorSV minorSV patchlevelSV preleaseSV metadataSV
|
||||||
setv "$1" "${!6}"
|
setv "$1" "${!6}"
|
||||||
setv "$2" "${!7}"
|
setv "$2" "${!7}"
|
||||||
setv "$3" "${!8}"
|
setv "$3" "${!8}"
|
||||||
|
@ -212,6 +263,7 @@ function semver_copy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_build() {
|
function semver_build() {
|
||||||
|
# args: majorV minorV patchlevelV preleaseV metadataV
|
||||||
echo_ "${!1}.${!2}.${!3}"
|
echo_ "${!1}.${!2}.${!3}"
|
||||||
array_isempty "$4" || recho_ "-$(array_join "$4" .)"
|
array_isempty "$4" || recho_ "-$(array_join "$4" .)"
|
||||||
array_isempty "$5" || recho_ "+$(array_join "$5" .)"
|
array_isempty "$5" || recho_ "+$(array_join "$5" .)"
|
||||||
|
@ -219,6 +271,7 @@ function semver_build() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function semver_setvar() {
|
function semver_setvar() {
|
||||||
|
# args: versionV majorV minorV patchlevelV preleaseV metadataV
|
||||||
setv "$1" "$(semver_build "$2" "$3" "$4" "$5" "$6")"
|
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
|
# 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_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_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" "${1}metadata"; }
|
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" "${1}metadata"; }
|
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_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_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"; }
|
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_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_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_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
|
from xpath.exceptions import *
|
||||||
import parser as P
|
import xpath.exceptions
|
||||||
import yappsrt as Y
|
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):
|
def api(f):
|
||||||
"""Decorator for functions and methods that are part of the external
|
"""Decorator for functions and methods that are part of the external
|
||||||
|
@ -60,19 +63,19 @@ class XPathContext(object):
|
||||||
|
|
||||||
@api
|
@api
|
||||||
def find(self, expr, node, **kwargs):
|
def find(self, expr, node, **kwargs):
|
||||||
return XPath.get(expr).find(node, context=self, **kwargs)
|
return xpath.find(expr, node, context=self, **kwargs)
|
||||||
|
|
||||||
@api
|
@api
|
||||||
def findnode(self, expr, node, **kwargs):
|
def findnode(self, expr, node, **kwargs):
|
||||||
return XPath.get(expr).findnode(node, context=self, **kwargs)
|
return xpath.findnode(expr, node, context=self, **kwargs)
|
||||||
|
|
||||||
@api
|
@api
|
||||||
def findvalue(self, expr, node, **kwargs):
|
def findvalue(self, expr, node, **kwargs):
|
||||||
return XPath.get(expr).findvalue(node, context=self, **kwargs)
|
return xpath.findvalue(expr, node, context=self, **kwargs)
|
||||||
|
|
||||||
@api
|
@api
|
||||||
def findvalues(self, expr, node, **kwargs):
|
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():
|
class XPath():
|
||||||
_max_cache = 100
|
_max_cache = 100
|
||||||
|
@ -82,9 +85,9 @@ class XPath():
|
||||||
"""Init docs.
|
"""Init docs.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
parser = P.XPath(P.XPathScanner(str(expr)))
|
parser = xpath.parser.XPath(xpath.parser.XPathScanner(str(expr)))
|
||||||
self.expr = parser.XPath()
|
self.expr = parser.XPath()
|
||||||
except Y.SyntaxError, e:
|
except xpath.yappsrt.SyntaxError, e:
|
||||||
raise XPathParseError(str(expr), e.pos, e.msg)
|
raise XPathParseError(str(expr), e.pos, e.msg)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -112,7 +115,7 @@ class XPath():
|
||||||
@api
|
@api
|
||||||
def findnode(self, node, context=None, **kwargs):
|
def findnode(self, node, context=None, **kwargs):
|
||||||
result = self.find(node, context, **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")
|
raise XPathTypeError("expression is not a node-set")
|
||||||
if len(result) == 0:
|
if len(result) == 0:
|
||||||
return None
|
return None
|
||||||
|
@ -121,18 +124,18 @@ class XPath():
|
||||||
@api
|
@api
|
||||||
def findvalue(self, node, context=None, **kwargs):
|
def findvalue(self, node, context=None, **kwargs):
|
||||||
result = self.find(node, context, **kwargs)
|
result = self.find(node, context, **kwargs)
|
||||||
if E.nodesetp(result):
|
if xpath.expr.nodesetp(result):
|
||||||
if len(result) == 0:
|
if len(result) == 0:
|
||||||
return None
|
return None
|
||||||
result = E.string(result)
|
result = xpath.expr.string(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@api
|
@api
|
||||||
def findvalues(self, node, context=None, **kwargs):
|
def findvalues(self, node, context=None, **kwargs):
|
||||||
result = self.find(node, context, **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")
|
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):
|
def __repr__(self):
|
||||||
return '%s.%s(%s)' % (self.__class__.__module__,
|
return '%s.%s(%s)' % (self.__class__.__module__,
|
||||||
|
@ -141,3 +144,19 @@ class XPath():
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.expr)
|
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
|
git_is_merged
|
||||||
)
|
)
|
||||||
function git_check_gitvcs() {
|
function git_check_gitvcs() {
|
||||||
[ "$(_vcs_get_type "$(_vcs_get_dir)")" == git ]
|
git rev-parse --show-toplevel >&/dev/null
|
||||||
}
|
}
|
||||||
function git_ensure_gitvcs() {
|
function git_ensure_gitvcs() {
|
||||||
git_check_gitvcs || die "Ce n'est pas un dépôt git"
|
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
|
-m, --merge
|
||||||
Si la branche actuelle est une branche de release, ou s'il existe une
|
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
|
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
|
S'il n'existe pas de branche de release, proposer de fusionner les
|
||||||
modifications de la branche develop dans la branche master, sans
|
modifications de la branche develop dans la branche master, sans
|
||||||
préparer de branche de release au préalable.
|
préparer de branche de release au préalable.
|
||||||
|
@ -114,13 +114,18 @@ OPTIONS
|
||||||
release par rapport à develop.
|
release par rapport à develop.
|
||||||
-d, --diff
|
-d, --diff
|
||||||
Afficher les modifications actuellement effectuée dans la branche de
|
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() {
|
function show_summary() {
|
||||||
git log --oneline --graph "$@" |
|
git log --oneline --graph "$@" |
|
||||||
grep -vF '|\' | grep -vF '|/' | sed 's/\* //; s/^ /+ /' |
|
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() {
|
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=
|
projdir=
|
||||||
origin=origin
|
origin=origin
|
||||||
action=auto
|
action=auto
|
||||||
|
@ -208,6 +228,9 @@ fi
|
||||||
|
|
||||||
git_ensure_gitvcs
|
git_ensure_gitvcs
|
||||||
|
|
||||||
|
setx vertype=pver --sw "" --show-source
|
||||||
|
[[ "$vertype" == pom* ]] && maven_update=1 || maven_update=
|
||||||
|
|
||||||
push_branches=()
|
push_branches=()
|
||||||
push_tags=()
|
push_tags=()
|
||||||
push_deferred=
|
push_deferred=
|
||||||
|
@ -216,14 +239,20 @@ push_deferred=
|
||||||
|
|
||||||
setx branch=git_get_branch
|
setx branch=git_get_branch
|
||||||
|
|
||||||
|
update_opt=
|
||||||
if [ "$action" == update ]; then
|
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=
|
newver=
|
||||||
|
|
||||||
if [ "$incversion" == auto ]; then
|
if [ "$incversion" == auto ]; then
|
||||||
if [ ${#pver_opts[*]} -gt 0 ]; then
|
if [ ${#pver_opts[*]} -gt 0 ]; then
|
||||||
# des options ont été spécifiées, les honorer
|
# 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"
|
release="release-$newver"
|
||||||
else
|
else
|
||||||
# sinon, prendre une décision en fonction des branches de release
|
# sinon, prendre une décision en fonction des branches de release
|
||||||
|
@ -246,6 +275,7 @@ if [ "$action" == update ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
pver_opts=(${maven_update:+--maven-update -R} "${pver_opts[@]}")
|
||||||
case "$incversion" in
|
case "$incversion" in
|
||||||
menu)
|
menu)
|
||||||
setx majorv=pver -s "$oldver" -ux "${pver_opts[@]}"
|
setx majorv=pver -s "$oldver" -ux "${pver_opts[@]}"
|
||||||
|
@ -257,18 +287,28 @@ if [ "$action" == update ]; then
|
||||||
-t "Basculer vers une nouvelle branche de release" \
|
-t "Basculer vers une nouvelle branche de release" \
|
||||||
-m "Veuillez choisir la branche à créer"
|
-m "Veuillez choisir la branche à créer"
|
||||||
[ "$release" != master ] && newver="${release#release-}"
|
[ "$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)
|
major)
|
||||||
setx newver=pver -s "$oldver" -ux "${pver_opts[@]}"
|
setx newver=pver -s "$oldver" -ux "${pver_opts[@]}"
|
||||||
release="release-$newver"
|
release="release-$newver"
|
||||||
|
update_opt=-x
|
||||||
;;
|
;;
|
||||||
minor)
|
minor)
|
||||||
setx newver=pver -s "$oldver" -uz "${pver_opts[@]}"
|
setx newver=pver -s "$oldver" -uz "${pver_opts[@]}"
|
||||||
release="release-$newver"
|
release="release-$newver"
|
||||||
|
update_opt=-z
|
||||||
;;
|
;;
|
||||||
patchlevel)
|
patchlevel)
|
||||||
setx newver=pver -s "$oldver" -up "${pver_opts[@]}"
|
setx newver=pver -s "$oldver" -up "${pver_opts[@]}"
|
||||||
release="release-$newver"
|
release="release-$newver"
|
||||||
|
update_opt=-p
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -331,7 +371,7 @@ Vous allez créer la nouvelle branche de release ${COULEUR_VERTE}$release${COULE
|
||||||
|
|
||||||
if [ -z "$newver" ]; then
|
if [ -z "$newver" ]; then
|
||||||
# le cas échéant, tenter de calculer la version en fonction de la release
|
# 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
|
fi
|
||||||
|
|
||||||
if [ "$r" -eq 0 -a -n "$write" ]; then
|
if [ "$r" -eq 0 -a -n "$write" ]; then
|
||||||
|
@ -445,7 +485,7 @@ if [ "$action" == merge ]; then
|
||||||
|
|
||||||
if [ -z "$newver" ]; then
|
if [ -z "$newver" ]; then
|
||||||
# le cas échéant, tenter de calculer la version en fonction de la release
|
# 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
|
fi
|
||||||
|
|
||||||
if [ -n "$newver" ]; then
|
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}"
|
estepn "Intégration ${COULEUR_VERTE}$release${COULEUR_NORMALE} --> ${COULEUR_BLEUE}develop${COULEUR_NORMALE}"
|
||||||
git checkout develop
|
git checkout develop
|
||||||
git merge "$release" -m "Intégration de la branche $release" --no-ff || die
|
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
|
fi
|
||||||
|
|
||||||
# mettre à jour la branche sur laquelle on se trouve
|
# mettre à jour la branche sur laquelle on se trouve
|
||||||
|
|
159
pver
159
pver
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- 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
|
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
|
||||||
urequire DEFAULTS ptools
|
urequire DEFAULTS ptools xmlsupport
|
||||||
|
|
||||||
function pver_display_help() {
|
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/)
|
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]
|
$scriptname [options]
|
||||||
|
|
||||||
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
|
-f, --file VERSIONFILE
|
||||||
Gérer le numéro de version se trouvant dans le fichier spécifié. Le
|
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
|
fichier est créé si nécessaire.
|
||||||
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.
|
|
||||||
-F, --file-string VERSIONFILE
|
-F, --file-string VERSIONFILE
|
||||||
Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
|
Prendre pour valeur de départ le contenu du fichier VERSIONFILE.
|
||||||
vaut par défaut VERSION.txt)
|
-g, --git-file-string [BRANCH:]VERSIONFILE
|
||||||
-g, --git-string [branch:]VERSIONFILE
|
|
||||||
Prendre pour valeur de départ le contenu du fichier VERSIONFILE (qui
|
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
|
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
|
-s, --string VERSION
|
||||||
Prendre pour valeur de départ le numéro de version spécifié
|
Prendre pour valeur de départ le numéro de version spécifié
|
||||||
|
|
||||||
--show
|
--show
|
||||||
Afficher le numéro de version. C'est l'action par défaut
|
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
|
--check
|
||||||
Vérifier que le numéro de version est conforme aux règles du versionage
|
Vérifier que le numéro de version est conforme aux règles du versionage
|
||||||
sémantique
|
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
|
--eq VERSION
|
||||||
--ne VERSION
|
--ne VERSION
|
||||||
--lt VERSION
|
--lt VERSION
|
||||||
|
@ -54,6 +71,10 @@ OPTIONS
|
||||||
--le, --gt, et --ge ignorent l'identifiant de build (comme le demande la
|
--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
|
règle du versionage sémantique). Les opérateurs --same et --diff
|
||||||
comparent aussi les identifiants de build.
|
comparent aussi les identifiants de build.
|
||||||
|
-u, --update
|
||||||
|
Mettre à jour le numéro de version.
|
||||||
|
|
||||||
|
Les options suivantes impliquent --update:
|
||||||
-v, --set-version VERSION
|
-v, --set-version VERSION
|
||||||
Spécifier un nouveau numéro de version qui écrase la valeur actuelle.
|
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
|
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
|
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,
|
numéro de version est obtenu à partir du nom de la branche git courante,
|
||||||
qui doit être de la forme release-VERSION
|
qui doit être de la forme release-VERSION
|
||||||
-u, --update
|
|
||||||
Mettre à jour le numéro de version.
|
|
||||||
|
|
||||||
--menu
|
--menu
|
||||||
Afficher un menu permettant de choisir le composant de la version à
|
Afficher un menu permettant de choisir le composant de la version à
|
||||||
incrémenter
|
incrémenter.
|
||||||
-x, --major
|
-x, --major
|
||||||
Augmenter le numéro de version majeure
|
Augmenter le numéro de version majeure.
|
||||||
-z, --minor
|
-z, --minor
|
||||||
Augmenter le numéro de version mineure. C'est la valeur par défaut.
|
Augmenter le numéro de version mineure. C'est la valeur par défaut.
|
||||||
-p, --patchlevel
|
-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
|
-l, --prelease ID
|
||||||
Spécifier un identifiant de pré-release, à ajouter au numéro de version.
|
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,
|
de l'identifiant, e.g. alpha deviant alpha.1, beta-1.2 devient beta-1.3,
|
||||||
rc1 devient rc2
|
rc1 devient rc2
|
||||||
XXX ces fonctions ne sont pas encore implémentées
|
XXX ces fonctions ne sont pas encore implémentées
|
||||||
|
-S, --snapshot
|
||||||
|
Ajouter l'identifiant SNAPSHOT, utilisé par Maven
|
||||||
-R, --final, --release
|
-R, --final, --release
|
||||||
Supprimer l'identifiant de prérelease
|
Supprimer l'identifiant de prérelease, utilisé par Maven
|
||||||
|
|
||||||
-m, --metadata ID
|
-m, --metadata ID
|
||||||
Spécifier un identifiant de build, à ajouter au numéro de version.
|
Spécifier un identifiant de build, à ajouter au numéro de version.
|
||||||
-M, --vcs-metadata
|
-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é.
|
gestionnaire de version. Note: pour le moment, seul git est supporté.
|
||||||
--add-metadata ID
|
--add-metadata ID
|
||||||
Ajouter l'identifiant spécifié à la valeur actuelle, au lieu de la
|
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 "$@"
|
pver "$@"
|
||||||
|
|
Loading…
Reference in New Issue