Skip to content

Spec for init scripts and sandbox updates

David Allsopp edited this page Aug 5, 2021 · 7 revisions

Overview

opam has a series of embedded shell scripts and shell commands which are used in three contexts as part of:

  • opam init to set-up automatic switch detection based on CWD and command completion
  • opam env to set-up the shell environment
  • opam install to set-up the sandbox

Updating these requires updating every supported version of opam. The present mechanism is a little cumbersome (requiring the user to opam init --reinit) and can also result in unusable opam releases (e.g. from fish syntax removal).

This spec proposes moving the scripts and shell data to a separate repository which can be updated and released separately, allowing alterations to the sandbox and fixes to shell commands without having to re-release opam.

src/state/opamEnv.ml and src/client/opamInitDefaults.ml are where these scripts are presently used from.

Implementation

A new root branch scripts is added to ocaml/opam. Commits to this branch should be signed with the same GPG key as opam binaries. The branch should have linear history (i.e. no merge commits).

opam init gains a new --init-scripts <giturl>[#<branch>] parameter whose default value is https://github.com/ocaml/opam.git#scripts. If no is given then main is assumed (NOT the default branch of the repo). Two fields are added to .opam/config:

scripts-repository: "https://github.com/ocaml/opam.git"
scripts-branch: "scripts"

Two new options are added to both opam init and opam update: --fetch-scripts and --no-fetch-scripts (the default is --fetch-scripts) and additionally --update-scripts and --no-update-scripts to opam update (the default is --update-scripts). The opam binary at release time will contain an embedded git bundle of the scripts branch.

At opam init, as long as the --init-scripts parameter was either omitted or is (https://github.com/|git://github.com/|ssh://[email protected]/|[email protected]:)ocaml/opam[.git]#scripts, then the internal bundle is cloned to ./opam/opam-init/scripts. Otherwise, the supplied repository URL is cloned. Note that --no-fetch-scripts conflicts --init-scripts if the <giturl> is not the same as the git-bundle's. The cloned repository is referenced as upstream in the cloned repo (and will always point to <giturl> not the bundle) and the branch is called main. If the bundle is extracted, and --no-fetch-scripts was not specified, then upstream is pulled.

At opam update, unless --no-fetch-scripts is given, upstream is fetched. If the .opam/opam-init/scripts contains untracked or uncommitted changes or the branch main is not checked out then opam update emits a warning and does not fetch or update the repo. After fetching, if there are new commits and --no-update-scripts was not given, opam update either:

  • fast-forwards main to upstream/<branch>, if the HEAD if main is a commit on upstream/<branch> and informs the user that the scripts were updated.
  • attempts an automatic rebase of main onto upstream/<branch>. If this succeeds, and custom commits remain, then the user is informed that the scripts were updated and custom patches have been retained. If this fails, then main is left unaltered and the user is warned that the upstream scripts have been updated but the patches made to them do not rebase cleanly.

Note that both processes may cause the variables and init scripts to be regenerated. opam will display the first line of each commit messages of the new commits which have been adopted.

Sandboxes

opamrc's init-scripts field contains the actual sandbox scripts. The default will be updated to:

init-scripts: [
  [
    "sandbox.sh"
    """\
#!/usr/bin/env bash

. "$(dirname "$0")/scripts/sandboxes/bubblewrap.sh"