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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
# Tree Overlays
The underlying idea of a tree object is that it is an opaque object,
that can be passed around as a single artifact. Trees can be obtained
as a directory output of an action or as explicit reference to a
source directory. Using a tree rather than a collection of individual
files can be useful for reserving a whole directory for headers
for a particular library in order to avoid future conflicts, or if
the individual outputs of an action are not known in advance. The
latter happens often when calling foreign build systems to build
a third-party library or even toolchain; still, usually those
outputs can be used as opaque trees using appropriate staging.
There are, however, a few examples where opaque trees have to be
combined into a single one, e.g., if there is an external requirement
that certain files be staged flatly in a single directory.
To also support those rare use cases, `just` supports in-memory
actions to compute the overlay of two trees, optionally rejecting
conflicts instead of resolving them in a latest-wins way. Those
actions can be requested in user-defined rules, as well as by the
built-in rules `tree_overlay` and `disjoint_tree_overlay` (where
the latter causes a build error if the trees cannot be overlayed
in a conflict-free way).
Here we demonstrate the way these rules work on an artificial
example which we start from scratch.
``` sh
$ touch ROOT
```
We simply work locally, so our `repos.json` is trivial.
``` {.jsonc srcname="repos.json"}
{"repositories": {"": {"repository": {"type": "file", "path": "."}}}}
```
As a replacement for a foreign-build-system call, consider a target
having a single tree artifact as output, with contents heavily
depending on the configuration.
``` {.jsonc srcname="TARGETS"}
{ "foo":
{ "type": "generic"
, "arguments_config": ["FOO_BINS"]
, "out_dirs": ["bin"]
, "cmds":
[ "mkdir -p bin"
, { "type": "join"
, "$1":
[ "for tool in "
, {"type": "join_cmd", "$1": {"type": "var", "name": "FOO_BINS"}}
, " ; do echo \"foo binary ${tool}\" > bin/\"${tool}\""
, " ; chmod 755 bin/\"${tool}\""
, " ; done"
]
}
]
}
}
```
So, depending on the configuration the output tree has different entries.
``` sh
$ just-mr build -D '{"FOO_BINS": ["version", "upload", "download"]}' -p foo
INFO: Performing repositories setup
INFO: Found 1 repositories involved
INFO: Setup finished, exec ["just","build","-C","...","-D","{\"FOO_BINS\": [\"version\", \"upload\", \"download\"]}","-p"]
INFO: Requested target is [["@","","","foo"],{"FOO_BINS":["version","upload","download"]}]
INFO: Analysed target [["@","","","foo"],{"FOO_BINS":["version","upload","download"]}]
INFO: Discovered 1 actions, 0 tree overlays, 0 trees, 0 blobs
INFO: Building [["@","","","foo"],{"FOO_BINS":["version","upload","download"]}].
INFO: Processed 1 actions, 0 cache hits.
INFO: Artifacts built, logical paths are:
bin [8cd3ecc03f0ba26d9e104e52b40f88a0bc5a84b9:105:t]
{
"download": "[f270834a3411ba7d9e6fab59a8d93e1fbd6e55a3::x]",
"upload": "[af38d5c40e8828c67d0031fce42da86b68f56182::x]",
"version": "[a263fff2a3b94429878303875861fd93bcdbe248::x]"
}
$ just-mr build -D '{"FOO_BINS": ["version", "ci", "co", "rlog"]}' -p foo
...
INFO: Processed 1 actions, 0 cache hits.
INFO: Artifacts built, logical paths are:
bin [eaee8451fe929904016b73c73f466f534e248c3d:127:t]
{
"ci": "[eb8e3ec5baca0f16da7fe8b200181bde123c11bf::x]",
"co": "[1cb77df2638381460b338882e2942b3eb0a09975::x]",
"rlog": "[157a0fca577e8717d68920f76a998ab1b398594d::x]",
"version": "[a263fff2a3b94429878303875861fd93bcdbe248::x]"
}
```
Now, assume we have another such target.
``` {.jsonc srcname="TARGETS"}
...
, "bar":
{ "type": "generic"
, "arguments_config": ["BAR_BINS"]
, "out_dirs": ["bin"]
, "cmds":
[ "mkdir -p bin"
, { "type": "join"
, "$1":
[ "for tool in "
, {"type": "join_cmd", "$1": {"type": "var", "name": "BAR_BINS"}}
, " ; do echo \"bar binary ${tool}\" > bin/\"${tool}\""
, " ; chmod 755 bin/\"${tool}\""
, " ; done"
]
}
]
}
...
```
Both targets produce a tree `bin` instead of a collection of files
within the directory `bin`. Therefore, an overlay at analysis time
could only result in one or the other directory. However, we overlay
the results at build time.
``` {.jsonc srcname="TARGETS"}
...
, "both": {"type": "tree_overlay", "deps": ["foo", "bar"]}
, "both-noconflict": {"type": "disjoint_tree_overlay", "deps": ["foo", "bar"]}
...
```
If the entries do not conflict, in both cases, we get the union of the files.
``` sh
$ just-mr build -D '{"FOO_BINS": ["ci", "co"], "BAR_BINS": ["up", "down"]}' -P bin both
...
INFO: Processed 2 actions, 0 cache hits.
INFO: Artifacts built, logical paths are:
[98e5f0eed05bf887a6c9df7616b7d83323acf677:30:t]
INFO: 'bin' not a direct logical path of the specified target; will take subobject 'bin' of ''
{
"ci": "[eb8e3ec5baca0f16da7fe8b200181bde123c11bf::x]",
"co": "[1cb77df2638381460b338882e2942b3eb0a09975::x]",
"down": "[53aa524d39aff972c976bfd729a3fd26c5d364fd::x]",
"up": "[3bfadc230e82da61f056e1d9acd854298f0b19c3::x]"
}
$ just-mr build -D '{"FOO_BINS": ["ci", "co"], "BAR_BINS": ["up", "down"]}' -P bin both-noconflict
...
INFO: Processed 2 actions, 2 cache hits.
INFO: Artifacts built, logical paths are:
[98e5f0eed05bf887a6c9df7616b7d83323acf677:30:t]
INFO: 'bin' not a direct logical path of the specified target; will take subobject 'bin' of ''
{
"ci": "[eb8e3ec5baca0f16da7fe8b200181bde123c11bf::x]",
"co": "[1cb77df2638381460b338882e2942b3eb0a09975::x]",
"down": "[53aa524d39aff972c976bfd729a3fd26c5d364fd::x]",
"up": "[3bfadc230e82da61f056e1d9acd854298f0b19c3::x]"
}
```
In case of a conflict, however, the targets differ. The first one, `both`, will
overlay the files in a latest-wins fashion, whereas the second will fail when
handling the overlay action.
``` sh
$ just-mr build -D '{"FOO_BINS": ["version", "ci", "co"], "BAR_BINS": ["version", "up", "down"]}' -P bin/version both
...
INFO: Processed 2 actions, 0 cache hits.
INFO: Artifacts built, logical paths are:
[2a26b3dc1774df55eb1f1d9a865611a413204ab2:30:t]
INFO: 'bin/version' not a direct logical path of the specified target; will take subobject 'bin/version' of ''
bar binary version
$ just-mr build -D '{"FOO_BINS": ["version", "ci", "co"], "BAR_BINS": ["version", "up", "down"]}' both-noconflict || :
INFO: Performing repositories setup
INFO: Found 1 repositories involved
INFO: Setup finished, exec ["just","build","-C","...","-D","{\"FOO_BINS\": [\"version\", \"ci\", \"co\"], \"BAR_BINS\": [\"version\", \"up\", \"down\"]}","both-noconflict"]
INFO: Requested target is [["@","","","both-noconflict"],{"BAR_BINS":["version","up","down"],"FOO_BINS":["version","ci","co"]}]
INFO: Analysed target [["@","","","both-noconflict"],{"BAR_BINS":["version","up","down"],"FOO_BINS":["version","ci","co"]}]
INFO: Discovered 2 actions, 1 tree overlays, 2 trees, 0 blobs
INFO: Building [["@","","","both-noconflict"],{"BAR_BINS":["version","up","down"],"FOO_BINS":["version","ci","co"]}].
ERROR (action:aec6a6e881d3c3884420bee1330fbe9702ad3a7af11ee7f21fb59f88d6ba8f38):
Tree-overlay computation failed:
While merging the trees:
- [394c2bd3bf4a07f8e22f6e73c2adcb03f28349df:30:t]
- [e83b879ac94530f49855004138ea96df758b14d1:30:t]
While merging the trees:
- [7a5ed39406620e7b844788589f92fa4c17361c19:0:t]
- [28891f0d46f5053861ac36bc7da18285e65ed267:0:t]
Naming conflict detected at path "version":
- [a263fff2a3b94429878303875861fd93bcdbe248:0:x]
- [e9ebc93e1f91db5fab1fde7d22d8c6f59afab9f1:0:x]
ERROR (action:aec6a6e881d3c3884420bee1330fbe9702ad3a7af11ee7f21fb59f88d6ba8f38):
Failed to execute tree-overlay action.
requested by
- [["@","","","both-noconflict"],{"BAR_BINS":["version","up","down"],"FOO_BINS":["version","ci","co"]}]#0
inputs were
- 394c2bd3bf4a07f8e22f6e73c2adcb03f28349df:30:t
- e83b879ac94530f49855004138ea96df758b14d1:30:t
ERROR: Build failed.
```
|