This document is a coding spec for dopamine CLI client dop
.
The status marks indicated along the document have the following meaning:
- ❌ : Not coded
- ✅ : Coded
- ✔️ : Covered by tests
$ dop [global options] [command] [command options]
-C|--change-dir [directory]
✅- Change to directory before executing the command
-v|--verbose
✅- Enable verbose mode
-c|--no-color
❌- Disable colored output
--version
✅- Print client version and exit
--help
✅- Print help and exit
The following table contains paths, that may be referred to in the next sections.
Symbol | Path | Description |
---|---|---|
$DOP_HOME |
Linux: ~/.dopamine Windows: %LOCALAPPDATA%\Dopamine |
Local storage for Dopmaine |
$DOP_HOME/profiles |
Local cache for profiles | |
$DOP_HOME/recipes |
Local cache for package recipes | |
$DOP_HOME/src |
Local cache for package sources | |
$DOP_HOME/cache |
Local built package cache | |
$DOP_HOME/dub/src |
Local cache for DUB packages | |
$DOP_HOME/dub/cache |
Local cache for DUB built packages | |
$PKG |
Refer to a package directory (aka. recipe directory) | |
$PKG/dopamine.lua |
Package recipe file. | |
$PKG/.dop |
Package working directory for dop |
|
$PKG/dop.lock |
Dependency lock file | |
$PKG/.dop/[build-id] |
Working directory for a config |
Each package is decribed by a recipe file, which is a Lua script named dopamine.lua
located at the package root.
There can be 3 sorts of recipe:
- A dependencies recipe (aka. light recipes).
- This kind of recipe is used to install dependencies locally.
- It is not meant to package a piece of software.
- Expresses dependencies through the
dependencies
global variable.
- A package recipe.
- Is a complete recipe that provide data and functions to build and package a piece of software.
- Recipe is defined by global variables:
- The following are mandatory for a package to be published:
name
version
(Semver compliant)license
build
functiontools
list the tools whose version impacts the build-id- e.g.
cc
,dc
- e.g.
- Others are optional:
authors
copyright
dependencies
source
- The following are mandatory for a package to be published:
- DUB recipes
- DUB recipes are valid Dopamine recipes (although not fully supported at the moment)
When a recipe or one of its function is executed, the current directory is set as follow:
Execution context | Current directory |
---|---|
Recipe evaluation | $PKG |
source function |
$PKG |
build function |
$CONFIG |
Each Dopamine recipe has a revision, allowing more than
one recipe for a package version.
Indeed, the version
of a recipe always refers to the packaged source code version
, not to the recipe code version.
In order to help packaging, a dop
Lua library is provided by the client.
It is implicitely imported and available in every recipe
local dop = require('dop')
Recipes may import other libraries, but the dop
library is the only one that is guaranteed to be always available.
It contains functions to run commands, concatenate paths, perform various file system operations, compute checksums...
Documentation TBD, see lib/src/dopamine/lua
source folder.
Lock files are used to ensure atomicity and exclusive access to a package and also to keep track of the
state of the package between successive invocations of dop
.
dop
uses their modification date and if required their content to check for the validity of a previous operation.
Command | Description |
---|---|
search |
Search for packages on Dopamine's registry. |
login |
Login with a token obtained on the registry. |
profile |
Get, set or adjust the compilation profile. |
options |
Get, set or adjust the package options. |
resolve |
Resolve an and lock dependencies. |
source |
Download package source. |
build |
Build package with selected compilation profile. |
stage |
Stage a package in a specified directory. |
package |
Package binary for distribution. |
revision |
Get the revision of a package. |
publish |
Publish a package recipe on a repository. |
upload |
Upload a built package to a repository. |
Set or get the compilation profile for the current package.
The selected profile of a package is saved in $PACKDIR/.dop/profile.ini
dop profile
✔️- Print the name of the currently selected profile or
(no profile selected)
- Print the name of the currently selected profile or
dop profile --describe
✔️- Print a detailed description of the current profile.
dop profile default
✅- Sets the default profile as current
- Use only the languages of the current recipe
dop profile default-lang1[-lang2...]
✅- Sets the default profile as current
- Use the languages of the current recipe in addition to the one(s) specified
dop profile [name]
✅- Sets the named profile as current
- Use only the languages of the current recipe
dop profile --add-missing
✅- Add missing languages to the compilation profile
dop profile --set-[tool] [tool_exe]
✅- Change a tool executable
- e.g.
dop profile --set-dc dmd
[tool_exe]
is optional and can be a command (e.g.dmd
) or a path- If
[tool_exe]
is omitted, the default for[tool]
is picked.
dop profile --release
✅- Set profile in Release mode
dop profile --debug
✅- Set profile in Debug mode
dop profile --save [name]
✅- Saves the current profile to the user profile cache with name
- Can be combined with other options that modify the profile.
For more sophisticated need, the profile INI files can be edited.
Profile files are INI files containing info about:
- the host (OS, architecture)
- build mode (Release or Debug)
- The compiler (one per language):
- name (Gcc, Dmd...)
- version
- ABI
Profile files can be cached in ~/.dopamine/profiles
.
The filename for profiles is [basename]-[langlist].ini
.
For example:
~/.dopamine/profiles/default-d-c.ini
Resolve and lock dependencies.
Prerequisite: A profile must be chosen (dependencies can depend on profile)
dop resolve
✔️- Resolve dependencies and creates a dependency lockfile for the current package.
- If one exists already, exits without alteration.
dop resolve -f|--force
✅- Resolve dependencies and overwrite the dependency lockfile
dop resolve --prefer-system
✅- Creates/reset a dependency lockfile using the
preferSystem
heuristic mode. - This is the default heuristic and therefore equivalent to
--force
.
- Creates/reset a dependency lockfile using the
dop resolve --prefer-cached
✅- Creates/reset a dependency lockfile using the
preferCached
heuristic mode.
- Creates/reset a dependency lockfile using the
dop resolve --prefer-local
✅- Creates/reset a dependency lockfile using the
preferLocal
heuristic mode.
- Creates/reset a dependency lockfile using the
dop resolve --pick-highest
✅- Creates/reset a dependency lockfile using the
pickHighest
heuristic mode.
- Creates/reset a dependency lockfile using the
dop resolve --no-network
✅- Disable access to network for the resolution of dependencies
dop resolve --no-system
✅- Disable access to system installation for the resolution of dependencies.
dop resolve --use [dependency] [version]
❌- Use the specified version of dependency package in the lock file.
- If lock file exists, alter it.
- If lock file does not exist, create it with this version.
[dependency]
must be one of the dependencies (direct or indirect) of the current package.[version]
must be an exact and existing version of[dependency]
and must be compatible with the version specification in the dependency tree.
Dependency lock files are located in the package root in a file named dop.lock
.
Download and install dependencies of a package.
Prerequisite: The dependencies must be locked.
State:
$PROF/.lock
has adep
field to track where the dependencies were installed. If empty, deps were installed under$USR_DIR/packages
, otherwise the content points to the dependencies prefix.
Command invocations:
dop depinstall
❌- Download and install the dependencies
- Dependencies that are not built for the chosen profile are built.
- They are installed in a per-dependency and per-profile directory under the
~/.dopamine/packages
directory.
dop depinstall --stage [prefix]
❌- Same as
dop depinstall
except that dependencies are staged in the given prefix. - The build process will use the dependencies installed in
[prefix]
instead of the ones in the~/.dopamine/packages
directory.
- Same as
Download package source code.
Requirements:
- The
source
recipe function, if provided, must effectively download the package source code and return the path. - If the
source
function returns successfully, the return value is written to$SRC_FLG
. - If the package embeds the source code, the
source
symbol may be a constant string, which is interpreted as a relative path from$PKG
to the source directory. - If the
source
symbol is omitted,'.'
is assumed.
Command options:
dop source
✔️- Execute the
source
function of the recipe file. - If
source
symbol is a string, the source code is expected local with the package,source
being the relative path to the source directory.
- Execute the
- ....
Build the current package
Prerequisites:
- The profile must be chosen.
- The dependencies must be locked.
- The dependencies must be installed.
- The source code must be available
Requirements:
- The
build
function of the Lua recipe must effectively compile the package using the build system provided by the package source code. - The build must happen in a directory within the package that is unique for the build configuration. Such a directory is created and made current before the function is executed.
- The
build
function accepts two arguments in addition toself
(the recipe table):dirs
: a table containing several paths:dirs.root
: path of package root directory containing the recipe filedirs.src
: the path to the source code
config
: the compilation config table:config.profile
: the compilation profileconfig.options
: the compilation optionsconfig.hash
: A unique hash for the configurationconfig.short_hash
: An abbreviation of the unique hash
depinfos
: a table containing one entry per dependency, each containing where it is installed.
- The
build
function may use the install functionality of the build system. If it does, it must install to thedirs.install
directory. - If the build is successful,
$BLD_FLG
is written. - If the build is successful, the
build
function must returntrue
if the install functionality was used. If so,$INST
must exist and is the path is written to$BLD_FLG
.
Command options:
dop build
❌- Execute the
build
function of the recipe file.
- Execute the
dop build --profile [profile]
❌- Execute the
build
function of the recipe file using[profile]
as compilation profile instead of the one currently selected.
- Execute the
dop build --debug
❌- Execute the
build
function of the recipe file using a debug variant of the currently selected profile.
- Execute the
dop build --release
❌- Execute the
build
function of the recipe file using a release variant of the currently selected profile.
- Execute the
Package the compiled package.
Prerequisites:
- The profile must be chosen.
- The dependencies must be locked.
- The dependencies must be installed.
- The source code must be available
- The package must be built.
- The recipe must have a
package
function, or have installed during thebuild
command
Requirements:
- If the recipe uses the install functionality of the build system, it may or may not declare a
package
function. - If the recipe does not use the install functionality of the build system, it must declare a
package
function. - If
package
function does not exist and$INST
and$STAGE
are different directories, the content of$INST
is copied to$STAGE
. - The
package
function takes three arguments in addition toself
(the recipe table):dirs
: a table containing paths:dirs.src
to the source directorydirs.config
is a working directory unique for the (profile + options) configurationdirs.build
is a recommended location to build, it may or may not have been useddirs.install
is where to install (which is optional)dirs.dest
is where to create the package
config
: the same as for thebuild
functiondepinfos
: the same as for thebuild
function
- If the
dirs.install
anddirs.dest
directories are identical and install functionality was used, thepackage
function may only patch files in that directory. - If the
dirs.install
anddirs.dest
directories are different, thepackage
function must effectively copy the necessary files to thedirs.dest
directory, either fromdirs.install
or directly from where the build occurred. - If the recipe declares a
patch_install
function, it is executed. Thepatch_install
function has the same signature as thepackage
function.
Command options:
dop package
❌- Execute the
package
function of the recipe with the default destination. - If
package
symbol isnil
and the package was installed, simply copy the installation to the destination directory.
- Execute the
dop package [dest]
❌- Same as previous but package to
[dest]
.
- Same as previous but package to
Cache the built package to be reused in the current system as a pre-built dependency for other packages
Publish a recipe to the registry
Upload the built package to the registry to be reused as a pre-built dependency on other systems.