Table of contents

Opam 102: Pinning Packages

Date: 2024-03-25
Category: Trainings



Pins standout. They help us anchor interest points, thus helping us focus on what's important. They become the catalyst for experimentation and help us navigating the strong safety features that opam provides users with.

Pins standout. They help us anchor interest points, thus helping us focus on what's important. They become the catalyst for experimentation and help us navigating the strong safety features that opam provides users with.

Welcome, dear reader, to a new opam blog post!

Today we take an additional step down the metaphorical rabbit hole with opam pin, the easiest way to catch a ride on the development version of a package in opam.

We are aware that our readers are eager to see these blog posts venture on the developer side of the opam experience, and so are we, but we need to spend just a bit little more time on the beginner and user-side of it for now so please, bear with us! 🐻

This tutorial is the second one in this on-going series about the OCaml package manager opam. Be sure to read the first one to get up to speed. Also, check out each article's tags to get an idea of the entry level required for the smoothest read possible!

New to the expansive OCaml sphere? As said on the official opam website, opam has been a game changer for the OCaml distribution, since it first saw the day of light here, almost a decade ago.

Tutorial context and basis

As far as context goes for this article, we will consider that you already are familiar with the concepts introduced in our tutorial opam 101.

Your current environment should thus be somewhat similar to the one we had by the end of that tutorial. Meaning: your version of opam is a least 2.1.5 (all outputs were generated with this version), you have already launched opam init, created a global switch my-switch and, possibly, you have even populated it with a few packages with a few calls to the opam install command.

Furthermore, keep in mind that, in this blog post, we are approaching this subject from the perspective of a developer who is looking into integrating new packages to his current workload, not from the perspective of someone who is looking into sharing a project or publishing a new software.

opam pin is a feature that will quickly become necessary for you to use as you continue your exploration of opam. It allows for the user to pin a given package to a specific version, or even change the source from which said package is pulled, installed, and synchronised with from within your currently active switch.

This feature shines the most in contexts such as:

  • when doing ordinary switch management;
  • for incorporating external, still under-construction, libraries to your own current workload;
  • when designing a specific switch: pinning a specific package version will make it the main compatibility constraint for that switch, thus tailoring the environment around it in the process.

Reminder

Remember that opam's command-line interface is beginner friendly. You can, at any point of your exploration, use the --help option to have every command and subcommand explained. You may also check out the opam cheat-sheet that was released a while ago and still holds some precious insights on opam's CLI.

Use-case for opam pin

Now onto today's use-cases for opam pin, the premise is as follows:

The package on which your current development depends on has just had a major update on its development branch. This package is available on the opam repository and its name is hc.

That update introduced a new feature that you would very much like to experiment with for your own on-going project.

However, that feature is still very much a work-in-progress and the maintainers of hc are not about to release their package anytime soon...

That's when opam pin comes in. In this article, we will cover two similar use-cases for opam pin, namely the one dealing with pinning a version of a package that is already available on the opam repository, and that of pinning a version of an unreleased package, directly from its public URL.

After all the basics have been laid out, we will eventually cover some of the more underground ⛏ and dangerous 🔥 features available when pinning packages.

Important Notice

For the sake of convenience and brevity, we will breakdown the opam pin command, and some of its options, by only dealing with addresses that obey the classic definition of the word URL.

However do keep in mind that opam uses a broader definition for that word, going as far as to consider a filesystem path to be a valid string for a URL argument, thus allowing all opam pin calls and options to be valid when manipulating opam packages inside a local filesystem or local network instead of just on the web.

Pinning the dev version of a released package: opam pin add --dev-repo

Picking up from the base context: our project depends on hc, and hc has just received an update. The first option available for us to access this fresh update on the hc repository is to use opam pin add --dev-repo <pkg> command.

$ opam pin add --dev-repo hc
[hc.0.3] synchronised (git+https://git.zapashcanon.fr/zapashcanon/hc.git)
hc is now pinned to git+https://git.zapashcanon.fr/zapashcanon/hc.git (version 0.3)

The following actions will be performed:
  ∗ install dune 3.14.0 [required by hc]
  ∗ install hc   0.3*
===== ∗ 2 =====
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved hc.0.3  (no changes)
⬇ retrieved dune.3.14.0  (https://opam.ocaml.org/cache)
∗ installed dune.3.14.0
∗ installed hc.0.3
Done.

So what exactly did opam pin do here?

$ opam pin add --dev-repo hc
[hc.0.3] synchronised (git+https://git.zapashcanon.fr/zapashcanon/hc.git)

When you feed a package name to the opam pin add --dev-repo command, it will first retrieve the package definition found inside the opam file in the directory of the corresponding package on the the Official OCaml opam repository or any other opam repositories that your local opam installation happens to be synchronised with.

You can inspect said package definition directly yourself with the opam show <pkg> command.

Let's take a look at the package definition for hc:

$ opam show hc

<><> hc: information on all versions ><><><><><><><><><><><><><><><><>
name         hc
all-versions 0.0.1  0.2  0.3

<><> Version-specific details <><><><><><><><><><><><><><><><><><><><>
version      0.3
repository   default
url.src      "https://git.zapashcanon.fr/zapashcanon/hc/archive/0.3.tar.gz"
url.checksum
          "sha256=61b443056adec3f71904c5775b8521b3ac8487df618a8dcea3f4b2c91bedc314"
          "sha512=a1d213971230e9c7362749d20d1bec6f5e23af191522a65577db7c0f9123ea4c0fc678e5f768418d6dd88c1f3689a49cf564b5c744995a9db9a304f4b6d2c68a"
homepage     "https://git.zapashcanon.fr/zapashcanon/hc"
doc          "https://doc.zapashcanon.fr/hc/"
bug-reports  "https://git.zapashcanon.fr/zapashcanon/hc/issues"
dev-repo     "git+https://git.zapashcanon.fr/zapashcanon/hc.git"
authors      "Léo Andrès <contact@ndrs.fr>"
maintainer   "Léo Andrès <contact@ndrs.fr>"
license      "ISC"
depends      "dune" {>= "3.0"} "ocaml" {>= "4.14"} "odoc" {with-doc}
synopsis     Hashconsing library
description  hc is an OCaml library for hashconsing. It provides
             easy ways to use hashconsing, in a type-safe and
             modular way and the ability to get forgetful
             memoïzation.

Here, you can see the dev-repo field which contains the URL of the development repository of that package. Opam will use that information to retrieve package sources for you.


hc is now pinned to git+https://git.zapashcanon.fr/zapashcanon/hc.git (version 0.3)

Once it has retrieved hc sources, opam will then store the status of the pin internally, which is that hc is git pinned to url git.zapashcanon.fr/zapashcanon/hc at version 0.3.

$ opam pin list
hc.0.3    git  git+https://git.zapashcanon.fr/zapashcanon/hc.git

Did you know? The default behaviour for opam pin is the list option. The option to see all pinned packages in the current active switch.

On the other hand, the default behaviour for opam pin <target> command is the add option. Keep it in mind if you happen to grow tired of typing opam pin add <target> every time.


Opam will then analyse hc dependencies and compute a solution that respects the dependencies constraints and state of your current switch (i.e. the compatibility constraints between the packages currently installed in your switch).

If it manages to do so, it will come forth with a prompt to install the pinned package and its dependencies.

The following actions will be performed:
  ∗ install dune 3.14.0 [required by hc]
  ∗ install hc   0.3*
===== ∗ 2 =====
Do you want to continue? [Y/n] y

Pressing Enter or y + Enter will perform the installation.

Notice that sometimes a * character is found next to some package actions? It's the shorthand signal that the package is pinned, you can get that information at a quick glance when opam outputs the actions to perform for you if you know what to look for.

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved hc.0.3  (no changes)
⬇ retrieved dune.3.14.0  (https://opam.ocaml.org/cache)
∗ installed dune.3.14.0
∗ installed hc.0.3
Done.

Congratulations, you now have a pinned development version of the hc package. You can now start exploring the neat feature you have been looking forward to!

Pinning the dev version of an unreleased package: opam pin add <url>

Every once in a while on your OCaml journey, you will come across unreleased software.

These OCaml programs and libraries can still very much have active repositories but their maintainers have not yet gone as far as to release them in order to distribute their work through opam to the rest of the OCaml ecosystem.

Yet, you might still want to have seamless access to these software solutions on your local opam installation for your own personal enjoyment and developments. That's when opam pin add <url> comes in handy.

Modern OCaml projects will most often have one or several opam files in their tree which opam can operate with.

$ opam pin git+https://github.com/rjbou/opam-otopop
Package opam-otopop does not exist, create as a NEW package? [Y/n] y
opam-otopop is now pinned to git+https://github.com/rjbou/opam-otopop (version 0.1)

The following actions will be performed:
  ∗ install opam-client 2.0.10 [required by opam-otopop]
  ∗ install opam-otopop 0.1*
===== ∗ 2 =====
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved opam-client.2.0.10  (https://opam.ocaml.org/cache)
∗ installed opam-client.2.0.10
∗ installed opam-otopop.0.1
Done.

As you can see, the course of an opam pin add <url> call is very close to that of an opam pin add --dev-repo <pkg>, the only exception being the following line:

Package opam-otopop does not exist, create as a NEW package? [Y/n] y

Since the package is unavailable on the opam repositories that your opam installation is synchronised with, opam doesn't know about it.

That's why it will ask you if you want to create it as a NEW package.

Once pinned, that package is available in your switch as any other ordinarily available repository package.


You can see here that opam has pinned the opam-otopop package to a specific 0.1 version.

opam-otopop is now pinned to git+https://github.com/rjbou/opam-otopop (version 0.1)

The reason for that is found inside the opam file at the root of the source repository for that package:

version: "0.1"

In any instance where this specific field is not found in the opam file, the version name would then be pinned to the verbatim ~dev version.

Dig into opam pin, find spicy features

Add a pin without installing with --no-action

Here are the two main use-cases for a call to opam pin with the --no-action option:

  • You don't want to install a package immediately, but do want to inform opam of its existence to allow opam to keep the compatibility constraints of that specific package in the equation whenever you are undertaking operations that would require such calculations;
  • You just want to be assured that your package will be synchronised with the right sources;

--no-action will only perform the first actions of an opam pin call and will quit before installing the package, it can be used with all pin subcommands.

$ opam pin add hc --dev-repo --no-action
[hc.0.3] synchronised (git+https://git.zapashcanon.fr/zapashcanon/hc.git)
hc is now pinned to git+https://git.zapashcanon.fr/zapashcanon/hc.git (version 0.3)
$

Update your pinned packages

There are two ways to go about updating and upgrading your pinned packages. They are the same no matter if you used the --dev-repo option, or <url> argument, or any other method for pinning them.

The first one you may consider is to either install, or reinstall the specific package(s). The reason is that opam will always first synchronise with the linked source, and then proceed to recompiling.

$ opam install opam-otopop

<><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><>
[opam-otopop.0.1] synchronised (git+https://github.com/rjbou/opam-otopop#master)

The following actions will be performed:
  ↻ recompile opam-otopop 0.1*

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⊘ removed   opam-otopop.0.1
∗ installed opam-otopop.0.1
Done.

In the above code block, opam-otopop has been upgraded by that opam install call.

The second method is to use the specific opam update and opam upgrade mechanisms. These commands are very common in an opam abiding workflow. Their general usage was briefly mentioned in our article opam 101.

By default, opam update updates the state of your opam repositories, for you to have access to the most recent version of your packages. If you add the --development flag to it, it will also update the source code of your pinned packages internally.

$ opam update --development

<><> Synchronising development packages <><><><><><><><><><><><><><><><><><><><>
[opam-otopop.0.1] synchronised (git+https://github.com/rjbou/opam-otopop#master)
Now run 'opam upgrade' to apply any package updates.

Then you run upgrade as you would in any other package upgrade scenario.

$ opam upgrade
The following actions will be performed:
  ↻ recompile opam-otopop 0.1* [upstream or system changes]

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⊘ removed   opam-otopop.0.1
∗ installed opam-otopop.0.1
Done.

Unpin packages

When you are done with your experimentation and wish to remove a pinned package, you can simply call the remove subcommand.

Keep in mind that opam unpin is an alias for opam pin remove.

The behaviour of opam unpin is slightly different between released and unreleased packages.

Released packages

If the pinned package is released, by default, opam will retrieve and install the released version of the package instead of removing that package altogether.

$ opam pin list
hc.0.3    git  git+https://git.zapashcanon.fr/zapashcanon/hc.git
$ opam list hc
# Packages matching: name-match(hc) & (installed | available)
# Package # Installed # Synopsis
hc.0.3    0.3         pinned to version 0.3 at git+https://git.zapashcanon.fr/zapashcanon/hc.git
$ opam pin remove hc
Ok, hc is no longer pinned to git+https://git.zapashcanon.fr/zapashcanon/hc.git (version 0.3)
The following actions will be performed:
  ↻ recompile hc 0.3
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved hc.0.3  (https://opam.ocaml.org/cache)
⊘ removed   hc.0.3
∗ installed hc.0.3
Done.
$ opam list hc
# Packages matching: name-match(hc) & (installed | available)
# Package # Installed # Synopsis
hc.0.3    0.3         Hashconsing library

As we can see in the details:

⬇ retrieved hc.0.3  (https://opam.ocaml.org/cache)

opam has retrieved the sources from the archive that is specified in the opam file of the relevant opam repository, thus pulling hc back down to its latest available, current-switch compatible, release.

Notice the absence of the * character next to the package action? It means the package is no longer pinned.

Unreleased packages

On the other hand, an unreleased package, since its only definition source—meaning both the location of its source code as well as all information required for opam to operate, found in the corresponding opam fileis the pin itself, opam will have no other choice than to offer to remove it for you.

$ opam pin list
opam-otopop.0.1    git  git+https://github.com/rjbou/opam-otopop#master

In this case, opam unpin <package-name> (or idempotently: opam pin remove <package-name>) launches an opam remove action:

$ opam pin remove opam-otopop
Ok, opam-otopop is no longer pinned to git+https://github.com/rjbou/opam-otopop#master (version 0.1)
The following actions will be performed:
  ⊘ remove opam-otopop 0.1
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⊘ removed   opam-otopop.0.1
Done.

Unpin but do no action

Just like with the opam pin add command, the --no-action option is available when removing pins. It will only unpin the package, without removing it, or recompiling it.

$ opam pin remove opam-otopop --no-action
Ok, opam-otopop is no longer pinned to git+https://github.com/rjbou/opam-otopop#master (version 0.1)

$ opam list opam-otopop
# Packages matching: name-match(opam-otopop) & (installed | available)
# Package      # Installed # Synopsis
opam-otopop.0.1 0.1         An opam-otopop package

You may use it for removing the pin from a package while still keeping it installed in your switch, or replacing it by its opam repository definition version.

The resulting package remains linked to its URL, but it is not considered as pinned, so there will be no update or automatic syncing to follow the changes of the upstream branch.

You may also consider this feature to prepare a specific action, say, as a temporary state. For example, you could unpin several packages in a row, and then proceed to recompiling the whole batch in one go.

One URL to pin them all: handling a multi-package repository

Every example seen so far had but one opam file at the root of their respective work tree (sometimes in a specific opam/ directory).

Yet it is possible for some projects to have several packages distributed by a single repository. An example of this would be the opam project source repository itself. If that is the case, and you pin that URL, the default behaviour is that all the packages defined at that address will be pinned.

Let's take this project.

You can see that several packages are defined: ocp-index and ocp-browser.

Here's how a pin action behaves when given that URL:

$ opam pin add git+https://github.com/OCamlPro/ocp-index
This will pin the following packages: ocp-browser, ocp-index.
Continue? [Y/n] y
ocp-browser is now pinned to git+https://github.com/OCamlPro/ocp-index (version 1.3.6)
ocp-index is now pinned to git+https://github.com/OCamlPro/ocp-index (version 1.3.6)

The following actions will be performed:
  ∗ install ocp-indent  1.8.1  [required by ocp-index]
  ∗ install ocp-index   1.3.6*
  ∗ install ocp-browser 1.3.6*
===== ∗ 3 =====
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved ocp-indent.1.8.1  (https://opam.ocaml.org/cache)
∗ installed ocp-indent.1.8.1
∗ installed ocp-index.1.3.6
∗ installed ocp-browser.1.3.6
Done.

As you can see, this process is exactly the same as before, but with 3 packages in one go.

What if I do not want to pin every package in that repository?

Easy: if you just need one of the packages found at that URL, you can just feed that package name to the opam pin add <package-name> <url> CLI call, just like we did at the beginning of this tutorial!

$ opam pin add ocp-index git+https://github.com/OCamlPro/ocp-index
[ocp-index.1.3.6] synchronised (git+https://github.com/OCamlPro/ocp-index)
ocp-index is now pinned to git+https://github.com/OCamlPro/ocp-index (version 1.3.6)

The following actions will be performed:
  ∗ install ocp-indent 1.8.1  [required by ocp-index]
  ∗ install ocp-index  1.3.6*
===== ∗ 2 =====
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved ocp-indent.1.8.1  (cached)
∗ installed ocp-indent.1.8.1
∗ installed ocp-index.1.3.6
Done.

If you do not know the exact names of these different packages, you may also consider using the very handy opam pin scan command which will lookup the contents repository at the URL and list its opam packages for you:

$ opam pin scan git+https://github.com/OCamlPro/ocp-index
# Name       # Version  # Url
ocp-index    1.3.6      git+https://github.com/OCamlPro/ocp-index
ocp-browser  1.3.6      git+https://github.com/OCamlPro/ocp-index

Setting arbitrary version numbers, toying with fire

As demonstrated earlier, opam will choose a version of the pinned package according to the contents of the opam file.

The important thing to take away from that is, in most usual scenarios, the contents of the opam file are paramount to how opam will calculate compatibility constraints in a given switch.

It is from the information that is hardcoded inside the opam file that opam will be able to take educated decisions whenever changes to the state of your current switch are to be made. There is a way, however, to circumvent that behaviour, that we want to inform you of, even if it entails a bit of precaution.

Naturally, directly tinkering with such a key stability feature like compatibility constraints solving does require you to tread carefully. We will see together some of the pitfalls and things to do that will keep you from finding yourself in confusing situations in regards to the state of your switch and the dependencies within it.

Ready? Lets get acquainted with our first slightly dangerous opam feature:

You are allowed to append an arbitrary version number to the name of the pinned package for opam to incorporate in its calculations, as seen in the following code block:

$ opam pin add directories.1.0 git+https://github.com/ocamlpro/directories --no-action
[directories.1.0] synchronised (git+https://github.com/ocamlpro/directories)
directories is now pinned to git+https://github.com/ocamlpro/directories (version 1.0)

In this specific example, package directories is available in the opam repository, that our opam installation is synchronised with. However, there is no such 1.0 version in that repository. Not a single reference to such a version number can be found at that address, neither in the tags, nor releases of the repository, and not even in the opam file.

$ opam show directories --field all-versions
0.1  0.2  0.3  0.4  0.5

What we have done here is effectively telling opam that directories is at a different version number than it actually is in the most purely technical aspect...

But why would we want to do such a thing?


Let's consider a reasonable use-case for opam pin add <package>.<my-version-number> <url>:

You have been working on a project called my-project for some time and you are using a package named fst-dep for your development.

Below, you will find an excerpt of the fst-dep.opam file, specifically its dependencies:

depends: [
  "dep-to-try" { <= "3.0.0" }
  "other-dep"
]

All three packages (fst-dep,dep-to-try and other-dep) are installed in your current switch and are available on your favourite opam repository.

One day you go about checking the repository for each dependency, and you find that dep-to-try has just had one of its main features reimplemented, improved and optimised, they are preparing to release a 4.0.0 version soon.

See, these changes would have been available for you to fetch directly from it's development repository had you been working with it directly, but you are not. It is up to the maintainers of fst-dep to do that work.

Since you have no ownership over any of these dependencies. You have no way of changing any of the version constraints in this tiny dependency tree that ranges from fst-dep and upwards.

Here are the three mainstream solutions to this problem:

  • Wait for both packages to publish new releases. A new official release from the dep-to-try team, which would ship said reimplementation, and another from the fst-dep team which would update its dependency tree to include dep-to-try's latest version. Needless to say that this could take an arbitrary amount of time which is unsatisfying at best.
  • Another suboptimal solution would be to copy the current state of the entire opam repository relevant to your package distribution, go to the corresponding directory for fst-dep inside that repository, relax the hard dependency "dep-to-try" { <= "3.0.0" } and reinstall all the packages that are directly or indirectly affected by that change. A very time consuming task for such a small edit to the global dependency tree.
  • Last option would be to pin fst-dep, then go about manually editing the dependencies of fst-dep with the opam pin --edit option to relax the dependency. The only pitfall with this solution is that, in a context where dep-to-try is a key package in the OCaml distribution, and many other packages depend on it as well, you might have to do a lot of editing to make your switch a stable environment with all dependency constraints met...

So neither of these solutions fit our needs. They are all unsatisfactory at best and even counter-productive at worst.

That's when arbitrary version pinning shines.

The main benefit of this feature is that it allows for added flexibility in navigating and tweaking the compatibility tree of any opam repository at the switch-level. It provides the user with ways to circumvent all tasks pertaining to a larger operation on the global graph of packages.

$ opam pin dep-to-try.3.0.0 git+https://github.com/OCamlPro/dep-to-try
[dep-to-try.3.0.0] synchronised (file:///home/rjbou/ocamlpro/opam_bps_examples/dep-to-try)
dep-to-try is now pinned to git+https://github.com/OCamlPro/dep-to-try#master (version 3.0.0)

opam will still think that dep-to-try's version is valid ({ <= "3.0.0"}), even if you are synchronised with the state of its development branch, thus giving you access to the latest changes with the minimal amount of manual editing required. Pretty neat, right?

Now, onto the pitfalls that you should keep in mind when tinkering with your dependencies like that.

What kind of predicament awaits you?

  1. You could introduce unforeseen behaviours. This could be anything from errors at compile-time, if dep-to-try's interfaces have changed significantly, to runtime crashes if you're unlucky.
  2. Another source of confusion could arise if you happen to use the opam unpin dep-to-try --no-action command on such a package. After unpinning it, there's a chance that you would later forget it used to be pinned to a development version. There would be little to no way for you to remember which package it was that you had experimented with at some point. You would either have to inspect all you installed packages or even remake a switch from scratch which would not be affected by your reckless arbitrary version pinning and would work just fine after that.

Our advice is rather simple: use this feature with discretion and try to avoid unpinning packages if it's not to reinstall or remove them altogether. If you follow these instructions, you should be safe...

Setting multiple arbitrary version numbers

One last bit of black magic for you to play around with.

Instead of pinning package-name.my-version-number, you may use the --with-version option to pin packages at that URL to an arbitrary version. A key detail is that it is compatible with multiple opam file pinning... Just keep in mind that all the pitfalls mentioned previously apply here too, only with multiple packages at once, which could make it more confusing.

Below, you can see that we are setting all the packages found in that repository to the same version:

$ opam pin add git+https://github.com/OCamlPro/ocp-index --with-version 2.0.0
This will pin the following packages: ocp-browser, ocp-index.
Continue? [Y/n] y
ocp-browser is now pinned to git+https://github.com/OCamlPro/ocp-index (version 2.0.0)
ocp-index is now pinned to git+https://github.com/OCamlPro/ocp-index (version 2.0.0)

The following actions will be performed:
  ∗ install ocp-indent  1.8.1  [required by ocp-index]
  ∗ install ocp-index   2.0.0*
  ∗ install ocp-browser 2.0.0*
===== ∗ 3 =====
Do you want to continue? [Y/n] y

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved ocp-indent.1.8.1  (cached)
⬇ retrieved ocp-index.2.0.0  (no changes)
⬇ retrieved ocp-browser.2.0.0  (no changes)
∗ installed ocp-indent.1.8.1
∗ installed ocp-index.2.0.0
∗ installed ocp-browser.2.0.0
Done.

You can see that all these packages are pinned to 2.0.0 now.

$ opam pin list
ocp-browser.2.0.0    git  git+https://github.com/OCamlPro/ocp-index
ocp-index.2.0.0      git  git+https://github.com/OCamlPro/ocp-index

Conclusion

Here it is, the opam pin command in most of its glory.

If you have managed to stick this long to read this article, you should no longer feel confused about pinning projects and should now have another of opam's most commonly used feature in your arsenal when tackling your own development challenges!

So it is that we have learned about pinning both released and unreleased packages. Additionally, we showcased several features for orthogonal use-cases: from the more quality of life-oriented calls such as opam show and opam pin scan, to obscure features like arbitrary version pinning as well as ordinary options like --no-action, --dev-repo and subcommands like opam unpin.

We are steadily approaching a level of familiarity with opam that will allow us to get into some really neat features soon.

Be sure to stay tuned with our blog, the journey into the rabbit hole has only started and opam is a deep one indeed!


Thank you for reading,

From 2011, with love,

The OCamlPro Team



About OCamlPro:

OCamlPro is a R&D lab founded in 2011, with the mission to help industrial users benefit from experts with a state-of-the-art knowledge of programming languages theory and practice.

  • We provide audit, support, custom developer tools and training for both the most modern languages, such as Rust, Wasm and OCaml, and for legacy languages, such as COBOL or even home-made domain-specific languages;
  • We design, create and implement software with great added-value for our clients. High complexity is not a problem for our PhD-level experts. For example, we helped the French Income Tax Administration re-adapt and improve their internally kept M language, we designed a DSL to model and express revenue streams in the Cinema Industry, codename Niagara, and we also developed the prototype of the Tezos proof-of-stake blockchain from 2014 to 2018.
  • We have a long history of creating open-source projects, such as the Opam package manager, the LearnOCaml web platform, and contributing to other ones, such as the Flambda optimizing compiler, or the GnuCOBOL compiler.
  • We are also experts of Formal Methods, developing tools such as our SMT Solver Alt-Ergo (check our Alt-Ergo Users' Club) and using them to prove safety or security properties of programs.

Please reach out, we'll be delighted to discuss your challenges: contact@ocamlpro.com or book a quick discussion.