1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
Property application specifications ("propspecs")
=================================================
Purposes
--------
Property application specifications are a domain-specific language which
enables
- combining properties to make new properties, e.g. with ``DEFPROPLIST``; and
- representing the properties which are to be applied to a host in a form
which can be serialised using the Lisp printer.
Definitions
-----------
An *atomic property application* ("propapp") is a list satisfying the lambda
list ``(PROPERTY &rest ARGS)`` where ``PROPERTY`` is a symbol naming a
property and ``ARGS`` satisfies that property's lambda list. A *property
combinator* is a function which takes at least one propapp as one of its
arguments and returns a single propapp, or a macro which takes at least one
form which evaluates to a propapp as one of its arguments, and returns a form
which evaluates to a single propapp. A *property application specification*
("propspec") is
i. a readably printable Lisp form;
ii. containing propapps combined using property combinators;
iii. containing no free variables except as bound by macro property
combinators, i.e., such that its evaluation is not affected by any
dynamic or lexical context;
iv. associated with a list of ASDF systems, and such that
v. evaluating the propspec produces an atomic property application which, when
those ASDF systems are loaded, applies the propapps in accordance with the
combinators.
An *unevaluated property application specification* ("unevaluated propspec")
is a list of Lisp forms which can be converted into a property application
specification by
i. replacing each argument in each propapp with the result of evaluating that
argument in the dynamic and lexical contexts in which the unevaluated
propspec occurs.
ii. wrapping a single property combinator which takes a variable number of
arguments around the resulting list of Lisp forms, usually ``SEQUENCE`` or
``ALL-OF``.
That is, the arguments to propapps in an unevaluated propspecs are forms which
will produce the arguments to the property, rather than those arguments
themselves. There is one special case: if the symbol naming the property ends
with the character ``.``, then the propapp is replaced with a new one
according to the following rules (the "dotted propapp rules"):
i. the property to be applied is the property named by the symbol in the same
package and with the same name as the first element of the propapp, but
with the trailing period removed from the name;
ii. the first argument is not evaluated if it is a list whose first element is
a keyword, or a if it is a list of lists where the first element of the
first list is a keyword; and
iii. the last argument is treated as an embedded unevaluated propspec, and is
recursively converted into a propspec according to the usual evaluation
rules, where the surrounding combinator is ``ALL-OF``.
Available combinators
---------------------
``ALL-OF``
~~~~~~~~~~
Function. Applies each of the propapps passed as arguments without stopping
if any of them signal a failed change. Semantically, the propapps are ordered
with respect to their ``:HOSTATTRS`` subroutines, but not with respect to
their ``:APPLY`` subroutines.
``SEQUENCE``
~~~~~~~~~~~~
Function. Applies each of the propapps passed as arguments, stopping and
signalling a failed change if any of the proapps signal a failed change.
Semantically, each propapp implicitly depends upon the preceding propapps.
``UNAPPLY``
~~~~~~~~~~~
Function. Unapplies a single propapp.
``ON-CHANGE``
~~~~~~~~~~~~~
Macro. Applies properties when attempting to apply the first did not return
``:NO-CHANGE``.
Remarks
-------
The conversion of an unevaluated propspec into a propspec must resolve any
free variable references, except where those will be resolved by macro
property combinators.
The ``PROPS`` macro converts an unevaluated propspec into a propspec.
The elements of unevaluated propspecs are typically arguments to macros, such
that the context of evaluation for forms which produce the arguments to the
propapps is the context in which the call to the containing macro appears.
The single property combinator which will be wrapped around the list of forms
depends on the macro. ``DEFHOST`` uses ``ALL-OF``, while ``DEFPROPLIST`` uses
``SEQUENCE``.
The dotted propapp rules are intended to make applications of properties like
``DEPLOYS``, ``DEPLOYS-THESE`` and ``CHROOT:DEBOOTSTRAPPED``, which take
property application specifications as arguments, easier to read and write in
the most common cases. For example, you can write::
(deploys. (:ssh (:sudo :as "spwhitton@athena.example.com")) athena.example.com
((additional-property val1)
(a-further-property val2)))
instead of::
(deploys '(:ssh (:sudo :as "spwhitton@athena.example.com")) athena.example.com
(make-propspec :props `((additional-property ,val1)
(a-further-property ,val2))))
(though note the parentheses around the two propapps must remain, unlike in
``DEPLOY``, ``DEFHOST`` etc.).
|