Skip to content

Commit 23a892a

Browse files
committed
feat: runSkimmer.sh for applying interactive suggestions (leanprover-community#36712)
This PR introduces a script `scripts/runSkimmer.sh` which runs `lake build Mathlib:applyCurrentTryThis` via a minimal "side package" that depends on (only) both skimmer and Mathlib. The command `scripts/runSkimmer.sh` will apply all interactive suggestions (try this suggestions, hints) in Mathlib. Because it uses a local dependency, it can use the oleans obtained from a top-level `lake exe cache get` or `lake build` without needing to modify mathlib's lakefile and rebuild mathlib. The facet safely builds any missing oleans itself. This is still very experimental (and says so!), and hopefully can afford to be so by living entirely in `scripts/`. This script is configurable to be copy-pasted into other repos, after changing the config variables to point to the appropriate new targets. `runSkimmer.sh --init` then sets up the side package. (This PR already commits the result of `runSkimmer.sh --init`, and it does not need to be run again for Mathlib.) Technical note on updating the side package: Currently, running the script also runs `lake update` in the side package (only) (but does not fetch the cache). This may update the `lake-manifest.json` and `lean-toolchain` in the side package (here, in `scripts/SideSkimmer`). To prevent this from mixing with intentional refactors performed by skimmer, the `.gitignore` in that side package ignores the `lake-manifest.json` and the `lean-toolchain`. The alternative would be to use `./scripts/runSkimmer.sh --lake-update` in the workflows to simply keep the side package up to date instead of ignoring the side manifest and toolchain, but `lake update` in the side package is not very costly. Technical question on cache management: `lake update` attempts to get the mathlib cache (whether or not any substantive update actually happened) unless `MATHLIB_NO_CACHE_ON_UPDATE=1`. Currently this script sets `MATHLIB_NO_CACHE_ON_UPDATE=1` for mathlib and just advises getting the cache beforehand. But notice the following: even though mathlib is `require`d from a local path, mathlib *dependencies* are duplicated into `scripts/SideSkimmer/.lake/packages` and rebuilt there. This isn't such a big deal for mathlib's dependencies, but it might be a big deal for projects *depending* on mathlib. So, we only set `MATHLIB_NO_CACHE_ON_UPDATE=1` if we're targeting mathlib. But is there a better way? The usage is as follows: ``` Usage: runSkimmer.sh [[--no-update] [--on [tgts...]] | --lake-update | --init | -h | --help] Options: [no arguments] Run `lake update` in `SideSkimmer`, then run `lake build <tgt>:applyCurrentTryThis` on targets configured in `runSkimmer.sh`. (When refactoring mathlib, does not get mathlib's cache.) --on [tgts...] Run `lake update` in `SideSkimmer`, then run `lake build <tgt>:applyCurrentTryThis` for `tgt` in the supplied `tgts`. Each `tgt` may be lake target syntax for the current package or a library or module. (When refactoring mathlib, does not get mathlib's cache.) --no-update Only run `lake build <tgts>:applyCurrentTryThis`, without first running `lake update` in `SideSkimmer`. Applies both the default targets and those supplied with `--on`. --init Set up the `SideSkimmer` side package. This only needs to be done when first introducing `runSkimmer.sh` to a new repo. --lake-update Only run `lake update -v` in `SideSkimmer`, and if refactoring mathlib, do not get mathlib's cache while doing so. ``` Disclosure: Proofreading services and reminders of bash syntax/conventions were provided by Claude Opus 4.6, but I'm fully to blame for the design and keystrokes. :)
1 parent 8a12e93 commit 23a892a

4 files changed

Lines changed: 173 additions & 0 deletions

File tree

scripts/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ under `ci-tools/`).
5050
- `create_deprecated_modules.lean` defines the `#create_deprecated_modules` command that
5151
automatically generates the `deprecated_module` entries, gathering information from `git`.
5252
The expectation is that this will be expanded to a fully automated process that happens in CI.
53+
- `runSkimmer.sh` applies all interactive text suggestions generated within Mathlib (the
54+
`lean_lib`). `runSkimmer.sh --on tgt1 tgt2 ...` applies only to those lake targets (libraries,
55+
modules) within mathlib. If oleans for the refactored targets are already present, it will use them;
56+
else it will build any necessary oleans. This script may be copy-pasted to other repos with altered
57+
config variables, then set up with `runSkimmer.sh --init`. This sets up a minimal side package
58+
`SideSkimmer` which avoids the need for including `skimmer` as a dependency.
59+
See `runSkimmer.sh -h` and the bash module doc for more details.
60+
NOTE: the functionality exposed by this script is very experimental, and subject to change.
61+
Please report issues to Thomas Murrills on Zulip.
5362
- `migrate_to_fork.py`
5463
Helps contributors migrate from having direct write access to the main repository
5564
to using a fork-based workflow. This comprehensive script automates the entire migration process:

scripts/SideSkimmer/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.lake
2+
/lake-manifest.json
3+
/lean-toolchain

scripts/SideSkimmer/lakefile.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Lake
2+
3+
open Lake DSL
4+
5+
package "side-skimmer"
6+
7+
require "skimmer" from git "https://github.com/thorimur/skimmer" @ "v0.0.1+try-this"
8+
require mathlib from ".." / ".."

scripts/runSkimmer.sh

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#! /usr/bin/env bash
2+
3+
: <<'BASH_MODULE_DOC'
4+
5+
This script runs an **experimental prototype** of certain Skimmer functionality.
6+
7+
While Skimmer is planned to be extensible, currently this script effectively only runs `lake build <tgt>:applyCurrentTryThis` on the specified targets, which may be configured in this script.
8+
9+
This script works by using a "side package" relative to the location of this script that depends on both the local package and skimmer.
10+
11+
`runSkimmer.sh --init` will create this side package, as long as it is local to the target package (e.g. at `packageToRefactor/scripts/runSkimmer.sh`) and all of the variables have been configured to match the refactor targets.
12+
13+
Report issues to Thomas Murrills, on Zulip, either by DM or on the following channel:
14+
https://leanprover.zulipchat.com/#narrow/channel/113488-general/topic/automatically.20apply.20code.20actions
15+
16+
BASH_MODULE_DOC
17+
18+
# ---------------------------------------------
19+
# Config variables (specific to target package)
20+
# ---------------------------------------------
21+
22+
# The directory in which the side-skimmer package will be created.
23+
# I.e., the package is expected to live in `side_pkg_dir/SideSkimmer/`.
24+
# `"$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"` yields the absolute directory containing this script, no matter the invocation location.
25+
side_pkg_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26+
pkg="${side_pkg_dir}/SideSkimmer"
27+
28+
# The package containing the targets we want to run `lake build <tgt>:applyCurrentTryThis` on.
29+
# Expected to be local relative to the location of this script.
30+
target_pkg="mathlib"
31+
# The lakefile syntax for the relative path to the target package from `side_pkg_dir` / SideSkimmer.
32+
# E.g. if we have target_pkg / scripts / SideSkimmer, use `'".." / ".."'`
33+
relative_path='".." / ".."'
34+
35+
# The targets in the target package on which we will run `lake build <tgt>:applyCurrentTryThis`.
36+
# May use lake target syntax; may be the whole package or libraries or modules in the package.
37+
# May be a bash array `("tgt1" "tgt2" ...)`; will refactor each in turn.
38+
tgts=("Mathlib")
39+
40+
# --------------------
41+
# End config variables
42+
# --------------------
43+
44+
echo "Note: the functionality provided by this script is experimental and subject to change. This script will become unnecessary in the future."
45+
echo "Please report any issues (especially incomprehensible ones!) to Thomas Murrills on Zulip."
46+
47+
usage() {
48+
cat <<EOF
49+
Usage: runSkimmer.sh [[--no-update] [--on [tgts...]] | --lake-update | --init | -h | --help]
50+
51+
Options:
52+
[no arguments] Run \`lake update\` in \`SideSkimmer\`, then run \`lake build <tgt>:applyCurrentTryThis\` on targets configured in \`runSkimmer.sh\`. (When refactoring mathlib, does not get mathlib's cache.)
53+
--on [tgts...] Run \`lake update\` in \`SideSkimmer\`, then run \`lake build <tgt>:applyCurrentTryThis\` for \`tgt\` in the supplied \`tgts\`. Each `tgt` may be lake target syntax for the current package or a library or module therein. (When refactoring mathlib, does not get mathlib's cache.)
54+
--no-update Only run \`lake build <tgts>:applyCurrentTryThis\`, without first running \`lake update\` in \`SideSkimmer\`. Applies both the default targets and those supplied with \`--on\`.
55+
--init Set up the \`SideSkimmer\` side package. This only needs to be done when first introducing \`runSkimmer.sh\` to a new repo.
56+
--lake-update Only run \`lake update -v\` in \`SideSkimmer\`, and if refactoring mathlib, do not get mathlib's cache while doing so.
57+
EOF
58+
}
59+
60+
checkNoArg() {
61+
if [[ -n "$1" ]]; then
62+
echo "Unexpected argument \`$1\`"
63+
usage
64+
exit 1
65+
fi
66+
}
67+
68+
# Argument handling:
69+
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
70+
checkNoArg "$2"
71+
usage
72+
exit 0
73+
elif [[ "$1" == "--init" ]]; then
74+
checkNoArg "$2"
75+
shouldInit=true
76+
elif [[ "$1" == "--lake-update" ]]; then
77+
checkNoArg "$2"
78+
lakeUpdate=true
79+
elif [[ "$1" == "--no-update" || "$1" == "--on" ]]; then
80+
if [[ "$1" == "--no-update" ]]; then
81+
noUpdate=true
82+
shift
83+
fi
84+
if [[ "$1" == "--on" ]]; then
85+
tgts=("${@:2}")
86+
else
87+
checkNoArg "$1"
88+
fi
89+
else
90+
checkNoArg "$1"
91+
fi
92+
93+
# If we're refactoring mathlib, don't get the cache.
94+
# If not, mathlib may be a dependency, in which case it will live in `SideSkimmer/.lake/packages`.
95+
# TODO: duplicating the oleans is not ideal. Can we re-use the packages already available locally?
96+
# Setting `packagesDir` does not seem to work.
97+
if [[ "${target_pkg}" == "mathlib" ]]; then
98+
export MATHLIB_NO_CACHE_ON_UPDATE=1
99+
fi
100+
101+
if [[ "${shouldInit}" ]]; then
102+
mkdir -p "${pkg}"
103+
cat <<EOF > "${pkg}/lakefile.lean"
104+
import Lake
105+
106+
open Lake DSL
107+
108+
package "side-skimmer"
109+
110+
require "skimmer" from git "https://github.com/thorimur/skimmer" @ "v0.0.1+try-this"
111+
require ${target_pkg} from ${relative_path}
112+
EOF
113+
# Ignore things changed by `lake update`, update locally on individual runs.
114+
cat <<EOF > "${pkg}/.gitignore"
115+
/.lake
116+
/lake-manifest.json
117+
/lean-toolchain
118+
EOF
119+
# Creates toolchain, manifest, etc.
120+
(cd "${pkg}" && lake update)
121+
else
122+
if [[ -f "${pkg}/lakefile.lean" && -f "${pkg}/.gitignore" ]]; then
123+
if [[ "${lakeUpdate}" ]]; then
124+
echo "Only running \`lake update -v\` in \`SideSkimmer\`; skipping run."
125+
(cd "${pkg}" && lake update -v)
126+
exit 0
127+
fi
128+
# Only run `lake update` if `--no-update` is not present.
129+
if [[ ! "${noUpdate}" ]]; then
130+
echo "Running \`lake update\` in \`SideSkimmer\`. Use \`runSkimmer.sh --no-update\` to skip this step."
131+
(cd "${pkg}" && lake update)
132+
elif [[ ! -f "${pkg}/lake-manifest.json" ]]; then
133+
echo "Expected manifest at \`${pkg}/lake-manifest.json\`."
134+
echo "Please exclude the \`--no-update\` flag to create one."
135+
exit 1
136+
elif [[ ! -f "${pkg}/lean-toolchain" ]]; then
137+
echo "Expected toolchain at \`${pkg}/lean-toolchain\`."
138+
echo "Please exclude the \`--no-update\` flag to create one."
139+
exit 1
140+
fi
141+
echo "Note: \`runSkimmer.sh\` uses available oleans from the targeted package and builds necessary ones. Consider getting the cache prior to running if possible."
142+
for tgt in "${tgts[@]}"; do
143+
cmd=(lake build "${tgt}:applyCurrentTryThis")
144+
echo "Running \`${cmd[@]}\`."
145+
(cd "${pkg}" && "${cmd[@]}")
146+
done
147+
else
148+
echo "Error: \`SideSkimmer\` package is not set up."
149+
echo "- Ensure that the script itself is local to the targeted package and that the variables in it point at the targeted package/libraries/modules."
150+
echo "- Run \`runSkimmer.sh --init\` to set up \`SideSkimmer\` under \`side_pkg_dir=${side_pkg_dir}\`."
151+
exit 1
152+
fi
153+
fi

0 commit comments

Comments
 (0)