lal is a simple command line tool that works on folders with a valid manifest.json, and accepts the following commands:
lal fetch- fetch dependencies frommanifest.jsonintoINPUTlal update- update arbitrary dependencies intoINPUTlal status- print current INPUT dependencies with originlal verify- verify manifest validity + verify flat lockfile dependency treelal env- control build environmentlal build [name]- run canonical build in docker with current directory mountedlal shell- enter container environment mounting current directorylal run- runs a non-build script through lal shelllal configure- generate configuration filelal init- generate manifest filelal stash- copies currentOUTPUTto cachelal upgrade- performs an upgrade checklal clean- cleans up cache directorylal export- obtain a raw tarball from artifactorylal query- list versions of a component on artifactorylal remove- remove components fromINPUTandmanifest.jsonlal publish- publish release builds to artifactorylal propagate- works out steps to propagate dependencies
A per-repo file. Format looks like this (here annotated with illegal comments):
{
"name": "libwebsockets", // name of repo
"environment": "centos", // name of environment found in the lal config
"supportedEnvironments": ["centos", "xenial"],
"components": { // map of components and default configuration
"libwebsockets": {
"defaultConfig": "release",
"configurations": ["release", "clang"]
},
"websockets_tests": {
"defaultConfig": "coverage",
"configurations": ["coverage", "release", "clang"]
}
},
"dependencies": {
"ciscossl": 42
},
"devDependencies": {
"gtest": 42
}
}A per-build file auto-generated by lal build and will reduce the lockfiles generated from dependencies to provide aggregated information.
{
"name": "edonus",
"config": "release",
"container": {
"name": "edonusdevelopers/centos_build",
"tag": "2016-04-03"
},
"environment": "centos",
"tool": "0.10.0", // from `lal --version`
"version": "5", // from --with-version or "EXPERIMENTAL-{randomhex}"
"sha": "0ee0ee225d107076ed4b00368805d987baac9c4d", // from --with-sha
"dependencies": {
"libwebsockets": {
"name": "libwebsockets",
"config": "release",
"container": {
"name": "edonusdevelopers/centos_build",
"tag": "2016-04-03"
},
"environment": "centos",
"version": "47",
"tool": "0.10.0",
"dependencies": {
"ciscossl": {
"name": "ciscossl",
"config": "release",
"container": {
"name": "edonusdevelopers/centos_build",
"tag": "2016-04-03"
},
"environment": "centos",
"version": "200",
"tool": "0.10.0",
"dependencies": {}
}
}
},
"ciscossl": {
"name": "ciscossl",
"config": "release",
"container": {
"name": "edonusdevelopers/centos_build",
"tag": "2016-04-03"
},
"environment": "centos",
"version": "200",
"tool": "0.10.0",
"dependencies": {}
}
}
}This struct is fully recursive in the sense that every value in the dependencies hash is also a valid lockfile.
A per-machine configuration file in ~/.lal/config generated by lal configure. This is an example of environments, artifactory settings and mounts for a hypothetical edonus team.
{
"artifactory": {
"server": "https://engci-maven-master.cisco.com/artifactory",
"group": "CME-release",
"vgroup": "https://engci-maven.cisco.com/artifactory/CME-group"
},
"cache": "/home/devuser/.lal/cache",
"environments": {
"centos": { "container": "edonusdevelopers/centos_build", "tag": "latest" },
"xenial": { "container": "edonusdevelopers/build_xenial", "tag": "latest" }
},
"upgradeCheck": "2016-06-30T12:20:10.126707483+00:00",
"mounts": [
{
"src": "/mnt/tools",
"dest": "/tools",
"readonly": true
}
]
}Every repository is required to specify the name of one of the specified environments in their manifest.json.
The upgradeCheck value is updated automatically by lal upgrade.
A per-repo temporary file primarily for lal env that overrides the current environment.
{
"env": "xenial"
}When this file exists, every lal command will use this environment rather than the default one. It is created by lal-env.
This file is intended to be gitignored because it overrides manifest.environment.
The local cache is populated by fetches from the registry, or calls to stash them.
~/.lal/cache $ tree .
├── environments
│ ├── centos
│ │ └── ciscossl
│ │ └── 6
│ │ └── ciscossl.tar.gz
│ └── xenial
│ └── ciscossl
│ └── 6
│ └── ciscossl.tar.gz
└── stash
└── ciscossl
└── asan
└── ciscossl.tar.gzSources:
environmentsare components from the registry under a specific environment namespacestashare tarballs of OUTPUT of builds when doinglal stash <name>
As implied by the structure of the Manifest, Lockfile, and cache directories, the only versioning scheme supported by lal is a monotonically increasing integer sequence.
Provides list of dependencies currently in INPUT.
If they are not in the manifest they will be listed as extraneous.
If they are stashed dependencies they will be listed in yellow origin
Extra flags:
--fullor-f: print the full dependency tree--originor-o: print version and environment origin of artifact--timeor-t: print build time of artifact
Alias: lal ls
Subcommand that controls the current environment. This is a sticky, repo-wide setting stored in $PWD/.lal/opts when working with non-standard environments.
$ lal env
xenial
# every lal command will defer the environments key in `manifest.json` by default
$ lal env set zesty # writes { "environment": "zesty" } to .lal/opts
$ lal env update # invokes docker pull of the zesty image
# now every lal command will warn if `manifest.environment != lal env`
$ lal fetch # fetches from zesty
$ lal build # build using zesty components
$ lal shell # enters zesty shell
$ lal run unit-test websocket_server_test 5 asan # runs unit test in zesty shell
$ lal env reset # deletes `.lal/opts` if it exists
# lal now behaves as usual, doing all commands in the described environment in manifest.jsonThis is an advanced command for people developing on temporary, non-standard environments. If you would like to override the environment on a command-by-command basis, there is an option for that as well.
Runs the BUILD script in the current directory in the container.
If no arguments are suppplied it will run ./BUILD $name $config where name is the value of name in the manifest, and config is the name of the component's defaultConfig.
E.g. lal build in say a gtest repo will probably call ./BUILD gtest release in the container.
lal build will run lal verify and abort if this fails. When using stashed components, you should build with --simple-verify or -s for short. This will allow stashed versions to pass, but still not cripple the verifier so that you accidentally include things built in different environments.
Any further verify blocks can be overridden with -f or --force. There are very few legit developer reasons why you would want to completely ignore lal verify, but maybe you have such a special case.
Release specific flags:
- --release: Generate a tarball and lockfile in
./ARTIFACTfolder after building - --with-version n: Jenkins specific option which will specify lockfile version
- --with-sha str: Jenkins specific option which will set revision id
Typically jenkins would do:
lal build --release --with-version=$BUILD_NUMBER --with-sha=$(git rev-parse HEAD)And publish that with lal publish.
Passing configuration flags:
- --config=name: Passes a named config to
BUILDas$2.
This allows multiple blessed configurations of the same component, i.e. lal build dme-unit-tests --config=asan and lal build dme-unit-tests --config=debug. Both are valid provided dme-unit-tests provides those configurations in the components part of the manifest.
Find the latest available version of a component that is available in all currently supportedEnvironments from the manifest.
-
lal update component [--save]: fetches the latest version of a component. The optional
--saveflag will also update the manifest file locally. -
lal update component=version [--save]: fetches a specific version. If the version is parsable as an integer, it is fetched from artifactory. Otherwise, it is assumed to be a stashed version.
Many component or component=version arguments can be used in one invocation.
- lal fetch [--core]: fetches all versions corresponding to the manifest from the registry and puts them into
INPUT. The optional--coreflag will disregard anydevDependencies.
Any components already found in INPUT are reused if they are present at the right version and correct environment.
Any extraneous versions found in INPUT are removed.
Enters an interactive shell in the container corresponding to the environment key in the manifest mounting the current directory.
Useful for experimental builds using internal scripts in a repo.
Assumes you have run lal fetch or equivalent so that INPUT is ready for this.
lal shell should basically run:
docker run \
-v $PWD:/home/lal/volume \
-w /home/lal/volume \
--user lal \
-it ${SOME_CONTAINER} \
/bin/bashNote that the config can be edited to pass in extra mounts.
lal shell should allow passing in trailing arguments to run arbitrary commands:
lal shell ./BUILD something# runs this command rather than/bin/bashand removes-ilal shell -p ./BUILD something# same, but adds --privileged todockerlal shell bash -c "cmd1; cmd2"# multiple commands in one golal shell --print-onlyprints above commandlal shell --print-only ./BUILD something# prints what would have been done
lal shell should also allow making it easy to forward the X11 socket:
lal shell -X# mounts/tmp/.X11-unix,~/.Xauthorityand forwards theDISPLAYevar
Host networking should be convenience flag:
lal shell -n# passes--net=hostto docker.
A combination of these two flags allows forwarding X through ssh and lal:
ssh -X somemachine # ssh with X11 forwarding
lal sh -X -n xcalc # run xcalc and forward X11 all the way through sshThe X11 forwarding setup requires xhost installed, and also xauth installed if you need it through ssh as well. You may need to run xhost local:docker to allow docker to access X.
Alias: lal sh
Runs scripts in the local .lal/scripts/ folder via lal shell. Because lal shell mounts $PWD, the scripts folder can contain parametrised scripts such as:
#!/bin/bash
# contents of .lal/scripts/subroutine
main() {
echo "hi $1 $2"
}
completer() {
echo "foo bar"
}Which could be invoked with lal run subroutine there mr, which would echo hi there mr in the container. An optional completer function can be supplied for autocomplete of values.
Alias: lal script
Stashes the current OUTPUT folder to in ~/.lal/cache/stash/${component}/${NAME} for future reuse. This can be put into another repository with lal update component=name
Alias: lal save
Helper command used by lal build exposed for convenience/sanity. Verifies that:
manifest.jsonexists in$PWDand is valid JSON- dependencies in
INPUTmatchmanifest.json - the dependency tree is flat
- dependencies in
INPUTcontains only published dependencies - dependencies in
INPUTwere built using the correct environment
lal build normally guards on this command.
An optional --simple or -s can be passed to lal verify to not check for published dependencies and a flat dependency tree.
Sets up a default config with a set of pre-configured defaults from a seperately supplied file with default values:
lal configure configs/edonus.jsonWill set up the docker environments, artifactory downnload settings, and common mounts to scan for for the edonus team.
To tweak different settings, edit ~/.lal/config after the original configure call, then manage it yourself.
Creates a basic manifest.json in the current directory, assuming directory name as the name of the main component.
A -f flag can be supplied to force overwrite the manifest.
lal init -f centosPerforms an upgrade check of lal. If new versions are found, it reports how to upgrade your lal tool. This is normally checked daily. But it can be done manually with this command.
This is currently disabled awaiting a redesign.
Deletes artifacts in the cache directory older than 14 days. The day is configurable with -d <days>.
Exports a build artifact from the storage backend in the current directory or a directory of choice.
The component can be either the name of the component for latest version, or suffixed with =version for a specific version:
lal -e xenial export gtest -o mystorage/
test -f mystorage/gtest.tar.gz
lal -e xenial export liblzma=6
test -f ./liblzma.tar.gzNB: export does not read the manifest.json for environment overrides.
Lists the availble versions in the storage backend that were built in a speific environent.
lal -e xenial query libwebsocketsNB: query does not read the manifest.json for environment overrides.
Removes and optionally saves a removal of a component from INPUT and the manifest.
lal remove libwebsockets --save
lal remove gtest --save-devNote you can only use one of save or save-dev at a time. Without either save flag, this subcommand simply deletes the corresponding subdirectory of INPUT.
Alias: lal rm
Publishes a release build in the local ARTIFACT subdirectory provided it is built with a correct version and proper credentials are presented.
lal env set xenial
lal fetch
lal build libldns --release --with-version=20 --with-sha=$(git rev-parse HEAD)
# specific builds should push immediately (even if there are more builds)
lal publish libldnsThe publish command will upload to a bucket named after the environment used to build it (found in ./ARTIFACT/lockfile.json). It will also verify that the version is set with --with-version.
The uploaded artifact will in this case end up the following location:
https://artifactory.host/artifactory/group/env/xenial/libldns/20/
If you have more supportedEnvironments then lal update will look in all the buckets corresponing to your environments before finding a version that can be useg in all environments.
Retraces a dependency tree in reverse to figure out steps needed to propagate a leaf dependency properly. This is useful for satisfying the full version strictness checks of lal verify in a large dependency tree (recall that we enforce a flat dependency tree).
Given a component with the following example dependency tree:
~ > mycomponent on master $ lal ls -f
mycomponent
├── openssl
├─┬ libcurl
│ ├── c-ares
│ └── openssl
├─┬ cucumber-cpp (dev)
│ └── gtest
├── gtest (dev)
├─┬ qt
│ ├── openssl
│ └── freetype
└── zlibIf we need to propagate a new version of openssl, we need to do it in two stages:
~ > mycomponent on master $ lal propagate openssl
Assuming openssl has been updated:
Stage 1:
- update [openssl] in libcurl
- update [openssl] in qt
Stage 2:
- update [libcurl, openssl, qt] in mycomponentEvery step in each stage is paralellizable, but every stage must wait for the previous stage. A simple web service to perform this scheduling and upgrade can be set up if you are willing to hook this up to your CI infrastructure.
--helpor-h-v--envor-e
Note that -v is a global option that gradually increases verbosity (allows multiple uses), and goes before subcommands.
lal update zlib # update with only standard logging (info!, warn!, and error!)
lal -v fetch # fetch with debug! messages
lal -vv build # build with debug! and trace! messagesThe --env flag will override the default environment in both manifest.environment and .lal/opts for the current command:
lal --env xenial fetch
lal -e xenial verify
lal -e xenial build
lal -e xenial shell
lal -e xenial script unit-test websocket_server_test 5 asanBecause these commands are often used together you can instead make it sticky with lal env.
For full autogenerated help of all flags of every subcommand help can be requested:
lal build -h
lal help build # equivalent