# How packages are installed and linked

This is the detail behind [Installing safely](where-packages-come-from.md#installing-safely): what
`jadpo package add`, `update`, `remove`, `link` and `unlink` do, and what
each refuses.

- **Where `add` installs from.** A folder holding `package.jadpo` is a
  `path` source, locked relative to the app's root (`../postcodes`);
  `<repository>@v<version>` is a `git` source. A repository written
  `host/owner/name` is fetched over HTTPS, a URL (`https://`, `ssh://`,
  `file://`, `git@host:`) as written, and a folder on this machine
  (starting `.` or `/`) from its path, locked relative to the root. Git
  runs with the developer's or CI's own access and never prompts. A Jadpo
  app's folder (another app's OpenAPI) and a bare name (the registry)
  are in the note at the end. A source whose path has a space is
  refused, since the lock writes each as one word.
- **A git release.** The repository is cloned with nothing checked out,
  the tag's commit is checked out, and the package is at the repository's
  root. The lock records the repository as written, the tag and its
  commit. A tag the repository lacks names the tags it has
  (`install.fetch_failed`).
- **Verification at install.** The package is compiled as the app's own
  integration in a scratch app (the golden rule), and must have no errors;
  the surface its code gives at the version its committed
  `surface.jadpo_record` names has to be that file byte for byte, and for
  git that version has to be the tag's (`install.surface_mismatch`). Only
  then are its files copied, leaving out hidden ones (`.git`) and a
  `build/` at its root, through a hidden folder beside the target so a
  failed copy leaves the old one, and its digest is worked out as "How the
  package format is read" says.
- **What `add` refuses.** A package already in the lock (`update` moves
  it); a package whose name the app's own code uses, which is installed,
  checked and undone, showing `package.name_taken`. A third party's git
  package installs without an acceptance (see the note at the end).
- **`update <name>`.** A `path` package is verified again from its folder;
  a `git` one moves to the newest `v<version>` tag whose committed surface
  names the same package, never to an older one, and a folder or tag now
  holding another major version is refused, since that is a new package.
  It prints the review
  [Package upgrades](package-upgrades.md)
  describes: each surface entry added, changed or removed, `used by the
  app` when the app's code writes its name through the package
  (`Postcodes.uk.tidy`), and `needs a person` for a changed or removed
  one the app uses. A linked package is unlinked first.
- **`remove <name>`.** Refused while a file of the app's has `use
  packages/<name>` (`install.in_use`), naming each; otherwise the folder
  and its lock line go, and the lock stays, possibly empty. A linked
  package is unlinked first.
- **`link <folder>`.** The lock's line becomes `link <path>`, the path
  relative to the root, and the line it replaced is kept in
  `.jadpo/links` (in the lock's format, `.jadpo/` git-ignored) for
  `unlink`. The installed folder stays. Every load reads the checkout's
  files, without hidden ones or its `build/`, in the installed folder's
  place, so `jadpo check`, `test` and `dev` compile the app against it;
  `jadpo check`, `link`, `test` and `dev` show its problems at the
  checkout's paths. A checkout with no
  `package.jadpo` can't be read. `link` itself shows the app's check
  against it. `jadpo dev` and `jadpo test --watch` watch the checkout as
  they run ("A package's names, and watching a linked checkout", below).
- **Where a link is refused.** CI is the `CI` variable set to anything but
  empty, as CI services set it and as `jadpo suggest share` and the
  terminal's animation already read it; there `jadpo check` and `jadpo
  test` refuse each link (`install.link_refused`).
  [Tooling](tooling.md) names no release or production profile, and
  every production build goes through `jadpo build`, which refuses a link
  whatever the environment.
- **`unlink <name>`.** Puts back the line `link` kept; with none (a
  package linked before it was installed), the lock no longer names it and
  the hint says to add it.
- **Examples.** A ```` ```jadpo ```` block in the `///`
  description of any public declaration; other fences are prose. Each runs
  as a test named `example of <name>` (then `example 2 of <name>`), placed
  after the package's own tests in the test file beside the declaration's
  file, in the scratch app. One that doesn't compile is shown at its line
  and left out so the rest run. A failure counts as shown when an example
  or one of the package's tests has a line calling the function with
  `fails <Failure>`. The bar's row counts examples; the package's own
  tests stay the `tests` row.
- **The changelog.** `CHANGELOG.md` beside `package.jadpo`,
  part of the package and its digest: `# Changelog`, then a `## <version>`
  section per version, newest first. For a new version `jadpo package
  check` writes the list as the first list under its heading (`- first
  release`, ``- added type `OutwardCode` ``, or `- no change to what it
  offers` for a patch), and everything beneath it is the author's. While
  the top section's version isn't a released tag, its heading and list
  are rewritten and the author's text kept, so a change before the tag
  updates it; a released section is never rewritten. A new version whose
  section has no text of the author's fails the bar
  (`publish.changelog_missing`); an already released one passes.

> Not built yet: adding another Jadpo app's folder, or a package by bare
> name from the registry, says `toolchain.not_built_yet`. A third party's
> git package needs an acceptance once `jadpo approval` reports publisher
> trust ([Package upgrades](package-upgrades.md));
> until then it installs without one, and accepting an update's changes
> waits for `jadpo approval` too. Outside CI, `jadpo build` still builds
> against a link.
