gnatsetup

gnatsetup is a command-line tool that can download and install AdaCore binary packages. It is designed to be used in conjunction with a manifest file that describes the set of packages to install.

gnatsetup is intended to help with the deployment of work environments, typically in the context of DevOps (CI/CD pipelines, Docker images, etc.) and can be used to set up a local environment for a developer.

One key feature of gnatsetup is that it can be extended to integrate into custom networks and workflows, typically to be able to download packages from a private registry.

Prerequisites

gnatsetup requires Python 3.8 or later.

Installation

On Linux: to install gnatsetup, unpack the package using:

tar xzf gnatsetup-<version>.tar.gz

In the directory of your choice, then place <prefix>/bin in your PATH.

Usage

The gnatsetup command line works as follow: some optional parameters, followed by a command parameter, followed optionally by parameters that apply to that command.

The following global options are supported:

  • --help: print a help message and exit.

  • --manifest <FILE>: specify an alternate manifest file to use. In the absence of this, the manifest file is gnatsetup.toml in the current directory.

  • --prefix <DIR>: specify an alternate installation prefix. In the absence of this, the prefix is read from the manifest file.

  • --root-dir <DIR>: specify the root directory in which gnatsetup will store its internal data, a cache of downloaded packages, and the installed packages. In the absence of this, the root directory is read from the manifest file, defaulting to .gnat in the user’s home directory.

The following commands are supported:

  • install: download and install the packages listed in the manifest file. This supports the following options:

    • package: the package to install; if this is specified, the manifest file is ignored.

    • version: the version of the package to install.

    • platform: the platform for which to install the package, for instance x86_64-linux or aarch64-linux.

  • list-packages: list the packages available in the manifest file.

  • printenv: print the environment variables that need to be set to use the installed packages. The output of this is intended to be evaluated by the shell, for instance with eval $(gnatsetup printenv).

  • download-packages: download the packages listed in the manifest file.

Manifest file format

The manifest file is a TOML file which describes the set of packages to install. The syntax is as follows:

######################
# The global section #
######################

# The [variables] and [config] sections contain global settings;
# they are optional.

[variables]
# A place to define custom variables that can be used below.
a_variable = a_value

[config] # Optional: the global configuration section

# The root directory, where the gnatsetup metadata is stored
root_dir = "$(env.GNATSETUP_ROOT_DIR|/home/<user>/.gnat)"

# The default installation prefix for all packages
prefix = "$(root_dir)/install"

# The local cache directory, typically hosting the downloaded packages
cache = "$(root_dir)/cache"

############################
# The dependencies section #
############################

# The [[dependencies]] entries list the packages to install.
# At least one of them is required.

# This represents a specific version of GNATcoll
[[dependencies]]
# The name of the package
name = "gnatcoll"
# The version of the package
version = "20.1"
# This is how to override the default value for the installation prefix
prefix = "/opt/gnatcoll"

# This represents a specific version of GNATcoll Bindings
[[dependencies]]
name = "gnatcoll-bindings"
version = "24.0w-20230224"
prefix = "/opt/gnatcoll-bindings"
platform = "x86_64-linux"

Macro substitutions can be used to provide variability to the manifest file.

  • The $(env.<VAR>) syntax is used to reference an environment variable: the value of the environment variable VAR will be used, and an error will be raised if the variable is not defined.

  • The $(env.<VAR>|<value>) syntax is used to reference an environment variable: the value of the environment variable <VAR> will be used, and if the variable is not defined, the value <value> will be used.

  • The $(<FIELD>) syntax is used to reference a field defined in the current section of the manifest file.

  • As a special case, $(MANIFEST_DIR) is replaced by the directory containing the manifest file.

  • The $(config.<FIELD>) syntax is used to reference a field defined in the global config section of the manifest file.

  • The $(variable.<FIELD>) syntax is used to reference a field defined in the global variables section of the manifest file.

  • Inside a macro, the suffix 'slug can be used to replace all non-alphanumeric characters with -. For instance $(env.NAME'slug) will expand to my-name if the environment variable NAME is set to my name.

Extending gnatsetup

The mechanism for extending gnatsetup is through the definition of Python modules that are loaded dynamically by gnatsetup and that can define:

  • How to download packages from a custom location: this is done by implementing a Registry Interface.

  • How to determine the file name for a package based on a dependency description, and how to install the corresponding packages: this is done by implementing a Recipe.

Predefined recipes and registry interfaces

gnatsetup is packaged with a set of recipes and registry interfaces that can be used out of the box. The share/gnatsetup/recipe directory in the gnatsetup Installation contains in particular the following files:

  • gnatpro.py: defines Recipes for installing a number of AdaCore packages.

  • local_folder.py: defines a Registry Interface that can be used to install packages from a local folder. The folder is provided through the GNATSETUP_CUSTOM_FOLDER environment variable. The packages are assumed to be available directly in the provided folder.

  • wget.py: defines a Registry Interface that can be used to install packages from a custom remote location using the wget command. Two environment variables are read for this:

    • GNATSETUP_WGET_URL: the base URL for the remote location; packages are assumed to be available at <base_url>/<package>.

    • GNATSETUP_WGET_HEADERS: any additional headers to pass to wget.

Feel free to use these for inspiration when writing your own recipes and registry interfaces.

Writing your own recipes and registry interfaces

The API for defining Recipes and Registry Interfaces is described respectively in recipes.py and package_registry_interface.py in the share/gnatsetup/gnatsetup_api directory of the gnatsetup installation.

For each, you’ll need to inherit from the base class and implement the required methods. Some methods are optional.

Making your own extensions available to gnatsetup

To make your own extensions available to gnatsetup, you’ll need to either:

  • Copy the files to the share/gnatsetup/recipes directory of the gnatsetup installation, or

  • Place them in a separate folder and point the GNATSETUP_CUSTOM_RECIPES environment variable to that folder.