summaryrefslogtreecommitdiff
path: root/doc/tutorial
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2025-03-05 16:58:09 +0100
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2025-03-06 13:44:29 +0100
commit3ebf005554d3169634e1495e844c576d4b9e76ae (patch)
tree0231eecae7d81399ee50fc525c1b73efa9be6be5 /doc/tutorial
parent91b9a0412c9e91f620a187354bfcc45df4b74279 (diff)
downloadjustbuild-3ebf005554d3169634e1495e844c576d4b9e76ae.tar.gz
tutorial: Add chapter on just-lock
Also update the README.
Diffstat (limited to 'doc/tutorial')
-rw-r--r--doc/tutorial/just-lock.md236
1 files changed, 236 insertions, 0 deletions
diff --git a/doc/tutorial/just-lock.md b/doc/tutorial/just-lock.md
new file mode 100644
index 00000000..03a65063
--- /dev/null
+++ b/doc/tutorial/just-lock.md
@@ -0,0 +1,236 @@
+Multi-repository configuration management: `just-lock`
+======================================================
+
+The multi-repository build configuration used as input by `just-mr` acts for
+all intents and purposes as a _lockfile_ for *justbuild* projects, containing
+the pinned versions of all content-fixed repositories. This is expected to be
+stored and shipped together with the source code, allowing a consistent
+development environment for all users.
+
+With dependencies of projects coming in many shapes and forms, `just-lock` is
+a tool for generating and maintaining the multi-repositories configuration
+(lock)file of *justbuild* projects. This tool performs several functionalities,
+such as importing dependencies with repository composition (extending the
+functionality available in the `just-import-git` tool), automatic deduplication
+of identical transitive dependencies (a functionality available also standalone
+in the `just-deduplicate-repos` tool), or setup of repository clones for local
+development. For the purposes of this tutorial, we will focus only on the
+dependency import aspects.
+
+Basic use of `just-lock`
+------------------------
+
+In order to produce the multi-repository build configuration file, `just-lock`
+expects an input configuration file. The format of this file is an extension of
+the one of `just-mr` and it is read as a `JSON` object. The file defines four
+elements:
+
+ - the description of local repositories, as the value for mandatory field
+ `"repositories"`. This usually defines local checkouts, patches, overlays.
+ - the description of remote dependencies, as the optional value for field
+ `"imports"`. For *justbuild* dependencies, their multi-repository configuration
+ (lock)file is taken as the ground truth for importing repository descriptions
+ into the current project. Non-*justbuild* dependencies can also be described
+ here, but can only be imported as-is, with overlays defining how such source
+ code should be integrated (as it will be shown below).
+ - the repository to consider as the main entry point for the build, as the
+ value of the optional field `"main"`.
+ - a list of repository names, as the value of the field `"keep"`. These names
+ will be kept in the final configuration during the automatic process of
+ deduplicating any repeated repositories brought in as transitive dependencies
+ from different imports. For the purposes of this tutorial, the use of this
+ field is not exemplified.
+
+### The input file
+
+For the following, we return to the *hello_world* example from the section on
+[*Building Third-party dependencies*](./third-party-software.md), which depends
+on the open-source project [fmtlib](https://github.com/fmtlib/fmt), in the
+setup that enables high-level target caching.
+
+We define the following `repos.in.json` input configuration file for
+`just-lock`:
+
+``` {.jsonc srcname="repos.in.json"}
+{ "main": "tutorial"
+, "repositories":
+ { "rules-cc":
+ { "repository": "rules-cc-rules-sources"
+ , "target_root": "tutorial-defaults"
+ , "rule_root": "rules-cc"
+ }
+ , "tutorial":
+ { "repository": {"type": "file", "path": "."}
+ , "bindings": {"rules": "rules-cc", "format": "fmtlib"}
+ }
+ , "tutorial-defaults":
+ { "repository":
+ { "type": "file"
+ , "path": "./tutorial-defaults"
+ , "pragma": {"to_git": true}
+ }
+ }
+ , "fmt-targets-layer":
+ { "repository":
+ { "type": "file"
+ , "path": "./fmt-layer"
+ , "pragma": {"to_git": true}
+ }
+ }
+ , "fmtlib":
+ { "repository": "fmtlib-sources"
+ , "target_root": "fmt-targets-layer"
+ , "bindings": {"rules": "rules-cc"}
+ }
+ }
+, "imports":
+ [ { "source": "git"
+ , "branch": "master"
+ , "commit": "3a5f0f0f50c59495ffc3b198df59e6edb8416450"
+ , "url": "https://github.com/just-buildsystem/rules-cc.git"
+ , "repos": [{"alias": "rules-cc-rules-sources", "repo": "rules"}]
+ }
+ , { "source": "git"
+ , "branch": "8.1.1"
+ , "url": "https://github.com/fmtlib/fmt.git"
+ , "repos": [{"alias": "fmtlib-sources"}]
+ , "as plain": true
+ }
+ ]
+}
+```
+
+As already mentioned, the `"imports"` field provides a description of the
+external (usually third-party) dependencies of a project. In our case, we
+use the `rules-cc` and `fmtlib` libraries, described as `git` sources.
+
+The first thing to note is the use of overlays. In our simple project, as we
+do not want to import anything other than the source trees of the needed
+dependencies, we create the `"rules-cc-rules-sources"` and `"fmtlib-sources"`
+names, which will bind the workspace roots of our `"rules-cc"` and `"fmtlib"`
+repositories, respectively, to the descriptions of the remote repositories
+providing the necessary source trees.
+
+The first import description object is for `rules-cc`, which is a *justbuild*
+project hosted as a Git repository, from which we would like to import its
+`"rules"` subdirectory. Thankfully, that project offers a useful shorthand by
+defining in its own locked repositories configuration file the `"rules"` overlay
+repository pointing to the respective subdirectory. `just-lock` will read that
+configuration file in order to produce the resulting configuration, caching any
+fetched source trees. It is thus highly recommended that the same build root as
+the one subsequently used by `just-mr` is provided to `just-lock` (via the
+`--local-build-root` option, with same default behaviour as in `just-mr`).
+
+In the case of `fmtib`, which is also hosted as a Git repository but does not
+provide a *justbuild* configuration file, we can only import it as-is, as a
+complete repository, signaled by setting the `"as plain"` flag. Do note that in
+this case we can limit ourselves to also just providing the `"branch"` field,
+and not also a specific commit. This is because `just-lock` automatically
+interrogates the remote in order to retrieve the top commit associated to a
+certain reference (in this case, a release tag) and pin it to a hard reference
+(in this case, the commit identifier) into the output configuration. This is a
+useful feature, as it is often the case that information about dependencies
+comes in the form of "loose" references, such as release tags or even simply the
+remote location of a distfile, but which `just-lock` then will pin down to a
+content-defined reference, such as a commit, blob, or tree identifier.
+
+### Generating the configuration
+
+We generate an output configuration file `repos.out.json` by running `just-lock`
+with the appropriate arguments, then we build the `helloworld` target with this
+configuration:
+
+``` sh
+$ just-lock -C repos.in.json -o repos.out.json
+[...]
+$
+$ just-mr -C repos.out.json build helloworld
+INFO: Performing repositories setup
+INFO: Found 5 repositories to set up
+INFO: Setup finished, exec ["just","build","-C","...","helloworld"]
+INFO: Requested target is [["@","tutorial","","helloworld"],{}]
+INFO: Analysed target [["@","tutorial","","helloworld"],{}]
+INFO: Export targets found: 1 cached, 0 uncached, 0 not eligible for caching
+INFO: Discovered 4 actions, 2 trees, 0 blobs
+INFO: Building [["@","tutorial","","helloworld"],{}].
+INFO: Processed 4 actions, 4 cache hits.
+INFO: Artifacts built, logical paths are:
+ helloworld [18d25e828a0176cef6fb029bfd83e1862712ec87:132736:x]
+$
+```
+
+As it can be seen, everything comes from cache and the new configuration behaves
+identical to the manually written one. If available, one can inspect the
+difference in content between the two files using the `jq` command-line tool:
+
+``` sh
+$ diff -y <(jq --sort-keys . repos.out.json) <(jq --sort-keys . repos.json)
+{ {
+ "main": "tutorial", "main": "tutorial",
+ "repositories": { "repositories": {
+ "fmt-targets-layer": { "fmt-targets-layer": {
+ "repository": { "repository": {
+ "path": "./fmt-layer", "path": "./fmt-layer",
+ "pragma": { "pragma": {
+ "to_git": true "to_git": true
+ }, },
+ "type": "file" "type": "file"
+ } }
+ }, },
+ "fmtlib": { "fmtlib": {
+ "bindings": { "bindings": {
+ "rules": "rules-cc" "rules": "rules-cc"
+ }, },
+ "repository": "fmtlib-sources", <
+ "target_root": "fmt-targets-layer" <
+ }, <
+ "fmtlib-sources": { <
+ "repository": { "repository": {
+ "branch": "8.1.1", "branch": "8.1.1",
+ "commit": "b6f4ceaed0a0a24ccf575fab6c56dd50ccf6f1a9", "commit": "b6f4ceaed0a0a24ccf575fab6c56dd50ccf6f1a9",
+ "repository": "https://github.com/fmtlib/fmt.git", "repository": "https://github.com/fmtlib/fmt.git",
+ "type": "git" "type": "git"
+ } | },
+ > "target_root": "fmt-targets-layer"
+ }, },
+ "rules-cc": { "rules-cc": {
+ "repository": "rules-cc-rules-sources", <
+ "rule_root": "rules-cc", <
+ "target_root": "tutorial-defaults" <
+ }, <
+ "rules-cc-rules-sources": { <
+ "repository": { "repository": {
+ "branch": "master", "branch": "master",
+ "commit": "3a5f0f0f50c59495ffc3b198df59e6edb8416450", "commit": "3a5f0f0f50c59495ffc3b198df59e6edb8416450",
+ "repository": "https://github.com/just-buildsystem/ru "repository": "https://github.com/just-buildsystem/ru
+ "subdir": "rules", "subdir": "rules",
+ "type": "git" "type": "git"
+ } | },
+ > "rule_root": "rules-cc",
+ > "target_root": "tutorial-defaults"
+ }, },
+ "tutorial": { "tutorial": {
+ "bindings": { "bindings": {
+ "format": "fmtlib", "format": "fmtlib",
+ "rules": "rules-cc" "rules": "rules-cc"
+ }, },
+ "repository": { "repository": {
+ "path": ".", "path": ".",
+ "type": "file" "type": "file"
+ } }
+ }, },
+ "tutorial-defaults": { "tutorial-defaults": {
+ "repository": { "repository": {
+ "path": "./tutorial-defaults", "path": "./tutorial-defaults",
+ "pragma": { "pragma": {
+ "to_git": true "to_git": true
+ }, },
+ "type": "file" "type": "file"
+ } }
+ } }
+ } }
+} }
+```
+
+Except for the two overlays, kept from the `just-lock` input file configuration,
+the two configuration files have the same content.