Package management
Any programming language that aims to make collaboration easier needs a way to distribute (and consume) its reusable modules. LIGO provides first-class support for such distributable units (i.e. packages).
Packages
Reusable modules that developers intend to share with others can be
distributed as packages by placing a ligo.json
(a manifest file)
next to their Ligo modules.
ligo.json | set.mligo | list.mligo |
Any directory (recursively) containing .mligo
files can be turned into a package
by simply placing a manifest file, ligo.json
over there.
LIGO registry
The LIGO registry is used to host LIGO packages. The LIGO registry contains the contracts/libraries along with their metadata. The packages which reside on the LIGO registry can be installed using the ligo install
command.
Consuming
To fetch (download) & maintain different versions of external libraries we need a package manager.
LIGO libraries can be published to the LIGO registry as well as npm.
Using ligo install
command we can fetch these ligo libraries.
Note:
Earlier versions of LIGO used esy
as the backend for package management. This is not so anymore, and installing esy is not necessary.
Workflow
We will need the LIGO compiler to compile smart contracts, to get the LIGO compiler follow these instructions.
Next, we will use a simple dependency @ligo/math-lib
published on the LIGO registry. To download & install the library, run,
Now we can write a smart contract which will use the @ligo/mathlib
library.
Note: When using LIGO packages via
#import
/#include
If only the name of the package is provided, it will be resolved to the
main
file of the package.If you want to import a specific file from the package, the syntax is of the form
#import "<pkg name>/<file in package>" "Module"
#include "pkg name>/<file in package>"
and we write some tests for our smart contract in main.test.mligo
To compile the contract to Michelson run the command
This will find the dependencies installed on the local machine, and compile the main.mligo
file.
To test the contract using LIGO's testing framework run the command
If you working with an existing LIGO project, to install the dependencies, at the root of the project just run
Specifying package versions
To use package, it is necessary to specify the exact version of the package. Semver ranges are currently not supported. This will, however, change soon.
Upgrading the version of a LIGO package
During the lifecycle of a project, if you wish to upgrade the version of a LIGO package,
Just update the package version to the desired one in the ligo.json
. e.g.
and run the command
This will fetch the updated version of the LIGO package, and the compiler will use the updated version of the package.
Using a LIGO package via REPL
If you wish to try out a LIGO package in the REPL environment, Install the LIGO package by following the steps above, and then fire up the LIGO REPL using the following command
Packaging
Packages are code units that can be shared with other developers. Therefore, authors must provide useful metadata, both for other programmers in the community as well as the LIGO toolchain, to understand the package's contents, its version, and other useful information.
Adding package metadata (LIGO manifest)
This is an important step, as it will help the tools and your users/collaborators, provide vital information about your package.
For LIGO packages, authors must provide a manifest file (ligo.json).
The structure of a LIGO manifest is as follows,
Required fields
name
: Name of the package.version
: Version of the package (Should be a valid sem-ver).main
: The main file of the package, Ideally this file should export all the functionality that the package provides.author
: Author of the package.license
: A valid SPDX license identifier.repository
: The place where the LIGO code is hosted (remote repository), Therepository
field follows a structure same as npm.bugs
: The url to your project's issue tracker and/or the email address to which issues should be reported. Thebugs
fields follows a structure same as npm.type
: Thetype
field can be one oflibrary
orcontract
, If the field is ommited default value oftype
islibrary
storage_fn
: In the case whentype
iscontract
, the name of the function which provides initial storage needs to be provided.storage_arg
: In the case whentype
iscontract
, an expression that is a parameter to thestorage_fn
needs to be provided.
Optional fields:
description
: A brief description of the package.readme
: Some readme text, if this field is omitted the contents of README.md or README will be used in its place.dependencies
: A object (key-value pairs) of dependencies of the package where key is apackage_name
and the value is apackage_version
dev_dependencies
: A object (key-value pairs) of dev_dependencies of the package where key is apackage_name
and value is apackage_version
Sample LIGO manifest (ligo.json
) with some of the above information:
Ignore some files or directories while packaging using .ligoignore
You can specify some files or directories which you want to keep out of the LIGO package (keys, deployment scripts, etc.) in a .ligoignore
file.
.ligoignore
file is similar to a .gitignore
file (you can specify glob patterns of files or directories you would like to ignore)
Creating and publishing packages to the LIGO registry
We are going the write a simple package ligo-list-helpers
library that is similar to the bigarray package we used earlier.
and some tests for the library
To run the tests run the command
Logging in
Before publishing, the registry server needs to authenticate the user to avoid abuse. To login,
If you're a new user,
This would create a .ligorc
in the home directory.
Note: By default, LIGO creates the rc file (
.ligorc
) in the home directory.
Publishing
LIGO packages can be published to a central repository at
packages.ligolang.org
with the ligo publish
command.
Note: while publishing a package If just want to see what LIGO publish would do, you can use the
--dry-run
flag$ ligo publish --dry-run
Quick CLI options reference
--cache-path
By default dependencies are installed in the .ligo
directory at the root of the project, If you wish to change
the path where dependencies are installed use the --cache-path
option to specify the path e.g.
--project-root
LIGO will try to infer the root directory of the project so that it
can find the dependencies installed on your local machine, If you wish
to specify the root directory manually you can do so using the
--project-root
option e.g.
--ligorc-path
LIGO creates a .ligorc
file to store auth tokens for the user for a specific registry, This auth token is useful when publishing a package.
By default LIGO creates the .ligorc
in the home directory, If you wish to override this you can do so using the --ligorc-path
e.g.
Note: Using
ligo login
users can log into multiple registries e.g. LIGO registry, and the LIGO beta registry, A new entry will be created in the.ligorc
for storing auth token of each registry.
--dry-run
While using ligo publish
if you don't want to make changes to the LIGO registry, you can use the --dry-run
flag. e.g.
This will only display the report on the command line what it would have done in the case of ligo publish
.
Unpublishing Packages
Packages can be published in two ways,
- Completely delete the entry
- Only unpublish a specific version
unpublish
is that subcommand, grouped under registry
subcommand, removes a package or a specific version of it from the registry
Summary
To unpublish a package, run ligo registry unpublish --package-name <name> --package-version <version>
from anywhere on the CLI (not necessarily from within a project)
Examples,
If --package-version
is skipped, the entire package is unpublished.
Notes
1. Are packages written in different syntaxes interoperable?
Yes, any syntax can be used in packages. Furthermore, one can consume a package written in one syntax from another.
2. What happens if there are entry points declared in a LIGO package?
If you need to use the entry points defined within a package, the best approach is likely to alias them:
In this case, only add
entry point from the package will be used by the compiler. By adding an alias for Increment.sub
, it is possible to also include that entry point in the final contract.