Component Specification (Buckminster)
< To: Buckminster Project
A Component Specification (CSPEC) is a generic description of a component. It defines its dependencies to other components, what actions that can be performed on it and how those actions affect the dependencies. It also defines what artefacts the component can export to other components.
As an example; to perform an action such as compilation, certain assets must be available (the source of the component certainly, and header/interface files from components your component is using). Or put more formally: the requirements of an action must be fulfilled.
When you perform an action, such as a compilation, this may produce artefacts needed by other actions. Or put more formally: 'An action can produce artefacts that fulfill requirements of other actions.
Dependencies do not exist in a vacuum, the dependency always exists because some aspect of it is needed to perform a specific action. Or put more formally: There is always a purpose behind a component dependency
A cspec defines the following top-level elements:
An action is something that can be executed. It can have zero or many prerequisites where each prerequisite is either a local or external reference to a component attribute. A local reference appoints something that it is declared in the same CSPEC. An external reference appoints a public attribute in a CSPEC of another component via a dependency. The execution of an action will often produce new artifacts.
Purpose qualified dependency
DEPRECATED! A purpose is something that an action or export will use as a qualifier on a dependency to request a specific export in the appointed component. This concept has been replaced by Component Attribute.
The purpose says "I need this component in order to <purpose>". Here's an example:
Assume that we have three Java components, A, B, and C. A use classes present in B. B in turn use classes from C but hides this completely from A. When compiling A, a compiled version of B is needed but there's no need for C. When running A, clearly both B and C will be needed.
Object Oriented methodology tells us that it would be bad if A needs to know about the runtime dependency from B to C. It would be much better if A can say "I need B in order to compile" or "I need B in order to run" and B could answer, "You need me in order to run? Then I need to bring C along as well". The purpose qualified dependencies resolves this elegantly.
Artefact and derived components
A component will always contain at least one artefact. A source component from a CVS repository will always contain the artefact "source". This artefact is typically one single folder. Different actions such as "compile" or "archive" can produce new artefacts. It is often beneficial to store such artefacts in repositories and offer them as alternatives to the source when a component needs to resolve its dependencies. An FTP or HTTP based repository that stores pre-compiled binaries is a good example of this. In Buckminster terminology, such a binary is a derived component. It will contain a cspec similar to the one bundled with the original source pruned from the actions that produced the binary. The pruning will limit the component usage as well of course.
Since pruning removes actions and usages, some dependencies might end up purposeless. Such dependencies will be pruned too.
Buckminster allow artefacts to be variable. Variability is achieved through artefact attributes and by actions that can produce artefacts attributed in different ways. A trivial example of this is a compiler that can compile the same source, either stripped and optimized (distribution), or with symbols and not optimized (for debug purpose). Rather than having two artefacts and two actions (and two of every required artefact, etc.) attributes can be set in the outmost action, and these are propagated all the way.
A attribute can be set in the artefact declaration or stem from the action that produces the artefact. The initial artefact of a cspec is never variable since it does not stem from an action. The more derived an artefact is, the less variable it becomes. A pre-built binary is typically not variable at all.
If an artefact defines that an attribute stems from the producing action, then that action must somehow provide the attribute. It can do this either by declaring that it is the originator (such as a compiler using attributes to control command line options) or by propagating it to at least one of its required artefacts and/or dependencies. It may also add new attributes to its requirements and/or dependencies.
Names of actions and exports
Buckminster does not stipulate the names of artefacts and exports but here are some examples:
|java.sourcepath||no associated action, this is often an initial export.|
|java.compile||exports artefacts such as classes and external dependencies to other components with java.compile purpose.|
|unit.tests||exports artefacts needed when this component is participating in unit tests.|
|deployable.ear||exports a fully packaged ear file.|
|java.classpath||exports artefacts that contain information about where java binaries such as classes can be found. Also includes external dependencies to other components with java.classpath purpose.|
|eclipse.incremental.build||an internal action that maps to the execution of the eclipse incremental build.|
|build.javadocs||create java API documentation. This action will require its local source artefact and in many cases link to a java.source export of external components.|
|run.tests||the prerequisits for this action is that everything is compiled and deployed up to a point where tests can be run. The action will then start the tests.|
|deploy.ears||deploys ear files in a JEE container after all prerequisits have been fulfilled.|