1 Commits
Author SHA1 Message Date
sneak b5521672c8 Install node, yarn and python from the distribution (closes #146)
check / check (push) Canceled after 0s
Follows sneak's ruling at
#146 (comment). Runtimes
and the installer tools bundled with python come from the distribution,
with no version and no hash. Third-party packages stay pinned by hash.

script/bootstrap drops nvm and corepack. It installs node, yarn and the
node packages only when yarn.lock is in the tree, and stops there when
yarn's major version is not 1. This repository's Dockerfile starts from
Alpine 3.24. The Python example starts from debian:trixie-slim, keeps
pipenv at $HOME/.pipenv on a host and in an image, and sets
PIP_ONLY_BINARY=:all:, so pip downloads no build tools without a hash
check.

Model: opus-5-5
2026-11-04 06:24:24 +00:00
4 changed files with 23 additions and 32 deletions

No files matched your search

+1 -2
View File
@@ -8,8 +8,7 @@ last_modified: 2026-11-04
1. Use yarn for package management, avoid using npm. 1. Use yarn for package management, avoid using npm.
1. Install node from the distribution. If its version is too old, use a newer 1. Install node from the distribution, in whatever version it packages.
distribution.
1. Use `prettier` for code formatting, with four spaces for indentation. 1. Use `prettier` for code formatting, with four spaces for indentation.
+7 -7
View File
@@ -88,12 +88,12 @@ with your task.
`pip install --require-hashes`. It installs the packages from `Pipfile.lock` `pip install --require-hashes`. It installs the packages from `Pipfile.lock`
with `pipenv install --deploy`, plus `--dev` when the tests need the with `pipenv install --deploy`, plus `--dev` when the tests need the
development packages. It sets `PIP_ONLY_BINARY=:all:` for both installs, so development packages. It sets `PIP_ONLY_BINARY=:all:` for both installs, so
a package with no wheel for the image stops the install. In that step it a package with no wheel for the image stops the install. It installs no
installs no Python, because a step above it already did. `Pipfile` names no Python there, because the tests use the distribution's, which a step above
`python_version`, because `--deploy` stops when the distribution's Python it installs. `Pipfile` names no `python_version`, because `--deploy` stops
differs from it. The tests run after `ARG CACHEBUST`, and every other stage when the distribution's Python differs from it. The tests run after
installs its Python packages after it, as in the Python `test` phase example `ARG CACHEBUST`, and every other stage installs its Python packages after
in `REPO_POLICIES.md` it, as in the Python `test` phase example in `REPO_POLICIES.md`
- [ ] The gate phases invoke their tools directly, never through `make lint` or - [ ] The gate phases invoke their tools directly, never through `make lint` or
`script/test` — those are themselves a `docker build` and would recurse `script/test` — those are themselves a `docker build` and would recurse
@@ -208,7 +208,7 @@ with your task.
with a one-line message when yarn's major version is not 1. with a one-line message when yarn's major version is not 1.
- [ ] A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap` - [ ] A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap`
only if that stage needs yarn. A stage that needs yarn starts from an only if that stage needs yarn. A stage that needs yarn starts from an
image whose distribution packages yarn 1, such as Alpine. image whose distribution packages yarn 1, which today means Alpine.
- [ ] `script/bootstrap`, `script/fmt` and `script/fmt-check` run yarn by - [ ] `script/bootstrap`, `script/fmt` and `script/fmt-check` run yarn by
whichever name is present: `yarn`, or `yarnpkg` on Debian and Ubuntu. With whichever name is present: `yarn`, or `yarnpkg` on Debian and Ubuntu. With
neither name on `PATH`, they print one line saying to run neither name on `PATH`, they print one line saying to run
+7 -7
View File
@@ -156,12 +156,12 @@ Template files can be fetched from:
the packages from `Pipfile.lock` with `pipenv install --deploy`, plus the packages from `Pipfile.lock` with `pipenv install --deploy`, plus
`--dev` when the tests need the development packages. It sets `--dev` when the tests need the development packages. It sets
`PIP_ONLY_BINARY=:all:` for both installs, so a package with no wheel `PIP_ONLY_BINARY=:all:` for both installs, so a package with no wheel
for the image stops the install. In that step it installs no Python, for the image stops the install. It installs no Python there, because
because a step above it already did. `Pipfile` names no the tests use the distribution's, which a step above it installs.
`python_version`, because `--deploy` stops when the distribution's `Pipfile` names no `python_version`, because `--deploy` stops when the
Python differs from it. The tests run after `ARG CACHEBUST`, and every distribution's Python differs from it. The tests run after
other stage installs its Python packages after it, as in the Python `ARG CACHEBUST`, and every other stage installs its Python packages
`test` phase example in `REPO_POLICIES.md` after it, as in the Python `test` phase example in `REPO_POLICIES.md`
- Server: the final stage builds and runs the application - Server: the final stage builds and runs the application
- Non-server: the final stage brings up the dev environment - Non-server: the final stage brings up the dev environment
@@ -204,7 +204,7 @@ are thin shims calling them. Model scripts:
inline or by running it. inline or by running it.
- [ ] A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap` - [ ] A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap`
only if that stage needs yarn. A stage that needs yarn starts from an only if that stage needs yarn. A stage that needs yarn starts from an
image whose distribution packages yarn 1, such as Alpine. image whose distribution packages yarn 1, which today means Alpine.
- [ ] `script/setup` / `make setup` — readies a fresh clone: runs `bootstrap`, - [ ] `script/setup` / `make setup` — readies a fresh clone: runs `bootstrap`,
then `install-precommit`, plus repo-specific init then `install-precommit`, plus repo-specific init
- [ ] `script/test` / `make test` — - [ ] `script/test` / `make test` —
+8 -16
View File
@@ -135,14 +135,13 @@ style conventions are in separate documents:
packages. Debian 13 and Ubuntu 26.04 package yarn 4. With packages. Debian 13 and Ubuntu 26.04 package yarn 4. With
`--frozen-lockfile`, yarn 4 refuses a yarn 1 `yarn.lock`. Without that flag, `--frozen-lockfile`, yarn 4 refuses a yarn 1 `yarn.lock`. Without that flag,
it rewrites the file in its own format, with its own hashes in place of it rewrites the file in its own format, with its own hashes in place of
these. A host whose distribution packages yarn 4 moves to one that packages these. Alpine and Ubuntu 24.04 package yarn 1, so a host uses one of those.
yarn 1, such as Alpine or Ubuntu 24.04.
A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap` A `Dockerfile` stage copies `yarn.lock` before it runs `script/bootstrap`
only if that stage needs yarn. A stage that needs yarn starts from an image only if that stage needs yarn. A stage that needs yarn starts from an image
whose distribution packages yarn 1, such as Alpine. The Python and Go stages whose distribution packages yarn 1, which today means Alpine. The Python and
below need no yarn, so they copy no `yarn.lock` before that step and never Go stages below need no yarn, so they copy no `yarn.lock` before that step
reach the stop. and never reach the stop.
`script/cibuild` runs the CI build, and the Gitea workflow calls it. The `script/cibuild` runs the CI build, and the Gitea workflow calls it. The
script changes to the repo root, runs `script/bootstrap`, runs script changes to the repo root, runs `script/bootstrap`, runs
@@ -553,9 +552,9 @@ style conventions are in separate documents:
A cache mount is shared by every build on the host, and nothing checks its A cache mount is shared by every build on the host, and nothing checks its
files again. files again.
A Python repository's `script/bootstrap` adds these lines in `main`, above A Python repository's `script/bootstrap` adds these lines. The `ensurepip`
the last `echo`. The `ensurepip` test fails when python is missing, and also test fails when python is missing, and also when Debian's venv package is
when Debian's venv package is missing: missing:
```sh ```sh
if [ ! -x "$HOME/.pipenv/bin/pip" ]; then if [ ! -x "$HOME/.pipenv/bin/pip" ]; then
@@ -569,13 +568,6 @@ style conventions are in separate documents:
"$HOME/.pipenv/bin/pipenv" install --dev --deploy "$HOME/.pipenv/bin/pipenv" install --dev --deploy
``` ```
Make `script/requirements.txt` once with
`echo pipenv | pip-compile --generate-hashes --allow-unsafe -o script/requirements.txt -`,
from Alpine's `py3-pip-tools` package, because Debian and Ubuntu do not
package it. Make the first `Pipfile.lock` with
`$HOME/.pipenv/bin/pipenv lock`, after the `pip install` line has installed
pipenv.
In the example below, `script/bootstrap` finds `make`, `git`, python and In the example below, `script/bootstrap` finds `make`, `git`, python and
venv already installed. The example copies no `yarn.lock`, so venv already installed. The example copies no `yarn.lock`, so
`script/bootstrap` installs no node and no yarn. `script/bootstrap` installs no node and no yarn.
@@ -591,7 +583,7 @@ style conventions are in separate documents:
# stay in their own layer when script/ changes. # stay in their own layer when script/ changes.
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates make git \ && apt-get install -y --no-install-recommends ca-certificates make git \
python3 python3-venv \ python3 python3-pip python3-venv \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# script/bootstrap installs pipenv in a virtual environment at # script/bootstrap installs pipenv in a virtual environment at
# $HOME/.pipenv, and the tests below run that pipenv. # $HOME/.pipenv, and the tests below run that pipenv.