BindRules - ShapeTools version bind rules
The ShapeTools version binding subsystem (see
vbind(1)) provides a mechanism for
expressing
general version bind rules. These rules describe on an
abstract level version properties, which will be matched against the
properties of concrete versions during the version bind procedure. The goal is
to select one or more versions from a named history in order to provides
access to these version(s). A version bind operation is always performed for
exactly one history at a time. Version bind rules express something like
Select the most recent saved version.
If there is no saved version, select the busy version.
ShapeTools however needs rules in a more formal notation to be able to interpret
them. Let's see, how the rule above is translated into the formal notation.
Version bind rules consist of a list of attribute expressions evaluated one
after another until one of the expressions leads to a unique version
identification. The expressions are separated by semicolons, the last
expression ends with a period. The rule from above will now read:
Select the most recent saved version ;
Select the busy version .
Each attribute expression consist of a list of predicates, separated by commas.
The predicates are evaluated from left to right resulting in a
hit set,
a set of versions fulfilling all predicates evaluated so far. The initial hit
set for an attribute expression contains all versions of the name to be bound.
Each predicate potentially narrows the hit set. The predicates in our rule
are:
all saved versions , most recent version ;
busy version .
Remember, that each predicate bases it's selection on the hit set left by the
predicate before. Hence exchanging the two predicates in the first attribute
expression may lead to different results. We will give more information on
this topic in the section about the evaluation algorithm below. We now reach
the final form of ShapeTools version bind rules. The predicates must be taken
from a list of predefined names and be equipped with arguments:
ge (status, saved) , max (stime) ;
eq (status, busy) .
That's it so far. This is a rule how ShapeTools understands it. It does however
illustrate just a small piece of the world of version bind rules. We will go
on in this manual page with a detailed description of version bind rules
divides into the sections
- RULE HEAD
- Description of the structure of rule heads.
- EVALUATION ALGORITHM
- The Algorithm how version bind rules are evaluated.
- NAME PATTERNS
- Name patterns as first predicate in attribute
expressions.
- PREDICATES
- List of valid predicates.
- ATTRIBUTES
- A List of predefined attribute names and some word about
the ordering relationship between attribute values.
- EXPANSION
- Description of the various types of expansion such as
parameter substitution, attribute and macro expansion, and command
substitution.
- LEXICAL STRUCTURE
- Lexical constraints for names and strings in version bind
rules.
- TIPS, TRICKS, AND TRAPS
- Some common problems.
- GRAMMAR
- A complete grammar for version bind rules.
A version bind rule consists of a rule head and a rule body. The example above
shows only the rule body. The rule head defines a name for the rule and
optionally a parameter list. The name is a string consisting of any printable
non-whitespace character except colon and parentheses. It is followed by an
optional parameter list in parentheses and a colon, delimiting the rule head.
Multiple parameters in the list are separated by comma. Examples are
most_recently_released:
from_release (release_name):
last_released (library_path, include_path):
The basic idea of the rule evaluation algorithm is, that in every state of
processing a
hit set exists, a set of versions reflecting the current
rule evaluation result. The hit set is initialized with all versions of the
given name at the beginning of each attribute expression. The attribute
expressions predicates are processed from left to right in the order they
occur. Each predicate imposes requirements to the versions in the hit set and
eliminates all versions not fulfilling these requirements. So, the hit set
becomes smaller and smaller during attribute expression evaluation. The
following figure illustrates this process together with the rule
most_recently_released defined above and the file foo existing as busy version
and as versions 1.0 through 1.2.
Initial hit set: ( foo[busy], foo[1.0], foo[1.1], foo[1.2] )
Evaluate Predicate: ge (status, saved),
New hit set: ( foo[1.0], foo[1.1], foo[1.2] )
Evaluate Predicate: max (stime);
Final hit set: ( foo[1.2] )
When the hit set becomes empty, that is when no version meets all the predicates
evaluated so far, the attribute expression
fails and processing is
finished immediately. All remaining predicates will not be evaluated. Even
remaining predicates without influence on the hit set (for example message
predicates) will not be processed. Processing continues with the next
attribute expression. If all attribute expressions finish prematurely, the
whole version binding fails. In the following example, the first attribute
expression fails and the second alternative leads to success.
Initial hit set: ( bar[busy] )
Evaluate Predicate: ge (status, saved),
New hit set (empty): ( )
Evaluate next attribute expression
starting with initial hit set again: ( bar[busy] )
Evaluate Predicate: eq (status, busy);
Final hit set: ( bar[busy] )
When evaluation reaches the end of an attribute expression without the hit set
being empty, two cases are possible. First, the hit set contains exactly one
version and everything is fine. This is usually the desired state and rule
evaluation returns the remaining version as bind result. Second, the hit set
may contain more than one version. In this case, the evaluation algorithm
depends on the expected result. When a unique version binding is expected,
this is treated as failure and evaluation goes on with the next attribute
expression. Non-unique version binding regards this as success and returns the
whole hit set.
Extending the hit set during evaluation of an attribute expression is not
possible. This would be against the nature of the version bind rules and would
make them much more difficult to understand. Hit set extension may only happen
by letting the current attribute expression fail and begin with a new one and
the maximum hit set.
Failure of an attribute expression must not necessarily be caused by an empty
hit set. It may also be caused by user interaction or by external constraints.
The following rules exemplify user interaction:
eq (state, busy), confirm (select busy version ?, y);
ge (state, busy), max (version).
where the user will be asked for confirmation to select the busy version, and
external constraints:
exists (otto, 1.0), eq (state, busy);
ge (state, busy), max (version).
where selection of the busy version happens only, when version 1.0 of otto
exists (this example is somewhat silly). Predicates like confirm and exists
don't care about the hit set. They provide the possibility to impose external
control on the evaluation of version bind rules. An attribute expression may
be finished prematurely and control switches to the next one.
There is another operator, the cut operator, that forces the whole bind
operation to finish (and fail). Typically the cut operator stands at the end
of an attribute expression that should never succeed. The following is a
typical example for use of this. Version binding fails, if there is an update
lock set on the most recent version.
max (version), hasattr (locker), cut (history is locked !);
max (version).
The cut operator accepts a string argument that will be written to the standard
output.
Each attribute expression may start with a pattern, against which the name to be
bound is matched. Only when the name matches the pattern, the corresponding
attribute expression will be evaluated. If not, the attribute expression will
be skipped. When the pattern is omitted in the attribute expression (as in our
example above), the expression is evaluated for each name.
The patterns are the same as those recognized by
sh(1) for filename generation
on the command line. Magic cookies are:
- *
- matching any string, including the empty string,
- ?
- matching any single character,
- [c...]
- matching any one of the characters enclosed in the square
brackets,
- [l-r]
- matching any character lexically between the left
(l) and the right ( r) character, inclusive, and
- [!c...]
- [!l-r]
- matching any character not recognized by their counterparts
above.
A rule with name patterns for example looks like:
xyyz.h, eq (version, 1.3);
*.c, eq (generation, 2), max (revision);
*.h, eq (generation, 3), max (revision).
In this example, version binding for C source files (most recent version from
generation 2) is different from version binding for header files (most recent
version from generation 3). Additionally, the name xyyz.h will always be bound
to version 1.3.
If the name to be bound is given together with a (absolute or relative)
pathname, this will
not be cut off. The match is always performed
lexically for the whole name given. Hence, the name pattern may also contain
path names, like
variant1/*, eq (alias, var1-1.4);
variant2/*, eq (alias, var2-1.2);
/usr/sample/include/*.h, max (revision).
Usually, the version bind subsystem does not check, if different path prefixes
in the name pattern and the given name to be bound lead to the same location.
The match is done lexically and must fit exactly. An exception is, when the
name pattern is given as network path name as in
atnetwork(3). A network
pathname consists of the name of the host, controlling the device where a
version is stored, the canonical pathname to the version and a version binding
(e.g. version number, version alias, or date) either in brackets or separated
from the name by an at (@) sign. Examples are
desaster:/usr/sample/project/foo.c[1.0];
desaster:/usr/sample/project/variant1/bar.c[var1-1.4];
desaster:/usr/sample/project/[email protected];
desaster:/usr/sample/project/bar.c@Fri Jun 18 13:40:58 MET DST 1993.
Network pathnames are mapped to canonical local pathnames before being processes
and in this case, the given name to be bound will also be mapped to a
canonical local pathname.
The technique using network pathnames is especially useful when storing the
result of a successful version selection persistently. This makes the version
selection easily reproducible from anywhere in the local areas network.
shape(1) uses this mechanism when generating its
bound configuration
threads.
This is the complete list of valid predicate names and a synopsis of their
arguments. The list is divided into several parts, each describing a certain
class of predicates.
The first class are predicates working independently on each element of the
current hit set. They impose certain requirements to the attributes of each
version and eliminate those, not fulfilling the requirements.
- eq (attrName,attrValue)
- The named attribute must exist in the versions attribute
list and it must have exactly the given value. When the corresponding
version attribute has multiple values, at least one of the values must
match exactly.
- hasattr (attrName)
- The named attribute must exist in the versions attribute
list. When applied to a standard attribute, hasattr requires a value to be
associated with the standard attribute. In case of user defined
attributes, the attribute value is not regarded.
- ne (attrName,attrValue)
- The named attribute, when existing in the versions
attribute buffer, must not have the given attribute value. When the
attribute does not exist, everything is fine. If the attribute has
multiple values, it is required, that none of the values matches the given
attrValue.
- {ge,gt,le,lt} (attrName,attrValue)
- The named version attribute must have a value, that is
greater or equal / greater than / less or equal / less than the given
attribute value. The named attribute must exist in the versions attribute
buffer, otherwise the version is eliminated from the hit set. For
attributes with multiple values, only one of the values must meet the
required property.
The second class are predicates that do not operate on single version but rather
on the complete hit set. They express relations between different versions in
the hit set and base their selection on comparison of different versions.
Usually, they are used to get a unique version binding, by ordering the hit
set and selecting one of the extremes.
- min (attrName)
- Retain the version(s) with the lowest value for the named
attribute in the hit set. String values are compared literally, others
"naturally" (see the list of known attributes below for an
explanation of that). Versions not carrying the named attribute or having
no value associated with the attribute name are eliminated from the hit
set.
- max (attrName)
- Retain the version(s) with the highest value for the named
attribute in the hit set. String values are compared literally, others
"naturally" (see the list of known attributes below for an
explanation of that). Versions not carrying the named attribute or having
no value associated with the attribute name are eliminated from the hit
set.
The next two predicate groups have no direct influence on the hit set. They can
invalidate the hit set and cause the rule evaluation to go on with the next
attribute expression, but they do never modify the hit set. These predicates
are activated, when the evaluation of the attribute expression reaches them,
i.e. when the hit set is not empty.
- msg (msgString)
- Print the given message to standard output and retain the
current hit set.
- cut (msgString)
- Force the current rule binding to fail and print the given
message to standard output. Printing is omitted, when the message string
is empty. Rule processing is stopped immediately and the returned hit set
is empty.
- confirm (msgString,expectedAnswer)
- Ask the user for confirmation to go on with the evaluation
of the current attribute expression. The given message string is printed
to standard output with the expected answer appended in square brackets.
After that, user input is read. When the user confirms the expected answer
(empty input) or his/her input matches the expected answer, evaluation of
the current attribute expression continues. Otherwise, the current hit set
is invalidated and processing goes on with the next attribute
expression.
- bindrule (ruleName)
- Abort evaluation of current attribute expression and switch
to another version bind rule. This predicate makes only sense as last
predicate in an attribute expression, as following predicates will never
be evaluated. Evaluation of the target rule ( ruleName) happens as
if the rule has been invoked directly, no influence on the initial hit set
is taken. When the target rule fails, the evaluation algorithm switches
back to the source rule and goes on with the next attribute
expression.
The last predicate group are external constraints. Their task is to influence
the evaluation process by examining conditions outside the handled version
history. Each of the following predicates has either a positive or a negative
result. Positive results have no effect on the hit set and the evaluation
process, while negative results invalidate the hit set and cause evaluation to
go on with the next attribute expression.
- exists (name[binding])
- Version binding with the given name (usually another one
than the current target name) and the given version binding must lead to
at least one version. The result is not required to be unique.
- existsnot (name[binding])
- Version binding with the given name and rule must
fail.
- existsuniq (name[binding])
- Version binding with the given name and rule must lead to a
unique selection.
- condexpr (program,expression)
- An external program, named in the program argument, is
activated to evaluate the given expression. The expression string is
written to the standard input of the external program. A zero result code
is considered to be positive, all others negative.
There are a number of known predicate names from former versions of the bind
rules machinery. They are internally mapped to the new predicate names. These
names are obsolete and should not be used any longer.
Obsolete name mapped to - cut attr eq attrex hasattr attrge ge
attrgt gt attrle le attrlt lt attrmax max attrmin min attrnot ne condex exists
condnot existsnot conduniq existsuniq
All predicates with effect on the contents of the hit set work on version
attributes. These attributes are either standard attributes with a defined
meaning or user defined attributes. The following is a list of attribute names
recognized as standard attributes. All other names are considered to be user
defined attributes.
- alias
- Version alias name (symbolic version identification
name).
- atime
- The date of last access (read or write) to the versions
contents.
- author
- The version author in the form
username@domain.
- cachekey
- A unique key for cached versions built from the creation
date, the id of the creating process and a serial number (e.g.
740148430.18469.6).
- ctime
- The date of the last status change. This date is updated,
when an attribute is added or deleted, or an attribute value is
changed.
- generation
- The generation number. The value for this attribute is
plain numeric.
- host
- The name of the host from where the version was accessed.
This attribute may have different values at one time, when the version is
accessed from different hosts.
- locker
- The user who has set a lock on the concerned version. This
attribute has an empty value, when no lock is active. The attribute value
is given in the form username@domain.
- ltime
- The date of last lock change (set or give up update lock).
This has an empty value is empty, when there was never a lock set on the
version.
- mtime
- The date of the last modification of the versions
contents.
- name
- The name (without suffix) of the version. For example
foo for foo.c.
- owner
- The version owner in the form
username@domain.
- revision
- The revision number. As for generation, only numeric values
are accepted.
- size
- The size of the versions contents in bytes.
- status
- The version status. This is one of busy, saved, proposed,
published, accessed, or frozen.
- stime
- The save date. This attribute has an empty value for busy
versions.
- syspath
- The absolute pathname through which the version was
accessed. This attribute may have different values at one time, when the
version is accessed by different pathnames (e.g. symbolic links).
- type
- The suffix part of the versions name. For example fc
for foo.c.
- version
- The version number in the form generation.revision.
A special value is the string busy instead of a version number. As busy
versions have no version number, this value is used for identifying the
busy version of a history.
Some predicates (like
ge or
max) require an ordering relationship
between attribute values. For user defined attributes, ordering bases on
alphabetical (ASCII) comparison of the values. User defined attributes with
multiple values are compared by their first values, if these are identical by
their second values and so on. No value is considered smaller than any other
value. For example
attr1 = anton attr2 = berta
berta is smaller than anton
karl
but
attr1 = anton attr2 = anton
berta is bigger than berta
karl
For some of the standard attributes listed above, we need special
regulations.
- Version numbers (generation.revision)
-
are ordered by generation number first and revision number secondary
(e.g. 1.2 is smaller than 2.1). Busy is smaller than
any version number.
- Alias Names
-
are ordered by the version numbers (see above) of the identified
versions.
- Cache keys
-
are ordered by simple text comparison. This has the effect that the
youngest cache key is considered the biggest.
- Version states
-
are ordered in the sequence as listed above. Busy is the lowest
and frozen the highest state.
- User attributes
-
The order of user attributes bases on alphabetical comparison of the
string username@domain.
- Time attributes
-
Time comparison assumes older dates to be smaller than newer ones.
During evaluation of version bind rules, four different kinds of expansion are
possible. These are
parameter substitution,
attribute expansion,
external macro expansion and
command substitution. Expansion
happens, when a magic pattern is found in the rule text, starting with either
a dollar sign ($) or, in case of command substitution, with a backward quote
character (`).
Generally, expansion in version bind rules happens only within patterns and
within predicate arguments. Bind rule syntax or predicate names cannot be
introduced by substituted strings. Expansions outside patterns and predicate
arguments are ignored and usually lead to an error message.
A parameter substitution string is usually introduced by the pattern $_ followed
by the parameter name (an exception is $+ as shown below). The parameter name
is optionally delimited by a dollar sign. This is necessary, when there is no
whitespace character following. The parameter name may be any of the names
specified in the rule head or one of the following predefined names.
- $_rule$
- The current rule name.
- $_target$ or $+
- The current target file name to be bound.
- $_parameter$
- Any other parameter.
A parameter may have the same name as a citeable attribute (see below). In this
case, the parameter citation hides the attribute citation. There is no way to
cite the value of an attribute when there is an equally named rule parameter.
The reserved names rule, target, and hits are not allowed as parameter names.
An attribute expansion string looks exactly like a parameter substitution
string. It is introduced by the pattern $_ followed by the attribute name
which is optionally delimited by a dollar sign, when a non-whitespace
character follows immediately. Attribute names may be built of any printable
characters except '#'. Besides, it makes no sense to cite attributes with an
equal sign ('=') in the attribute name, as the Attributed Filesystem (AtFS)
doesn't allow this.
The value by which the attribute expansion string will be replaced depends on
the current state of processing. This may cause different values to be
inserted for the same citation in different processing states. Attribute
expansion happens as late as possible, it is done right before the evaluation
of the concerned pattern or predicate. With one exception, $_hits$, attribute
expansions will only be substituted, if the current hit set cardinality is 1.
- $_hits$ or $=
- The number of versions satisfying the binding conditions
expressed so far (the cardinality of the hit set). This value continuously
changes during rule evaluation.
- $_attribute$
- The value of any attribute of a uniquely selected
version.
Attribute citations may be overloaded by parameter citations (see above).
External macros are evaluated by an external macro processor. If no such macro
processor is available, external macros remain unchanged. They have the form:
- $C
- where C is any printable non-whitespace character except
'+', '=', '_', ':', or '#'
- $(macroName) or ${macroName}
- Macro names may not contain '#' characters. Other
limitations may be imposed by the external macro definition and processing
facility.
A command enclosed in back quotes occuring in a bind rule quotes will be
replaced by its output. No modifications are done to the command output, hence
it may contain newline characters.
There are some characters with special meaning when occurring in version bind
rules. These are the syntactical characters colon (:), comma, (,), semicolon
(;), period (.), and parentheses (( and )), the comment symbol (#), the dollar
sign ($) or the back quote (`) introducing expansion strings ($), quotes
(" and '), and the escape symbol (\).
Comments are handled somewhat rigorously. A comment symbol (#) occurring
anywhere in the rule name or rule body has effect as long as it is not escaped
by a backslash (\) character. Comments range from the comment symbol
(inclusive) to the end of the line. Newline characters within comments may
also be escaped by a backslash character, continuing the comment on the next
line.
Nesting of parentheses and quotes is not supported.
The following is a list of lexical constraints for each part of a version bind
rule.
- Rule names and rule parameters
- Rule names may consist of any printable non-whitespace
character except colon and parentheses. The leftmost colon or opening
parentheses delimits the rule name.
Rule parameter names follow the same lexical rule, but additionally must not
contain comma characters, as this in the delimiter between
parameters.
- Patterns
- In principle, name patterns may consist of any printable
character. Comma and semicolon characters occurring in a name pattern must
be escaped by a backslash character. A period occurring in a name pattern
needs not to be escaped as long as it is not the last character
(ignoring trailing whitespace) in the rule body. Period as last character
is always considered to be end of rule sign. Name patterns may
contain macro or parameter citations and command substitutions.
- Predicates
- Each predicate name must be one of the reserved names
listed previously in this paper. Predicate arguments consist of any
printable character including whitespace. Comma, parenthesis or quoting
characters must be escaped. Any argument may be quoted by single or double
quotes. Quoting exceeds line limits.
Predicate arguments may contain macro, attribute or parameter citations
leaded by a dollar sign, or command substitutions enclosed in back quotes.
When quoted in single quotes, dollar signs and back quotes occurring in a
predicate argument are not taken by their special meaning and no citations
happen. Double quotes do not hide citations.
Why doesn't the bind rule select version xyz although I think it
should ?. An important facility to find an answer to this question is
the
trace option provided by the
vbind(1) command. It shows the
evolution of the hit set during rule evaluation.
Typing errors in standard attribute names may lead to confusing situations. They
cannot be recognized by the evaluation machinery, as any unknown attribute
name is considered to be an user defined attribute.
A minus sign (-) as first character in an alternative is considered as part of
the pattern and not as (old style) cut operator. Hence
-; (- as pattern)
and
,-; (default pattern followed by cut)
make a big difference. We recommend the use of cut() in any case. The short form
(-) is supported only for compatibility with older versions.
bind_rule ::= bind_rule_head :[-] bind_rule_body .
bind_rule_head ::= rule_name | rule_name ( rule_arg_list ) .
rule_arg_list: rule_name { , arg_name }* .
bind_rule_body ::= attr_expression { ; attr_expression}* . .
attr_expression ::= name_pattern { , predicate }* |
predicate { , predicate }* | .
name_pattern ::= { <any printable character or whitespace> }+
predicate ::= attr_value_predicate ( attr_name , string ) |
attr_name_predicate ( attr_name ) |
bind_rule_predicate ( rule_name ) |
msg_predicate ( string ) |
msg_answer_predicate ( string , string ) |
cond_rule_predicate ( string , bind_rule_head ) |
cond_expr_predicate ( string , string ) |
cut_predicate.
attr_value_predicate ::= eq | ge | gt | le | lt | ne .
attr_name_predicate ::= hasattr | max | min .
bind_rule_predicate ::= bindrule .
msg_predicate ::= cut | msg .
msg_answer_predicate ::= confirm .
cond_rule_predicate ::= exists | existsnot | existsuniq .
cond_expr_predicate ::= condexpr .
cut_predicate ::= - .
attr_name ::= arg_name | author | atime | ctime | generation |
locker | ltime | mtime | owner |
revision | size | state | stime | version .
rule_name ::= { <any printable character except colon and parentheses }+ .
arg_name ::= { <any printable character except comma, colon and parentheses }+ .
string ::= { <any printable character or whitespace> } .
$SHAPETOOLS/BindRules
vbind(1),
vadm(1),
atnetwork(3),
shape(1)
[email protected]