[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [buckminster-dev] Action properties [WAS Action output?]
|
Kenneth Ölwing wrote:
Generally speaking I'm feeling we're continually speaking past each
other. My gripe isn't really hooked up to how variability should work or
not or inherited props or a lot of the other stuff we seem to drift
into. I describe a use-case that as things work today will yield a
behavior I consider wrong. Nothing more, nothing less. I try to detail
that last.
The reason I brought variability into the discussion was to highlight that my example where
I invented the requirement properties was in conflict with it and hence, a bad idea.
The dependency chain still exists. A doesn't know about C. But A now
happens to use a 'coolselector' and when a user is attempting to set it
for A, unwittingly we have a problem. Yes, A could change and not use
coolselector as a name. But that still isn't always possible: 1) removal
of that name might for some reason cause untold grief downstream making
A very reluctant to change it, or, perhaps more probable, 2) shift the
dependency chain a bit - Z is now the changeable part and it depends on
an unchangeable A which *implicitly* depends on C through B. No one has
up to now even seen the problem but it suddenly surfaces.
Farfetched? Hmm, not really - it's a boundary condition, but a valid
outcome with the type of support we're discussing (unless we take steps
now to prevent this type of unintentional problems).
I think that if B uses C, then B must either hide (by redirecting or some other mechanism
that we don't have yet) or declare the properties in use by C. In other words, the fact that
C uses a coolselector property should not come as an unpleasant surprise to users of B. The
B documentation should state that B makes use of a coolselector since, technically, it does.
The fact that the use is implicit through C is irrelevant.
What 'global' properties are you talking about? I'm guessing that it is
the set generated by Buckminster for pointing to the home (and where we
started, the output root) etc. If so, that is not overlaid, quite the
contrary. Or, perhaps you're referring to what I below call 'runtime
properties'. If so, it is used to overlay, not be overlaid. Anything
else is not there right now?
I was thinking about the latter, and yes you're right, they are overlying.
Starting from the most outward point: IPerformManage.perform(). Into
this we can pass a list of component/action pairs, right? (doing so will
currently yield an NotImplementedYetException, but but let's assume it
is implemented).
The second thing we pass in is a *single* set of properties. This is
frequently empty, but with a command line (or its UI 'equivalent') of
'perform -D foo=bar C1#A C2#B' the set will contain the single pair of
foo=bar, correct? Let's call this set the 'runtime properties'.
Let's assume that component 1 (C1) and 2 (C2) are two top components to
two completely separate chains. Assume that both the A and B action use
the 'ant' actor.
Eventually the actor for A will get called with the runtime properties
in the perform context.
Among all the things the Ant actor code does (and we have already
established that this should really be moved to a more general place,
but that is beside the point right now) is to:
1) populate an empty map with any properties defined in the cspec for
that action
2) It then populates the same map with the runtime properties (so this
overlays any 'foo=...' that was present in the cspec)
3) Finally, we overlay the map with a number of Buckminster generated
properties (we do this last specifically so they can't be overridden).
(somewhere in all this is where inherited properties might come in etc
etc, but it doesn't change the issue)
The final map is now reflected in the Ant build script for A, and
presumably the script makes references using '${foo}'.
All good. But eventually the PerformManager code will start the B
action. And here's the whole point: *any* action (and actor) invoked,
including dependencies to A and B, will get a copy of the same runtime
properties. I think this is wrong - it does not give isolation. At best
it's completely benign (B doesn't care about 'foo' one way or another),
at worst B get's hopelessly confused by the content of foo. There's no
way to solve this by declaring anything in A since they are not in the
same chain. Your argument might be 'well, so invoke A and B in separate
perform calls'. Sure - but then we should forbid the usage I describe,
it isn't forbidden now.
The outermost interface simply doesn't give us a way to pass in multiple
runtime properties appropriate for the multiple given actions. I think
it should. That would make it completely possible to call A with one
set, appropriate for it, and B with another set, appropriate for that.
No possible 'leakage' between them. In general, all other property
interaction between actions is controlled by all the fancy rules of
inheritance, variability etc. The downside is of course that the
headless command must allow for expressing all this...
It's debatable whether it should be possible to inject runtime props to
actions not specifically listed in the call (i.e. for actions called as
a result of dependencies).
There is obviously solutions to all this, but everything has a benefit
and a drawback. We need to select the design, and then work with the
consequences.
OK. I see your point (or points :-) ). How about the following:
1. The runtime properties are immutable so there's no way the chain of actor execution can
change them. Every actor can *trust* that what they see is what's been defined by the
invoker of the perform command. This can be regarded as a good thing and it's often very useful.
Example: I user -Dbuild.id=<some generated id> to give all actors an id that they can use in
order to brand their respective products.
2. If I invoke action 'A', it's likely that I know about the properties of that action
although I might have limited or no knowledge about its dependencies and actions that will
get implicitly invoked. In many cases I don't *want* to know about that. All I care about is
'A'. As you point out, passing properties intended for one single action using a global
scope has some problematic implications. We need a way to tie a property to a specific
action. An easy way to do that is perhaps to just use action qualified property names.
Example: The component Z action 'rippage' needs a specific URL. So I use
-DZ#rippage!flmbrry.url=http://www.foo.org.
I thereby state that an overlay with the property flmbrry.url=http://www.foo.org must be
added whenever the Z#rippage action is executed (directly or implicitly). This overlay is
explicit for such invocations and cannot be seen by other actions. I will still be able to
use the global scope and write just -Dflmbrry.url=http://www.foo.org and it's quite possible
that it will yield the same result but there's some risk involved when doing that.
3. There is only one way to unintentionally 'confuse' an action with a property setting and
that is if you inadvertently override some property that that action make use of. In order
to prevent that from happening, perhaps our actions should have a way to declare immutable
properties? Something like:
<property name="fee" value"fum" mutable="false"/>
The default is of course mutable="true"
Thoughs?
- thomas