Class flixw
It owns project discovery, lock parsing, drift detection, version validation, Java
selection, compiler acquisition, unconditional digest verification, compiler-first verb
dispatch, the wrapper's own verbs, and the process launch. The two shims that reach it,
flixw and flixw.cmd, own exactly one decision each -- which java
-- plus one cache lookup, because logic in a shim has to be written twice and cannot be
unit-tested.
The stock Flix compiler is never modified, patched, or linked against. It is fetched
by URL, verified against a SHA-256 committed in .flixw/lock.toml, and executed
as an opaque process. The digest is recomputed on every invocation: there is no install
stamp and no flag that skips it.
These docs are published from the flixw repository and cover every member, private
ones included, because the internals are what a reader has to trust before letting this
file download and run a compiler. docs/CONTRACT.md is the description of what
ships and what is promised; this is how it is done.
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static final recordA compiler already in the cache thatpincan reuse, with where it came from.(package private) static final record(package private) static final class(package private) static final record(package private) static final record(package private) static final record(package private) static final recordOne key in lock.toml: the table it lives in, whether that table may omit it, the shape its value must have, and the sentence a diagnostic uses to describe it.(package private) static final recordParsed pin request; local selection never replaces the committed release fallback.(package private) static final recordWhat a lock pinned this digest as: the exact tag and repository, not what the compiler chooses to say about itself.(package private) static final recordA plugin dependency the project declares: not a fetch instruction, only a record of whatflixw plugin installverified when someone last ran it.(package private) static final recordWhether the lock was rewritten, and the sentence explaining why not when it was not.(package private) static final recordOne resolved, digest-verified plugin build, ready to launch.(package private) static final recordOne `key = value` occurrence, the table it was found in, and the line it sits on.(package private) static final recordEvery scalar entry in a document, plus every table header, in file order. -
Field Summary
FieldsModifier and TypeFieldDescriptionFallback verbs from Flix 0.77.0.(package private) static final String(package private) static final String(package private) static final PatternTwo-space indent, a lowercase name, then the column gap before its description.(package private) static final String(package private) static final String(package private) static final StringRuns a project'sexamples/<name>/; see the"examples"case inwrapperVerb(java.lang.String, java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String).(package private) static final String(package private) static final String(package private) static final PatternA GitHub release asset URL, split so only the tag has to change to find a newer one.(package private) static final intHow much of a help screen counts as the header forparseReportedVersion(java.lang.String).(package private) static final int(package private) static final Duration(package private) static final String(package private) static final StringThe cache inventory behindinfo --verbose; seelistCache(flixw.Lock, flixw.Jvm).(package private) static final StringA feature release or an exact one, and nothing else -- no ranges, no vendor.(package private) static final StringThe optional JDK provisioner; seerunJdkAsset(int).(package private) static final StringOverrides a declared GitHub dependency with a local checkout; see the"local"case inwrapperVerb(java.lang.String, java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String)and theexamples localrouting in the"examples"case.Bookkeeping verbs work before a compiler is pinned, likeplugin install.(package private) static final String(package private) static final List<flixw.LockField> Every key a lock may hold, in the order a generated lock writes them.(package private) static final StringThe URL written into every generated lock as a `#:schema` directive, and the `$id` of the schema itself.(package private) static final StringThe lock format's major version, which is not the wrapper's.(package private) static final intAdoptium answers in a few tens of KiB; this is room to spare, not a target.(package private) static final StringThe one output produced by Flix's supported Mill assembly task.(package private) static final intLocks already reported on, so a second read in the same run stays quiet.(package private) static final StringWhere the generated documentation and the JSON Schema are published.(package private) static final String(package private) static final Stringpicocli, published as a flixw release asset like every other companion.(package private) static final StringOne usage line for `pin`, because four diagnostics quote it and the fourth was already a release behind the first the last time one was written out by hand.(package private) static final StringA single path segment, nothing else -- in particular no `.`, so a name can never climb out of<cache>/plugins/the way..would.(package private) static final String(package private) static final DurationBounds for the two child processes stage 0 runs for information rather than for work.(package private) static final StringWherelatestPrereleaseTag()asks, since there is no/latestfor it.(package private) static final StringGitHub's own limits on the two path segments; a fork may live anywhere within them.(package private) static final Pattern(package private) static final StringThe installer; seerunSetupAsset(java.util.List<java.lang.String>).(package private) static final StringEvery path the installer writes and the project commits — the set the block pins and the set git has to carry.(package private) static final intThe oldest javac that can compile this file, which is a different number from the floor above and answers a different question.(package private) static final StringCurated Flix command specs for the renderer's class path: flixw's data, so a flixw release rather than picocli's.(package private) static long(package private) static final intThe interval flixw is tested on.(package private) static final Pattern(package private) static final StringWhere the stock compiler comes from when nothing says otherwise.(package private) static final String(package private) static final PatternA version token standing on its own, rather than one buried inside a longer word.(package private) static final String(package private) static final String -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) static booleanacceptable(int f, String source) Below MIN_JAVA is always fatal: the compiler will not run.(package private) static StringacceptPluginCommand(String name, String verb, Path root) (package private) static Pathacquire(flixw.Lock lock) (package private) static StringaskedVersion(flixw.Lock lock) What the pinned compiler reports of itself, aspinrecorded it; null when a lock predates the key and no refresh has backfilled it.(package private) static PathVersion-keyed, so a release's assets can be cached forever: the entry cannot go stale except by a new release, which is exactly when this path moves.(package private) static booleanassetExists(String url) Does this release asset exist? A HEAD, so the download itself stays a single attempt.(package private) static StringassetMainClass(Path asset) flixw-cli.javadeclaresflixwcli; that is the whole convention.(package private) static StringassetSourceBase(String version) Wrapper-owned, not a plugin -- fetched and verified against the release this stage 0 itself is, never installed by a user and never carrying the "3rd-party, unaudited" warning a real plugin does.attrMacros(String text) The macros in force for this file: git's built-inbinary, plus any the file defines itself.autoRunBoundary(List<String> argv) run <word>, with no leading flag and no--already, can only mean a forgotten forwarding boundary for upstream Flix: unlikecheck/test, where the same shape is a legitimate extra file to compile, stockrunrejects a bare trailing word outright ("does not support file arguments") rather than trying to load it.(package private) static intWaits for a child that owns the terminal, and guarantees it dies with us.(package private) static voidbackfillCommand(Path versionDir, Path into) Writes the verb an already-installed plugin declares, reading its jar once.(package private) static intbracketDelta(String line) How much this line opens or closes an inline array, counting only brackets outside quotes.(package private) static flixw.CachedcachedFor(String repo, String version, flixw.Lock had) The cached jar an earlierpinor run fetched for exactly this repository and version, or null -- and then pin downloads, as it always did.<cache>/jdks/*: the trees the provisioner unpacked.(package private) static flixw.PinRecordcachedPinRecord(String identity) Whatacquirelast wrote for this digest, if any -- a file read, never a subprocess or a re-parse of anyone's lock.(package private) static Path(package private) static StringThe single normalization used for release tags, cache coordinates, and every version comparison.(package private) static StringcanonicalAttrs(String shipped) The line endings the flixw block pins for one shipped path.(package private) static StringcaptureHelp(Path javaExe, Path jar) The compiler's `--help`, bounded, as text.(package private) static StringcaptureReportedVersion(Path jar, String javaPin) Asks a JAR what version it says it is, for the lock.captureVerbs(String out, Path jar) (package private) static booleanDoes a later rule leavetextoreolsaying something other than the block does? git resolves attributes one at a time, so a rule reaches only those it names: the block setslinguist-vendoredbeside the endings, and a project that turns that back off has not touched what this check protects.(package private) static intcheck(Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm) Every check, printed; the count is the caller's to act on.(package private) static intcheckCanonical(Path file, String wantDigest, String label) Compares an installed file with the bytes this release ships, by digest.(package private) static intgitattributes resolves by *last* matching pattern, so a rule after the wrapper block silently overrides it -- and a checked-out shim with the wrong line endings is exactly the failure the block exists to prevent.(package private) static String(package private) static flixw.JvmchooseInstall(List<flixw.Jvm> candidates, boolean strict) Picks among discovered installations: the newest JDK that is still inside the tested interval, and only if none is, the one just above it.(package private) static voidclearLocalCompiler(Path root) (package private) static Stringcmd.exe's own quoting convention for one command-line word: wrap in double quotes if it needs it, doubling any quote already inside.(package private) static StringcommandOwner(flixw.Lock lock, String verb) Which plugin, if any, declaredverbin this lock.(package private) static PathcompileAsset(Path asset, Path classpath) Compiles an asset once per content hash, or returns null to source-launch it.(package private) static PathcompiledAssetDir(String srcHash) <cache>/assets/<sha256 of source>/, content-keyed exactly like stage 0's own.(package private) static PathcompilerPath(flixw.Lock lock) (package private) static booleancompilerVerbHelp(String verb, String flag, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts) On renderer failure, launch the original compiler argv.(package private) static booleancompletionEarly(List<String> args) completion, answered before the project is resolved -- and enriched from the cache if there is one.(package private) static voidcompletionScript(List<String> args, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity) The project-independent completer, on stdout.(package private) static StringcompletionShell(List<String> args) The one shell name in these arguments, validated.(package private) static int(package private) static voiddeleteTree(Path p) (package private) static booleandiagnostic(String verb) Verbs that must answer even when no java satisfies the lock.(package private) static StringThe digest aSHA256SUMSfile names for one file, or null if it does not.Directories directly underdir, sorted; empty when it is not one.(package private) static voiddispatchLocal(Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, boolean forExample, List<String> rest, List<String> compilerVerbs, String verbId) The local asset serves bothlocalandexamples local.(package private) static void(package private) static StringdownloadAdvice(int status) A 5xx is the host failing; sending that user to re-read their pin is a false lead.(package private) static PatheditorJarPrefsFile(Path root) .flixw/local/editor-jar.toml: a per-machine preference for how./flix.jar-- the file the official VS Code Flix extension checks for at a workspace root, before its own global cache and before it ever downloads anything itself -- is kept in sync with the pin.(package private) static StringA release tag in a URL path.(package private) static PathensureAsset(String name) (package private) static PathensureAsset(String name, String version) The version is a parameter becausewrapper --upgradewarms the assets of the release it is upgrading *to*, from the stage 0 it is upgrading *from*.(package private) static voidensureGitignored(Path root, String line) One line, appended if missing --/flix.jaris generated, machine-specific state, the same reason.flixw/local/itself is never committed.(package private) static String(package private) static StringEscapes a value for the tab-separated rows above.(package private) static booleanexactCompilerHelp(List<String> argv) (package private) static Path(package private) static StringextractTagName(String json) The first"tag_name"value in a GitHub releases API response, or null.(package private) static flixw.Fail(package private) static IntegerfetchedFrom(String digest) Every URL these exact bytes were actually downloaded from and verified against, one per line -- whatpinmay reuse a cached jar as, and nothing else.(package private) static StringfieldJson(flixw.LockField f, String indent) (package private) static StringfileUrlHint(String base) Says what is wrong with afile://URL that a shell wrote and a JVM cannot read.(package private) static PathfindJavaUnder(Path root) Layout differs per platform -- macOS nests a .jdk bundle -- so look rather than guess.(package private) static PathfindPluginArtifact(Path dir) (package private) static PathSearch upward from cwd for flix.toml, bounded above by the wrapper's own project.forkAssets(String repo, String version) A fork's two asset conventions,flix-<version>.jarandflix.jar.(package private) static IntegerRunsgit <args>in root; null when git is absent or the command fails to start.(package private) static StringhelpContext(Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, boolean override) Everything the renderer is given, so it re-gathers none of it; seehelpTopic(java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String, java.util.List<java.lang.String>, boolean).(package private) static PathThe compiler's--help, verbatim, beside the verb record and keyed the same way.(package private) static PathhelpMetaFile(String identity) Provenance forhelpFile(java.lang.String): what the compiler called itself, what was stored, and when it was asked.(package private) static voidhelpTopic(List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts, boolean degrade) Only interactive help may degrade.(package private) static HttpClientThe one HTTP client, pinned to HTTP/1.1.(package private) static StringOne bounded HTTPS GET returning text.(package private) static StringhumanSize(long bytes) A byte count as a person reads it; cached JARs and JDKs are always well above 1 KB.(package private) static booleaninsideCompilerCache(Path jar) True when a path names something inside the cache flixw fills with pinned compilers.(package private) static StringinspectContext(flixw.Lock lock, flixw.Jvm jvm) What the inspector is told, as opposed to what it looks up.(package private) static StringinstalledCommandOwner(String verb) The installed plugin that claims this verb, for a project that declares none.(package private) static PathThe java recorded by the last successful install, if it is still there.(package private) static Map<String, flixw.PluginDep> Every installed plugin, newest version first, as the cache knows it.(package private) static voidinstallJdkVerb(List<String> argv) `./flixw wrapper --install-jdk`, so the choice need not wait for a failure.(package private) static booleanisHelpFlag(String arg) (package private) static booleanisKey(flixw.TomlEntry e, String table, String key) True when an entry is `table.key`.(package private) static booleanisMac()(package private) static booleanisUpstream(flixw.Lock lock, boolean override) Whether a fact verified against upstream Flix's own behaviour -- not its rendered--helplayout, which any fork can reproduce trivially -- is safe to apply here.(package private) static boolean(package private) static PathjavaHomeOf(Path exe) exe's JDK home: two directories up frombin/java.(package private) static booleanjavaPinAvailable(String pin) Is there a JDK on this machine that satisfies the pin? Asked by `pin` so that writing one is not silently a decision to break the next command.(package private) static voidjdkInstructions(int want) What to type on this OS, pointing at the same vendor flixw would fetch.(package private) static String(package private) static StringjsonString(String s) JSON string literal.jvmOpts()Directories a JDK is commonly unpacked into.(package private) static StringWherewrapper --upgradelooks for the newest release.(package private) static StringThetag_nameof the single most recently published flixw release, whether or not it is a pre-release -- which is the one thing/releases/latestcannot say, by GitHub's own design.(package private) static StringThe tag/releases/latestredirects to, which needs no API token or quota.(package private) static voidInherit cwd and the three streams; propagate the child's status.(package private) static voidlistCache(flixw.Lock lock, flixw.Jvm jvm) The cache inventoryinfo --verboseprints, rendered by a companion asset.(package private) static PathlocalCompilerFile(Path root) Mutable local state; lock.toml remains the committed, verified fallback.(package private) static booleanlocalHelpArgs(List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String verbId) (package private) static boolean(package private) static List<flixw.LockField> lockFields(String table) The fields declared for one table, in lock order.(package private) static flixw.Lock(package private) static Path(package private) static StringThe published JSON Schema for lock.toml, rendered fromLOCK_SCHEMA.The tables the schema knows about, deduplicated, in lock order.(package private) static StringlockText(String wrapper, String repo, String version, String url, String sha256, String reportedVersion, String java, Map<String, flixw.PluginDep> plugins) static voidThe one entry point.(package private) static voidmaintainEditorJar(Path root, Path jar, String requestedMode) Keeps./flix.jarpointing at exactly the JAR this pin just verified, for the one consumer that looks for it: the official VS Code Flix extension, which checks a workspace root before its own global cache and before it ever downloads anything.(package private) static StringmanifestVersion(Path manifest) The manifest is the human authority; disagreement stops us before the network.(package private) static flixw.JvmmarkJvmUse(flixw.Jvm jvm) Records a provisioned JDK only after it won selection, never merely because it was probed.(package private) static voidA flixw-owned last-use record, deliberately independent of filesystem atime.(package private) static StringnewerAsset(String source, String have) The same asset in that repository's newest release, or null if there is no newer one.(package private) static flixw.JvmnoJavaFound(int self, String pin) Nothing usable was found: say how to fix it, and stop.(package private) static voidnoteUnknownLockKeys(String text, String where, String wroteIt) Keys the schema does not describe, reported once and never fatally.(package private) static int(package private) static voidofflineHelp(String identity, Exception e) Help with no renderer: the routing table, then the compiler's own captured help.(package private) static booleanolderOrSame(String a, String b) Is `a` no newer than `b`? Both are the wrapper's own dotted versions.(package private) static booleanownsEditorJar(Path link, flixw.EditorJarPref pref) Whetherlinkis a file this project's own flixw put there -- a symlink resolving into this machine's compiler cache, or a regular file (a copy, or a hard link, indistinguishable from one on disk) whose digest matches what was last recorded here.(package private) static booleanownsEditorJar(Path link, flixw.EditorJarPref pref, Path localCompiler) Also recognizes a selected local link, including one broken by a clean build.(package private) static String(package private) static flixw.PinparsePin(List<String> args, flixw.Lock existing) ./flixw pin [<owner>/<repo>] [<version>] [--java <version>], or./flixw pin --refresh.(package private) static StringparseReportedVersion(String help) The version the compiler says it is, read from the header of its own help.parseVerbs(String out) The verbs a help screen advertises, by three independent parses.(package private) static booleanpatternMatches(String pattern, String path) Does one .gitattributes pattern match one path flixw ships?(package private) static void(package private) static PathpinRecordFile(String identity) Beside the version record and keyed the same way, so a re-pin gets a fresh one.(package private) static StringpluginAttribute(Path artifact, String attr, int max, String format) (package private) static PathpluginCacheDir(String name) Where a plugin may keep derived data between runs.(package private) static PathpluginEnv(Path root, flixw.Lock lock, flixw.Jvm jvm, Path compilerJar, String pluginName, flixw.ResolvedPlugin p, List<String> args) The context a plugin ABI version 1 promises: a flat environment-variable tier for the common case, plusFLIXW_CONTEXTnaming a versioned JSON file for anything structured.(package private) static voidpluginInstall(Path root, List<String> args) The only path a plugin's bytes reach the machine -- explicit, one attempt, same shape asacquire(flixw.Lock)for the compiler.(package private) static voidpluginList(flixw.Lock lock) (package private) static voidpluginRemove(List<String> args) (package private) static Path(package private) static StringpluginsTableJson(String indent) [plugins.<name>]for every name at once: an object whose keys are arbitrary (plugin names) but whose values all share one shape, which JSON Schema expresses withadditionalPropertiesas a sub-schema rather thanproperties.(package private) static voidpluginUpgrade(Path root, List<String> args) Moves every plugin this project declares, or one named, to its newest release.(package private) static StringpluginVersionOf(Path dir) The version half of a<version>-<sha256>plugin directory name.(package private) static voidprintAligned(List<String[]> rows) Prints a two-column list with its first two columns aligned, so that a listing whose entries vary wildly in length --0.75.2beside0.75.3+stable.names.4-- reads as a table instead of a ragged column of annotations nobody can scan.(package private) static intReads<home>/releasewhen present and parseable; else runs the candidate once.(package private) static StringprobeVersion(Path exe) The candidate's own version string -- `21.0.12` rather than `21` -- so a pin can be as exact as the person who wrote it chose to be.publishedAssets(String sums) Every companion asset a release publishes, read out of that release's ownSHA256SUMSrather than from a list in here.(package private) static voidpurgeCache(int days, boolean yes) Runs the cache lifecycle half of the inspector without requiring a project.(package private) static String(package private) static flixw.EditorJarPrefreadEditorJarPref(Path root) (package private) static flixw.LocalCompilerreadLocalCompiler(Path root) A malformed selection is fatal, never an implicit switch to another compiler.readLocalOverrides(Path root) The coordinates.flixw/local/packages.tomlnames, forcheck's advisory line -- not a general reader.(package private) static flixw.LockreadLockFields(String text, String where) Reads every keyLOCK_SCHEMAdeclares, keyed as `table.key` with the root table's keys unprefixed.(package private) static Map<String, flixw.PluginDep> readPlugins(String text, String where) [plugins.<name>]tables, keyed by name -- a dynamic set `LOCK_SCHEMA`'s fixed-table-and-key model cannot describe, so it is read directly fromtomlScan(java.lang.String, java.lang.String)rather than throughreadLockFields(java.lang.String, java.lang.String).(package private) static StringThe digest manifest for one release base, from wherever that base points.`.flixw/tasks.toml`: npm-`scripts`-style name-to-shell-string pairs, hand-edited and committed like `lock.toml` itself, but never generated or rewritten by `pin` or `doctor --fix` -- unlike the lock, this file is the human's to write, so it carries no `#:schema` directive and no "generated" header.(package private) static void(package private) static voidrecordFetch(String digest, String url) AddsurltofetchedFrom(java.lang.String); best-effort, like every cache write.(package private) static voidrecordJava(Path root, Path exe) Leaves the shim a note saying which JDK this project resolved to, so the next run can start on it instead of starting on whatever `java` is first on PATH and then relaunching.(package private) static voidrecordPluginInLock(Path root, String name, String version, String sha256, String url, String description, String command) (package private) static StringRedacts credentials from a URL-shaped value before it is printed.(package private) static StringredactOpts(String v) The same, for JVM option strings, which can carry -Dhttps.proxyPassword=secret.(package private) static flixw.RefreshrefreshLock(Path root) (package private) static voidrefreshPin(Path root) `./flixw pin --refresh`.(package private) static booleanAt most one relaunch, guarded by an env marker, so a stale release file cannot loop.(package private) static StringreleaseBase(String version) Where one release's assets live: a named version's, or whateverlatestmeans.(package private) static intrenderHelp(List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts) Runs the renderer and deletes its context.(package private) static voidrenderWrapperHelp(String verb, String fallback, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> opts) (package private) static voidrenderWrapperHelp(List<String> words, String fallback, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> opts) (package private) static void(package private) static voidreportOverrideGap(flixw.Lock lock, Path jar) Says so whenFLIX_JARnames a compiler out of flixw's own cache.(package private) static voidreportVersionGap(String lead, String pinned, String reported) Says so when the two version strings recorded about one compiler disagree.(package private) static Path(package private) static flixw.ResolvedPluginresolvePlugin(String name, flixw.Lock lock) (package private) static StringresolveRelease(String repo, String version) (package private) static voidBest-effort rollback; a failed restore must not mask the failure being reported.(package private) static StringrewriteBase(String url) (package private) static PathThis project's root, or null when there is no project here.(package private) static voidroutingNotice(String verb, String compilerVersion) Which side handled a verb, under FLIXW_TRACE only.(package private) static voidrunArtifact(Path artifact, Path javaExe, Path compilerJar, List<String> args, Map<String, String> env) Launches one plugin artifact as an opaque subprocess, inheriting cwd and the three streams exactly likelaunch(java.nio.file.Path, java.util.List<java.lang.String>, java.nio.file.Path, java.util.List<java.lang.String>)does for the compiler -- three formats, one launcher, because a plugin is not otherwise different from the compiler stage 0 already knows how to run.(package private) static intresourcesjoins the loader's class path only: data, so never compiled against.(package private) static intRuns a companion asset, in this JVM when it can be and in its own when it cannot.(package private) static StringrunCapture(List<String> cmd, Duration timeout, int cap) Runs a child and returns its merged output, bounded in both bytes and wall clock.(package private) static voidrunDeclaredPlugin(String name, String verb, List<String> args, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm) Runs the plugin that declared this verb, saying which one answered.(package private) static PathrunJdkAsset(int feature) Fetches, verifies and runs the JDK provisioner, and returns thejavait installed -- the one line the asset prints on stdout.(package private) static flixw.JvmThe JVM already executing this code, which is by construction usable.(package private) static voidrunSetupAsset(List<String> args) Runs the installer asset, fetching and verifying it first.(package private) static voidRuns a task's shell string via the platform shell, inheriting cwd and the three streams exactly like a plugin or the compiler does.(package private) static StringA manifest value made safe to print and to store.(package private) static booleansatisfiesJavaPin(String pin, String version) Does this JDK satisfy `[java] version` in the lock? A pin is a prefix of the version, cut at a dot: `21` accepts 21.0.12, `21.0` accepts 21.0.12, and neither accepts 21.1 or 2.(package private) static flixw.JvmselectJava(String pin) (package private) static flixw.LocalCompilerselectLocalCompiler(Path root, String typedPath) Resolves either a built compiler JAR or a Flix checkout containing Mill's output.(package private) static voidselfCompile(Path source) Compiles this source into the cache so the shim can skip the JEP 330 source launch next time.(package private) static Path(package private) static Stringsha256(byte[] b) (package private) static String(package private) static PathThe .java file this stage 0 was launched from, or null when it is running as the compiled class out of the cache.Splits a key into its segments, respecting quotes, then unquotes and trims each one.(package private) static Path(package private) static StringstoredHelp(String identity) The stored help for this compiler, re-verified against its own provenance record.(package private) static boolean(package private) static Stringv1.2.3and1.2.3name one release; the lock records the second.(package private) static StringstripComment(String line) Strips a trailing comment, ignoring '#' inside quotes.(package private) static StringAccepts the release tag where a version is expected:v0.75.2means0.75.2.(package private) static StringThe file name in oneSHA256SUMSline.(package private) static String(package private) static PathOne documented tokenizer: whitespace separates; '' and "" quote; \ escapes inside "" and bare.(package private) static StringtomlEscape(String s) The two escapes a TOML basic string needs.(package private) static StringtomlLookup(String text, String table, String key, String where) Reads one key from one TOML table.(package private) static flixw.TomlScanThe single TOML line scanner in stage 0.(package private) static void(package private) static booleantrace()(package private) static StringThe `x.x.x` that `[package].flix` is allowed to hold.(package private) static booleantryEditorJarLink(Path link, Path target, boolean hard) Attempts a symlink or hard link; failure lets the caller try its fallback.unknownLockKeys(String text, String where) Every key in the file thatLOCK_SCHEMAdoes not describe, named the way a diagnostic names it, in file order and without repeats.(package private) static String(package private) static StringunquoteToml(String v, String where) A quoted TOML value, fully unescaped -- unlikeunquote(java.lang.String), which every existing caller uses for a version, URL or digest, none of which can legally contain a backslash, so stripping the outer quotes has always been the whole job.(package private) static voidupdateWrapper(Path root) doctor --fix: the asset rewrites the files it owns, stage 0 refreshes the lock, and the two counts are added up here.(package private) static voidupgradeWrapper(Path root, String to, boolean pre) Moves this project to the newest published flixw --latest's pick, a version named outright, or, withpre, the newest release regardless of its own pre-release flag (seelatestPrereleaseTag()).(package private) static voidValidated on every run, not only when a download happens: a warm cache would otherwise hide a malformed mirror setting until the day it is actually needed.(package private) static voidvalidateJavaPin(String v, String where) A pin is a dotted number and nothing else: no ranges, no `latest`, no vendor.(package private) static voidvalidateUrl(String url, String where) Structural validation, so a malformed lock produces a FLIXW diagnostic rather than an uncaught IllegalArgumentException from URI.create deep in the download path.(package private) static StringvalidateVersion(String v, String where) (package private) static booleanvalidPluginName(String name) (package private) static StringverbIdentity(Path jar, flixw.Lock lock, boolean override) Pinned compilers are identified by their locked digest; overrides by path+size+mtime.(package private) static PathVerb records live in the wrapper cache keyed by identity, never beside the JAR: a content-addressed compiler directory is legitimately read-only, and a FLIX_JAR override points at a JAR flixw does not own and must not write next to.(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static flixw.Fail(package private) static voidFLIXW010 and FLIXW011 are advisory: they are printed, they never set exit status.(package private) static void(package private) static boolean--help/-hanywhere in a wrapper verb's own arguments, the same way a user expects it to work on any CLI.(package private) static intwarmAssets(String sums, String version) Fetches and verifies every companion asset of one release into the cache, so that the commands needing them work offline afterwards.(package private) static voidwarnMissingJava(String javaPin) (package private) static StringIOException.getMessage() is often bare the path; name the failure too.(package private) static PathResolves this file's own symlink chain without physicalizing unrelated directories.(package private) static voidThe last-resort help when the renderer itself cannot be reached.(package private) static voidwrapperNamespace(List<String> argv) flixw's own namespace.(package private) static StringwrapperUsage(String problem) (package private) static voidwrapperVerb(String verb, List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String verbId) (package private) static voidwriteAtomic(Path file, String text) Same-directory temp plus an atomic move.(package private) static PathwriteContextFile(Path root, flixw.Lock lock, flixw.Jvm jvm, Path compilerJar, String pluginName, flixw.ResolvedPlugin p, List<String> args) The structured half of the ABI: everythingpluginEnv(java.nio.file.Path, flixw.Lock, flixw.Jvm, java.nio.file.Path, java.lang.String, flixw.ResolvedPlugin, java.util.List<java.lang.String>)'s flat variables carry, plus the arguments this invocation was given, as one versioned JSON object.(package private) static voidwriteEditorJarPref(Path root, String mode, String sha256) (package private) static voidwriteHelpRecord(String identity, String help) Written on the one capture stage 0 already performs; a read-only cache stays silent.(package private) static voidwriteLocalCompiler(Path root, Path jar, String selectedSha256) (package private) static voidwritePinRecord(String identity, String repo, String version) Written bypinitself, the moment it settles on a digest -- not deferred to the nextacquire(flixw.Lock), which may never come: a project that pins one build and then immediately pins another runs no other command against the first digest in between, and a record onlyacquirewrites would never see it.
-
Field Details
-
WRAPPER_VERSION
- See Also:
-
WRAPPER_DIR
- See Also:
-
MIN_JAVA
static final int MIN_JAVA- See Also:
-
SOURCE_FLOOR
static final int SOURCE_FLOORThe oldest javac that can compile this file, which is a different number from the floor above and answers a different question. MIN_JAVA is what the *compiler* needs; this is what *stage 0* needs, and between the two lies the range where flixw runs, says the pinned Flix will not, and can fetch a JDK that will. Below it flixw cannot speak at all -- which is why the no-java diagnostic does not offer to install one. `tests/lint.sh` compiles this file with --release SOURCE_FLOOR so the number cannot quietly drift when a newer language feature is used.- See Also:
-
TESTED_CEILING
static final int TESTED_CEILINGThe interval flixw is tested on. Above the ceiling is a warning, not an error. The number means the suite has actually been run there, so it moves when that is done and not when a JDK is released: `.github/workflows/ci.yaml` runs the whole suite on the ceiling as well as on MIN_JAVA, which is what keeps the claim true rather than aspirational.- See Also:
-
PROBE_TIMEOUT
Bounds for the two child processes stage 0 runs for information rather than for work. Both are generous: exceeding one means the child is wedged, not slow. -
HELP_TIMEOUT
-
HELP_CAP
static final int HELP_CAP- See Also:
-
WRAPPER_VERBS
-
BUILTIN_VERBS
Fallback verbs from Flix 0.77.0. Used when `flix --help` cannot be captured or parsed. Its only job is to answer "does the pinned compiler already implement one of WRAPPER_VERBS" -- a question whose answer changes at most once a year, and never silently. Being one release stale here costs nothing; failing here would brick every project pinned to a compiler flixw has not seen. -
T0
static long T0 -
SEMVERISH
-
LOCK_SCHEMA_VERSION
The lock format's major version, which is not the wrapper's. It changes only when a lock this stage 0 writes would stop being readable under the rules below; adding an optional key is not such a change, and does not move it.- See Also:
-
PAGES_BASE
Where the generated documentation and the JSON Schema are published.- See Also:
-
LOCK_SCHEMA_URL
The URL written into every generated lock as a `#:schema` directive, and the `$id` of the schema itself. Taplo and Even Better TOML read that directive, so an editor validates the lock with no per-project configuration.- See Also:
-
REPO_PATTERN
GitHub's own limits on the two path segments; a fork may live anywhere within them.- See Also:
-
JAVA_PIN_PATTERN
A feature release or an exact one, and nothing else -- no ranges, no vendor.- See Also:
-
LOCK_SCHEMA
Every key a lock may hold, in the order a generated lock writes them.requiredmeans required when the table it sits in is present, which is why `[java] version` is optional: a project that does not care which JDK runs the compiler omits the table entirely, and an empty one means the same thing. -
NOTED_LOCKS
Locks already reported on, so a second read in the same run stays quiet. -
UPSTREAM_REPO
Where the stock compiler comes from when nothing says otherwise.- See Also:
-
PIN_USAGE
One usage line for `pin`, because four diagnostics quote it and the fourth was already a release behind the first the last time one was written out by hand.- See Also:
-
INFO_USAGE
- See Also:
-
DOCTOR_USAGE
- See Also:
-
VALIDATE_USAGE
- See Also:
-
EXAMPLES_USAGE
- See Also:
-
LOCAL_USAGE
- See Also:
-
EXAMPLES_LOCAL_USAGE
- See Also:
-
PLUGIN_NAME_PATTERN
A single path segment, nothing else -- in particular no `.`, so a name can never climb out of<cache>/plugins/the way..would. Checked at every point a name reaches a path: the three CLI entry points, and a lock's own[plugins.<name>]table, which is attacker-controlled the moment a lock is.- See Also:
-
METADATA_CAP
static final int METADATA_CAPAdoptium answers in a few tens of KiB; this is room to spare, not a target.- See Also:
-
UNSAFE
-
VERSION_TOKEN
A version token standing on its own, rather than one buried inside a longer word. Built fromSEMVERISHso the two cannot drift into disagreeing about what a version is. -
HEADER_LINES
static final int HEADER_LINESHow much of a help screen counts as the header forparseReportedVersion(java.lang.String).- See Also:
-
COMMAND_ENTRY
Two-space indent, a lowercase name, then the column gap before its description. -
LOCAL_BOOKKEEPING_VERBS
Bookkeeping verbs work before a compiler is pinned, likeplugin install. -
GH_ASSET
A GitHub release asset URL, split so only the tag has to change to find a newer one. -
PLUGIN_USAGE
- See Also:
-
SHIPPED
Every path the installer writes and the project commits — the set the block pins and the set git has to carry. One list, because it was two:.sccignoreshipped into the block while both copies still named five files, so a later rule re-pointing its endings went unreported and nothing noticed it was untracked. -
MILL_COMPILER_JAR
The one output produced by Flix's supported Mill assembly task.- See Also:
-
RELEASES_API
WherelatestPrereleaseTag()asks, since there is no/latestfor it.- See Also:
-
COMPLETION_SHELLS
-
COMPLETION_USAGE
-
JDK_ASSET
The optional JDK provisioner; seerunJdkAsset(int).- See Also:
-
SETUP_ASSET
The installer; seerunSetupAsset(java.util.List<java.lang.String>).- See Also:
-
INSPECT_ASSET
The cache inventory behindinfo --verbose; seelistCache(flixw.Lock, flixw.Jvm).- See Also:
-
CLI_ASSET
The help renderer and completion generator; seehelpTopic(java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String, java.util.List<java.lang.String>, boolean).- See Also:
-
EXAMPLES_ASSET
Runs a project'sexamples/<name>/; see the"examples"case inwrapperVerb(java.lang.String, java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String).- See Also:
-
LOCAL_ASSET
Overrides a declared GitHub dependency with a local checkout; see the"local"case inwrapperVerb(java.lang.String, java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String)and theexamples localrouting in the"examples"case.- See Also:
-
PICOCLI_VERSION
picocli, published as a flixw release asset like every other companion.It is the one third-party dependency in flixw, used only to render companion-asset help and generate completion. Stage 0 does not link against it, does not parse arguments with it and never loads it: flixw's own argument handling stays auditable without reading anyone else's code, which is the property this project exists to have.
Republished rather than fetched from Maven Central. A second download origin would be a second trust story -- outside the release's own
SHA256SUMS, outsideFLIXW_ASSET_SOURCE, unwarmed bywrapper --upgradeand unreachable from a mirror -- for a wrapper whose entire argument is that everything it runs came from one place and was checked against one manifest. Going throughensureAsset(java.lang.String)means the renderer's dependency is verified, mirrored, warmed and purged exactly like stage 0 itself, and costs no new code to do it. picocli is Apache-2.0, so redistribution is a licensing non-event.- See Also:
-
PICOCLI_ASSET
- See Also:
-
SPECS_ASSET
Curated Flix command specs for the renderer's class path: flixw's data, so a flixw release rather than picocli's. Optional -- without it the renderer reads the compiler's own--help, as for any version nobody curated.- See Also:
-
SHIM_SHA256
- See Also:
-
CMD_SHA256
- See Also:
-
-
Constructor Details
-
flixw
public flixw()
-
-
Method Details
-
fail
-
w001
-
w002
-
w003
-
w004
-
w005
-
w006
-
w007
-
w008
-
w009
-
w010
FLIXW010 and FLIXW011 are advisory: they are printed, they never set exit status. -
w011
-
env
-
trace
static boolean trace() -
tr
-
validateVersion
-
stripTagPrefix
Accepts the release tag where a version is expected:v0.75.2means0.75.2. GitHub shows the tag, not the version. The releases page, the tag list, the archive links and the asset URLs all readv0.75.2, so copying from where the versions actually are gets you the tag every time -- and flixw itself builds"v" + versionto construct that URL, so it already holds that the two name one release. Refusing the form flixw prints into its own URLs made the user do a normalization the wrapper was doing anyway. Only ahead of a digit, sovNextis still a bad version rather than the versionNext, and the diagnostic keeps naming the real problem. Deliberately not applied to[package].flix: that field is Flix's, and Flix acceptsx.x.xalone. Tolerating a tag there would let flixw read a manifest that Flix itself rejects, which is a worse outcome than the error it replaces. -
canonical
The single normalization used for release tags, cache coordinates, and every version comparison. SemVer build metadata identifies a build, not a release, so it is accepted in the manifest and stripped everywhere it would name an artifact. Defining this once is what stops `flix = "0.75.2+build.4"` from producing a drift error that `./flixw pin` cannot repair. -
triple
The `x.x.x` that `[package].flix` is allowed to hold. That field is Flix's, not flixw's, and Flix rejects anything else outright -- "This toml file has a Flix version number of the wrong length" for a version carrying build metadata. It also accepts 99.99.99 against a 0.75.2 compiler, so it reads as a coarse floor rather than a pin. The exact version therefore lives in the lock, which is flixw's own file and can say `0.75.2+fork.wstein.260807.1` without breaking anything. Drift compares the two at this precision, because that is all the manifest is able to express. -
q
-
why
IOException.getMessage() is often bare the path; name the failure too. -
redact
Redacts credentials from a URL-shaped value before it is printed. `doctor` output exists to be pasted into bug reports, and a proxy URL is the one environment value that routinely carries a password. Host and port are what a reader needs; user-info and query string never are. Values that are not URLs at all -- a NO_PROXY host list, say -- have no '@' and pass through untouched. -
redactOpts
The same, for JVM option strings, which can carry -Dhttps.proxyPassword=secret. -
lockTables
The tables the schema knows about, deduplicated, in lock order. The root is "". -
lockSchemaJson
The published JSON Schema for lock.toml, rendered fromLOCK_SCHEMA. Generated rather than hand-written for the reason the shims are compared byte for byte: a schema describing a lock this wrapper no longer writes is worse than no schema at all, because an editor presents it as authority. `tests/lint.sh` diffs this against the copy in `docs/schema/`, so the published file cannot drift from the code that writes the file it describes. Hand-rolled rather than serialised by a library, because stage 0 has no dependencies. The only values interpolated are ours, andjsonString(java.lang.String)escapes them anyway -- the patterns are full of backslashes. -
lockFields
The fields declared for one table, in lock order. -
fieldJson
-
tableJson
-
pluginsTableJson
[plugins.<name>]for every name at once: an object whose keys are arbitrary (plugin names) but whose values all share one shape, which JSON Schema expresses withadditionalPropertiesas a sub-schema rather thanproperties. -
jsonArray
-
jsonString
JSON string literal. Only the escapes RFC 8259 requires; every value here is ASCII. -
tomlScan
The single TOML line scanner in stage 0. This is not a TOML parser and does not try to be one -- stage 0 has no dependencies by design. It is deliberately table-aware, comment-aware and multi-line-string-aware, because the alternative that a plain regex gives you is reading `flix = "..."` out of some unrelated table, or out of the body of a description string. There is exactly one of these because there used to be two: `pin`'s rewrite carried a second copy that had never learned about multi-line strings, so a `flix = "9.9.9"` inside a `"""` description was correctly invisible to the lookup and yet rewritable by pin. Any divergence here means the version flixw reads is not the one it writes, so the two readers share a scanner rather than a convention. Lines are split on \n alone, never on \r?\n: `pin` rejoins with \n to rewrite a single line in place, and a split that swallowed the \r would quietly convert a CRLF manifest to LF. The trailing \r survives into the raw line and is removed by trim(). -
isKey
True when an entry is `table.key`. Dotted keys are resolved to their table bytomlScan(java.lang.String, java.lang.String), so both spellings arrive here already in the same shape. -
splitKey
Splits a key into its segments, respecting quotes, then unquotes and trims each one. `a.b` is two segments; `"a.b"` is one. Fails closed: an unterminated quote or an empty segment is a manifest this scanner will not guess at. -
tomlLookup
Reads one key from one TOML table. Anything it cannot classify inside the table it was asked about is rejected rather than guessed at. Duplicate tables and duplicate keys are ambiguous, so they fail rather than resolve. Accepts the key inside [table] and as a dotted key at the root (`package.flix`). -
bracketDelta
How much this line opens or closes an inline array, counting only brackets outside quotes. Used to skip a value that spans lines; it never goes below zero, because a stray closing bracket is not this scanner's business to diagnose. -
stripComment
Strips a trailing comment, ignoring '#' inside quotes. -
unquote
-
unquoteToml
A quoted TOML value, fully unescaped -- unlikeunquote(java.lang.String), which every existing caller uses for a version, URL or digest, none of which can legally contain a backslash, so stripping the outer quotes has always been the whole job. A task's command string is arbitrary shell syntax, where `\"` and embedded quotes are the ordinary case, so this processes TOML's basic-string escapes for real. A single-quoted (literal) string has none to process by definition -- exactly the TOML feature that lets a task avoid this entirely by not using `"..."`. -
lockPath
-
tasksPath
-
readTasks
`.flixw/tasks.toml`: npm-`scripts`-style name-to-shell-string pairs, hand-edited and committed like `lock.toml` itself, but never generated or rewritten by `pin` or `doctor --fix` -- unlike the lock, this file is the human's to write, so it carries no `#:schema` directive and no "generated" header. Flat by design: a table would invite grouping that a shell string running through `sh -c`/`cmd /c` gets no benefit from, and it is one fewer thingtomlScan(java.lang.String, java.lang.String)'s callers here have to check for. -
readLock
-
readPlugins
[plugins.<name>]tables, keyed by name -- a dynamic set `LOCK_SCHEMA`'s fixed-table-and-key model cannot describe, so it is read directly fromtomlScan(java.lang.String, java.lang.String)rather than throughreadLockFields(java.lang.String, java.lang.String). Each declared plugin needs `version` and `sha256`; `source` is optional and never used to fetch anything, only shown to a reader deciding what to install. -
readLockFields
Reads every keyLOCK_SCHEMAdeclares, keyed as `table.key` with the root table's keys unprefixed. Absent optional keys are simply not in the map. Presence and shape are both checked here, from the same list the published JSON Schema is rendered from, so a lock an editor flags is a lock flixw refuses -- and the diagnostic can say what the key is *for* rather than quoting a regex at someone. -
noteUnknownLockKeys
Keys the schema does not describe, reported once and never fatally. Advisory because the ordinary way to meet one is a lock written by a newer flixw, and refusing to run would make such a project unbuildable by every collaborator who had not upgraded yet -- the lock is committed, so that is most of them. Silence is the wrong answer too: a mistyped key is otherwise invisible, and the value someone believed they had set is simply never read. A lock that says it was written by a newer flixw gets no note at all, because there the unknown key is expected and the message would be wrong as well as noisy. -
unknownLockKeys
Every key in the file thatLOCK_SCHEMAdoes not describe, named the way a diagnostic names it, in file order and without repeats. Separate from the note because `doctor --fix` asks the same question for the opposite reason: it regenerates the lock from the values it read, which would *delete* any key it did not read. -
manifestVersion
The manifest is the human authority; disagreement stops us before the network. A manifest that exists but cannot be read is an error, not an absent declaration -- swallowing it would silently disable drift detection and let the compiler run. -
isWindows
static boolean isWindows() -
isMac
static boolean isMac() -
cacheHome
-
sha256
-
sha256
-
isUpstream
Whether a fact verified against upstream Flix's own behaviour -- not its rendered--helplayout, which any fork can reproduce trivially -- is safe to apply here.FLIX_JARis excluded unconditionally: an override is announced as unverified and is explicitly not stock-compatibility evidence, the same reasonreportOverrideGap(flixw.Lock, java.nio.file.Path)exists. -
localHelpArgs
-
localHelpSubcommand
-
wantsHelp
--help/-hanywhere in a wrapper verb's own arguments, the same way a user expects it to work on any CLI.pin,infoanddoctorotherwise treat an unrecognised--xxxas a usage error, so without this check--helpwas indistinguishable from a typo.pinis checked at its own call sites inrealMain(java.util.List<java.lang.String>)rather than inwrapperVerb(java.lang.String, java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String)-- it bypasses that dispatcher entirely, being the one verb answered before a compiler is ever reachable. Checked before the verb's own grammar runs, so it can never be shadowed by an "unknown option" diagnostic firing first -- which is exactly what happened before this existed.Only scans up to the first bare
--, not the whole list. No wrapper verb that calls this has a reason for a literal--to appear in its own arguments, so the guard is free insurance for all of them -- the one verb that genuinely forwards past a--isexamples, and it does not call this method at all: once a real verb (run/check/build/test) is named,--help/-his never intercepted in any position, because the compiler itself answers it better than a generic usage line once a verb is in play. See the"examples"case below. -
validPluginName
-
checkRepo
-
encodeTag
A release tag in a URL path. Only '+' needs it; the rest of a version is path-safe. -
forkAssets
A fork's two asset conventions,flix-<version>.jarandflix.jar. -
resolveRelease
-
httpClient
The one HTTP client, pinned to HTTP/1.1. Every request flixw makes is a single one-shot HEAD or GET, so HTTP/2 buys nothing here -- there are no concurrent streams to multiplex onto one connection -- and it costs a failure mode that only shows up as a red CI run. When a server sends GOAWAY while a stream is being opened, the JDK client raises `request not processed by peer`; because acquisition is one attempt with no retry loop, that lands on the user as a failed download and, through the missing lock, as fifteen further failures. That is a real observation, not a theoretical one: it took out the whole windows smoke job on ccba32b while ubuntu and macos passed the same commit. Pinning 1.1 deletes the race rather than retrying around it, which is the trade this project already makes everywhere else -- a retry would have to be bounded, logged and explained, and would still leave the request that *was* processed ambiguous. -
assetExists
Does this release asset exist? A HEAD, so the download itself stays a single attempt. -
parsePin
./flixw pin [<owner>/<repo>] [<version>] [--java <version>], or./flixw pin --refresh. The two are told apart by the slash, which a version can never contain -- the grammar rejects it -- so the order does not matter and neither does a flag. An omitted repository means the one already in the lock, so re-pinning a project that tracks a fork stays on that fork: rebuilding the upstream URL every time silently moved such a project back to stock, and because both are honestly version 0.75.2, nothing about it looked wrong. -
insideCompilerCache
True when a path names something inside the cache flixw fills with pinned compilers. -
reportOverrideGap
Says so whenFLIX_JARnames a compiler out of flixw's own cache. A mismatch between the override and the lock is the *ordinary* case -- the override exists to run a jar you built yourself, which is not the pinned one and is not meant to be -- so it is reported where state is printed, and not on every run. Pointing it inside<cache>/compilers/is different, and is always a mistake. Those names are content-addressed,flix-<version>-<sha256>.jar, so **the path changes every time the project is re-pinned**. An override set once to whatever `info` reported that day goes on naming the superseded artifact afterwards, and the project quietly builds with the compiler it used to pin. Nothing else in flixw could catch it: the digest guard is switched off by the override, and the version check passes because two builds of one release share a canonical version. Matching the lock is a mistake too, only a harmless one: it names the jar flixw would have chosen anyway, and it will stop doing that at the next pin. -
compilerPath
-
markUsed
A flixw-owned last-use record, deliberately independent of filesystem atime.One immutable cache artifact has one opaque marker containing only its UTC date. Reading first avoids rewriting it on every compiler launch, which matters both for SSD wear and for making a purge record mean a day of actual use rather than a day a wrapper happened to start. Failure is non-fatal: cache lifecycle must never stop a build, and an entry with no usable record is retained by purge.
-
validateDistUrl
static void validateDistUrl()Validated on every run, not only when a download happens: a warm cache would otherwise hide a malformed mirror setting until the day it is actually needed. -
validateUrl
Structural validation, so a malformed lock produces a FLIXW diagnostic rather than an uncaught IllegalArgumentException from URI.create deep in the download path. -
rewriteBase
-
acquire
-
downloadAdvice
A 5xx is the host failing; sending that user to re-read their pin is a false lead. -
download
-
runCapture
Runs a child and returns its merged output, bounded in both bytes and wall clock. Returns null when the child did not finish in time, or its output could not be read. The obvious shape -- a read loop with a deadline test in its condition -- bounds nothing: the test runs *between* reads, and read() on a pipe blocks until the writer produces a byte or closes it. A child that starts and then answers nothing parks stage 0 inside that one call forever, which is precisely what a process run for information must never do. So the read runs on a daemon thread and the timeout is enforced on the process, which is the only handle that can actually be revoked. The byte cap is a separate bound: a chatty child would otherwise exhaust the heap.- Throws:
IOException
-
diagnostic
Verbs that must answer even when no java satisfies the lock.The same set that stays in stage 0 permanently, minus `pin`, which is dispatched before java selection is reached at all. They are what a fresh clone or a broken checkout has to be able to run: a wrapper whose diagnostics need the thing they diagnose has none.
-
runningJvm
The JVM already executing this code, which is by construction usable. -
exeIn
-
probe
Reads<home>/releasewhen present and parseable; else runs the candidate once. -
probeVersion
The candidate's own version string -- `21.0.12` rather than `21` -- so a pin can be as exact as the person who wrote it chose to be. Same two sources as probe(), in the same order and for the same reasons: the release file costs one read, and executing the candidate is the fallback for a java that is not laid out like a JDK. -
satisfiesJavaPin
Does this JDK satisfy `[java] version` in the lock? A pin is a prefix of the version, cut at a dot: `21` accepts 21.0.12, `21.0` accepts 21.0.12, and neither accepts 21.1 or 2. Prefix rather than equality because the useful pin is nearly always "this feature release", and the exact one is available to whoever wants it by writing more of the number. Vendor is deliberately not part of it -- the pin says which Java the project needs, not whose. -
validateJavaPin
A pin is a dotted number and nothing else: no ranges, no `latest`, no vendor. It must also be a Java the pinned compiler can actually run under, so a pin below MIN_JAVA is refused at the point it is written rather than at every run afterwards. -
feature
-
strictJava
static boolean strictJava() -
acceptable
Below MIN_JAVA is always fatal: the compiler will not run. Above TESTED_CEILING is a warning, because a JDK upgrade must not break a wrapper whose pinned compiler tolerates it. FLIXW_STRICT_JAVA=1 makes the ceiling fatal for reproducible builds. -
chooseInstall
Picks among discovered installations: the newest JDK that is still inside the tested interval, and only if none is, the one just above it. Taking the first acceptable candidate in directory order was the earlier rule, and it answers by filename. On a machine carrying 11, 17, 21, 25 and 26 it selected 26 -- outside the tested interval, and warned about on every run -- because the symlink named `java` sorts before `openjdk@21`. Nothing was wrong with the search; the choice was made by `sort`. Above the ceiling is a last resort rather than a preference, so the lowest such candidate wins: it is the one closest to ground that has actually been tested. Returns null when nothing is usable, which is the caller's cue to fail. -
selectJava
-
markJvmUse
Records a provisioned JDK only after it won selection, never merely because it was probed. -
knownInstalls
Directories a JDK is commonly unpacked into. Deliberately only directories: the OS-native inventories are either unusable or misleading here. `java_home -V` is blind to Homebrew, which on macOS is where the JDKs usually are; `update-alternatives --config` is interactive and wants root; `dpkg`, `rpm`, `scoop list` and `choco list` answer with package names rather than paths; and `find /` is an unbounded walk on a tool that runs on every command. A directory that is not there costs one stat. -
httpGet
One bounded HTTPS GET returning text. Metadata only; bytes go through download(). -
installedJdk
The java recorded by the last successful install, if it is still there. -
findJavaUnder
Layout differs per platform -- macOS nests a .jdk bundle -- so look rather than guess. The executable bit is only required where it means something. Adoptium builds its Windows zip on a Unix machine, so entries carry a mode of 0770, and java.util.zip discards it: every file lands 0644. On Windows that is irrelevant, because what makes java.exe runnable there is the extension and the ACL -- but a check for it would rest on platform semantics rather than on anything unpacking guarantees. On POSIX the bit does mean something and tar preserves it, so it is still required. -
jdkInstructions
static void jdkInstructions(int want) What to type on this OS, pointing at the same vendor flixw would fetch. -
javaPinAvailable
Is there a JDK on this machine that satisfies the pin? Asked by `pin` so that writing one is not silently a decision to break the next command. It never offers, downloads or throws: the answer is used for a note, and a pin for a JDK this machine does not have is legitimate -- CI may have it, and `--install-jdk` can fetch it. -
noJavaFound
Nothing usable was found: say how to fix it, and stop. Never returns -- theJvmresult type only exists so the sole caller canreturnit.This used to prompt and then download a JDK inline, and that was the wrong shape twice over. It put ~200 lines of third-party metadata parsing, archive handling and per-platform policy inside the file that is loaded on every single invocation, to serve the rarest path there is; and it made an automatic network fetch the default answer to a missing dependency, in a wrapper whose entire argument is that it fetches only what a lock named and a digest confirmed. A precise diagnostic naming the repair is the better answer, and it is the one every other missing-dependency case here already gives. Provisioning is still available -- explicitly, as
./flixw wrapper --install-jdk-- and lives in a verified companion asset. -
installJdkVerb
`./flixw wrapper --install-jdk`, so the choice need not wait for a failure. -
runJdkAsset
Fetches, verifies and runs the JDK provisioner, and returns thejavait installed -- the one line the asset prints on stdout.Its diagnostics go straight to this process's stderr, which is what the user is already reading: the asset uses flixw's own
FLIXWnnncodes, and a caller must not be able to tell that the work happens outside stage 0's own file. -
jvmOpts
-
tokenize
One documented tokenizer: whitespace separates; '' and "" quote; \ escapes inside "" and bare. -
wrapperAnchor
Resolves this file's own symlink chain without physicalizing unrelated directories. -
resolveLinkChain
- Throws:
IOException
-
findRoot
Search upward from cwd for flix.toml, bounded above by the wrapper's own project. Invocation from outside that tree is refused rather than searched: an unbounded walk finds the first stray manifest above cwd and silently builds an unrelated project. -
verbsFile
Verb records live in the wrapper cache keyed by identity, never beside the JAR: a content-addressed compiler directory is legitimately read-only, and a FLIX_JAR override points at a JAR flixw does not own and must not write next to. -
helpFile
The compiler's--help, verbatim, beside the verb record and keyed the same way.Kept because
verbs(java.nio.file.Path, java.nio.file.Path, java.lang.String)already ran the subprocess and threw the text away: the verb list is a lossy parse of that text, sohelp flixwould otherwise pay a second compiler launch for bytes stage 0 held in a local variable one line earlier. Keyed by identity rather than by version, so two forks that both call themselves 0.75.3 cannot collide and aFLIX_JARoverride gets its own record instead of overwriting a pinned one. -
helpMetaFile
Provenance forhelpFile(java.lang.String): what the compiler called itself, what was stored, and when it was asked.It deliberately does not record the lock's version. This record is keyed by the compiler's digest and is therefore shared between projects -- the same bytes can be pinned as
0.75.3in one repository and as a fork's own tag in another, both correctly -- so there is no single lock version that belongs to it. The.pinrecord beside it has the same property and says so.Nor does it record the help format. Detecting scopt from picocli is a shape test on a few kilobytes, so caching the answer saves nothing and costs the one thing worth avoiding: a second place that decides what a help screen is, free to disagree with the renderer that actually formats it.
-
writeHelpRecord
Written on the one capture stage 0 already performs; a read-only cache stays silent. -
verbIdentity
Pinned compilers are identified by their locked digest; overrides by path+size+mtime. -
verbs
-
pinRecordFile
Beside the version record and keyed the same way, so a re-pin gets a fresh one. -
cachedPinRecord
Whatacquirelast wrote for this digest, if any -- a file read, never a subprocess or a re-parse of anyone's lock. Every project that ever acquired this exact jar wrote the same repo and version here, since the digest is the same bytes either way; the last writer is as good as any. -
fetchedFrom
Every URL these exact bytes were actually downloaded from and verified against, one per line -- whatpinmay reuse a cached jar as, and nothing else.Not the
.pinrecord: every ordinary run rewrites that from whatever the lock claims, and a lock is committed text. A fork's build shares upstream's cache name when their canonical versions agree, so a lock naming those bytes but claimingflix/flixrelabelled them on its next run, and the next offline pin of that version anywhere on the machine reused fork bytes as stock Flix. A line here is only ever added by a download that just produced these bytes from that URL, so a lock can claim what it likes and add nothing; two releases with identical bytes each keep their own line. -
recordFetch
AddsurltofetchedFrom(java.lang.String); best-effort, like every cache write. An append rather than a rewrite: one short line under O_APPEND cannot interleave. -
writePinRecord
Written bypinitself, the moment it settles on a digest -- not deferred to the nextacquire(flixw.Lock), which may never come: a project that pins one build and then immediately pins another runs no other command against the first digest in between, and a record onlyacquirewrites would never see it.acquirere-affirms the same record on every later run regardless, so a cache populated by an older flixw that predates this file entirely still backfills on its very next use rather than staying silent forever. -
captureHelp
The compiler's `--help`, bounded, as text. The two parses read it separately. -
captureVerbs
-
parseReportedVersion
The version the compiler says it is, read from the header of its own help. Free, becauseverbs(java.nio.file.Path, java.nio.file.Path, java.lang.String)already runs--helpand the version is sitting in the text it throws away. Both renderers put it in the first lines and neither puts it in the same place: scopt writesThe Flix Programming Language 0.75.2on one line, picocli writes the product name and the version on the next. Rather than encode either layout -- a fork may rename the product string, and one did move the version to its own line -- take the first standalone version token in the header. The header, not the whole screen: an option's default or an example further down is text about something else, and reading one as the compiler's identity would produce a mismatch report about nothing.- Returns:
- the reported version, or null when the header carries none -- which is not an error, only the absence of a second opinion
-
captureReportedVersion
Asks a JAR what version it says it is, for the lock. Best-effort in every direction: null when no JVM can be selected, when the JAR will not run, or when its header carries no version token.Nothing here may throw. This runs inside
pin, which is the documented repair for a project that cannot reach a compiler -- a machine with no usable Java must still be able to write a lock, and losing the second opinion is a far smaller loss than losing the ability to pin at all. -
reportVersionGap
Says so when the two version strings recorded about one compiler disagree.The digest settles *which bytes* the lock pins, and nothing settles that those bytes are the release it names. A mislabelled release asset -- a fork that tagged
v0.75.4over a 0.75.2 build, an upstream re-upload -- would otherwise be pinned, verified and run without a word.The compiler is *asked* once, by
pin, and its answer is recorded in the lock beside the digest. Every later run re-hashes those bytes anyway, so a digest that still matches is a version that still matches: a per-run second opinion would re-derive what the digest already proves, at the cost of a subprocess and a cache file. The comparison, unlike the capture, is free once both strings are in the lock, so it stays on every run -- it is what catches a lock edited or merged after pin wrote it, which is exactly the case pin-time checking cannot see.Compared through
canonical(java.lang.String), because build metadata identifies a build rather than a release: a compiler built from0.75.3+stable.names.3reporting0.75.3is agreeing, not disagreeing.FLIXW010: printed, never fatal. Pinning a mislabelled asset on purpose is legitimate, and the lock records both strings sovalidatecan decide what a build should do about it.- Parameters:
lead- how the disagreement is introduced, which differs between the moment of pinning ("the JAR just pinned") and every run afterwards ("the pinned compiler")
-
parseVerbs
The verbs a help screen advertises, by three independent parses. Two help renderers are in play and neither is a contract. Stock Flix is scopt: the verb list is one `Usage: flix [a|b|c]` line, and each verb repeats as `Command: a`. The picocli-based fork wraps that same bracket across several lines and replaces the per-verb lines with one indented `Commands:` block. A parser that handles only the first reports zero candidates on the second, which is what FLIXW010 was saying. Kept separate from the subprocess that produces the text so it can be tested against both renderers' real output without a JAR; `tests/UnitCheck.java` does exactly that. -
stage0Dir
-
runAsset
Runs a companion asset, in this JVM when it can be and in its own when it cannot.Spawning a JVM from a JVM to run a Java program is a smell, and the numbers never justified it: the fork is 29ms of a 402ms launch. The reasons that did hold were about the asset ending in
System.exit-- which would take the wrapper down mid-command -- and about what its class path drags in. The first is fixed at the source: every asset returns its exit code now. The second is what the loader below is for.There is no fork any more, and no fallback to one. The fallback existed for three cases and none survived: "no javac" is not one, because a JEP 330 source launch compiles too and fails identically without
jdk.compiler(measured against a jlinked java.base-only runtime); an unwritable cache is handled by compiling to a temporary directory instead; and an asset older thanruncannot be reached, sinceensureAsset(java.lang.String)only ever fetches this release's own. A fallback for situations that cannot arise is a second code path nothing exercises.Each asset gets its own
URLClassLoader, parented to the platform loader rather than the application one. Stage 0's classes are therefore invisible to it and its to stage 0: picocli loaded forhelpcannot be reached from the wrapper's own code, and an asset cannot accidentally resolve a stage 0 class instead of its own. The loader is closed when the asset returns, so nothing it loaded outlives the command.- Returns:
- the asset's exit code
-
runAsset
resourcesjoins the loader's class path only: data, so never compiled against. -
assetMainClass
flixw-cli.javadeclaresflixwcli; that is the whole convention. -
compiledAssetDir
<cache>/assets/<sha256 of source>/, content-keyed exactly like stage 0's own. -
compileAsset
Compiles an asset once per content hash, or returns null to source-launch it.An unwritable cache is a correct configuration, not an error, so it compiles into a temporary directory instead and the classes simply do not survive the command. Null is reserved for the case where nothing can be compiled at all -- no compiler in this runtime, or source that does not build -- which the caller turns into a diagnostic.
The bytes were digest-verified before they got here, so what is compiled is what was published.
-
selfCompile
Compiles this source into the cache so the shim can skip the JEP 330 source launch next time. The shim -- not stage 0 -- consults this cache: stage 0 is already the running process by the time it could decide. That is the one place the shim is allowed to know a cache layout, and it is why the cache path is a versioned interface between the shim and stage 0. -
deleteTree
-
wrapperVerb
-
dispatchLocal
static void dispatchLocal(Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, boolean forExample, List<String> rest, List<String> compilerVerbs, String verbId) The local asset serves bothlocalandexamples local. -
readLocalOverrides
The coordinates.flixw/local/packages.tomlnames, forcheck's advisory line -- not a general reader. The full format (including each entry'spath) lives once, inflixw-local.java, which owns writing it too; this reads only the table headers, since that is all a doctor line needs to say. -
newerAsset
The same asset in that repository's newest release, or null if there is no newer one.Derived from the URL the lock already records rather than from anything the plugin declares. That URL is known to have worked, and between two releases of one project only the tag changes -- so substituting the tag asks for the file that corresponds to the one already installed, rather than guessing at a naming scheme.
Only github.com release assets. A plugin hosted anywhere else gets a diagnostic naming the install command, because inventing a URL for an unknown layout is how an upgrade quietly fetches the wrong artifact.
-
latestTag
The tag/releases/latestredirects to, which needs no API token or quota. -
strip
v1.2.3and1.2.3name one release; the lock records the second. -
pluginUpgrade
Moves every plugin this project declares, or one named, to its newest release.Goes through `plugin install`, so an upgrade is not a second implementation of installing: the digest is taken and recorded, a newly declared verb is checked against the compiler's and the wrapper's, and the unaudited-code warning is printed by the same code that prints it on a first install.
-
pluginsDir
-
pluginCacheDir
Where a plugin may keep derived data between runs.Added because a plugin that computes something expensive has nowhere to put it, and the obvious place is wrong:
plugins/<name>/is enumerated byplugin listas the set of installed versions, so a cache directory there is reported as a version that cannot be run. Every plugin that needed this would otherwise invent its own corner of the cache, and none of them would be collected bywrapper --purge.flixw promises the path and that
--purgecollects it. It promises nothing about the contents: this is the plugin's, to key and invalidate as it sees fit. The directory is not created here -- a plugin that never writes leaves no trace.Not versioned, deliberately. A plugin upgrade that changes what it derives should say so in its own keys, which it can do and flixw cannot; keying the directory by version would instead orphan the old data silently on every upgrade.
-
pluginDir
-
pluginInstall
The only path a plugin's bytes reach the machine -- explicit, one attempt, same shape asacquire(flixw.Lock)for the compiler. `https://` is verified the ordinary way; `file://` copies a local path directly, for local plugin development and for testing this without a public URL. Neither is fetched because a lock named it: a project's[plugins.<name>]entry is read only byresolvePlugin(java.lang.String, flixw.Lock), never by this, so nothing about running `pin` or `doctor` can trigger a download here. -
installedPlugins
Every installed plugin, newest version first, as the cache knows it.Name and version come from the directory; the source URL from the file install wrote beside the artifact. A plugin installed before that file existed has no source, and upgrade says so rather than guessing at a URL.
-
commandOwner
Which plugin, if any, declaredverbin this lock. -
installedCommandOwner
The installed plugin that claims this verb, for a project that declares none.A plugin is a tool, not a dependency: installing one is a thing a person does to their machine, like putting a `git-` subcommand on PATH, and having to repeat it in every project's lock to type the word is not what anyone means by "installed". A lock entry is still consulted first, and still pins a version -- that is what a project reaches for when it wants the same plugin on someone else's machine and in CI.
Read from a file the install wrote beside the artifact, so an unrecognised word costs a directory listing rather than opening every installed plugin's jar.
Two plugins claiming one word is not resolved here. Install refuses a verb another plugin declared, so this is reachable only across projects that installed different plugins at different times, and picking one silently is worse than saying so.
-
backfillCommand
Writes the verb an already-installed plugin declares, reading its jar once.An empty file when it declares none, so the read is not repeated on every unrecognised word for every plugin that will never claim one.
-
dirsIn
Directories directly underdir, sorted; empty when it is not one. -
runDeclaredPlugin
static void runDeclaredPlugin(String name, String verb, List<String> args, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm) Runs the plugin that declared this verb, saying which one answered.Louder than
./flixw plugin <name>on purpose. There the caller named the plugin and knows what is running; here a bare word did, and the reader of a build log needs to be told that a third-party artifact -- not the compiler, not the wrapper -- is what answered it. -
acceptPluginCommand
-
pluginAttribute
-
sanitize
A manifest value made safe to print and to store.It is third-party text on its way to a terminal and to a committed file, so control characters go first: an ESC in a description is a terminal escape sequence in every `flixw help` that renders it, and nothing legitimate needs one. Whitespace collapses because the value crosses into the help asset on a tab-separated line, and the length is capped because a manifest attribute has no bound and a lock file is read by people.
-
recordPluginInLock
-
rootIfAny
This project's root, or null when there is no project here. -
lockIfAny
-
pluginList
-
pluginRemove
-
pluginVersionOf
The version half of a<version>-<sha256>plugin directory name. -
resolvePlugin
-
findPluginArtifact
-
cmdQuote
cmd.exe's own quoting convention for one command-line word: wrap in double quotes if it needs it, doubling any quote already inside. Not a full re-implementation of cmd.exe's parser -- nothing short of one is -- just enough that a space or an embedded quote in a task argument survives as one word in the common case. -
runTask
Runs a task's shell string via the platform shell, inheriting cwd and the three streams exactly like a plugin or the compiler does. Extra args are appended positionally -- the same contract `npm run` already has, and the reason for `"$@"` rather than string concatenation: an argument containing a space must not become two. -
askedVersion
What the pinned compiler reports of itself, aspinrecorded it; null when a lock predates the key and no refresh has backfilled it.Read rather than asked: the value is a property of the pinned bytes, so the digest every run already checks is what keeps it honest. Says nothing about a
FLIX_JARoverride -- seereportOverrideGap(flixw.Lock, java.nio.file.Path)for those bytes. -
report
-
listCache
The cache inventoryinfo --verboseprints, rendered by a companion asset.Stage 0 resolves the JDKs and hands them over; the asset walks the cache and formats. That split is the point: enumerating JDKs runs
java -versionover a search path and decides what counts, which is selection policy -- a second copy of it could disagree with the one that actually picks the JVM, and the table a person reads would be the one that never runs. Walking documented cache paths decides nothing, so it goes where the formatting is.Never fatal. Concise
infohas already printed by the time this is reached, and a wrapper that could not describe its own state without a network would be worse than one that describes less of it. -
purgeCache
static void purgeCache(int days, boolean yes) Runs the cache lifecycle half of the inspector without requiring a project.This is explicit and age-based rather than automatic: the cache is shared by projects, and a wrapper looking at one checkout has no authority to decide which other checkout may need offline bytes tomorrow. A caller who chooses a retention window is making that trade-off deliberately. The inspector protects the default JDK, this release's companion assets and all stage-0 classes; it considers the its own per-artifact usage record for everything else.
-
inspectContext
What the inspector is told, as opposed to what it looks up.Line-based rather than JSON: both ends ship in one release, neither has a parser, and a reader for six fields and three tables would cost more than the format documents. Tabs separate columns, so no value here may contain one -- versions, digests and paths do not.
-
cachedJdkDirs
<cache>/jdks/*: the trees the provisioner unpacked. -
printAligned
Prints a two-column list with its first two columns aligned, so that a listing whose entries vary wildly in length --0.75.2beside0.75.3+stable.names.4-- reads as a table instead of a ragged column of annotations nobody can scan. -
pad
-
humanSize
A byte count as a person reads it; cached JARs and JDKs are always well above 1 KB. -
checkCanonical
Compares an installed file with the bytes this release ships, by digest.By digest rather than by text because the text is no longer here -- it is in the installer asset. The check is the same check: the answer to "is this the shim flixw wrote" is identical whether it comes from comparing 6KB of shell or 64 hex digits, and this way it needs no fetch. What is lost is the ability to say *how* it differs, which this never said anyway.
-
canonicalAttrs
The line endings the flixw block pins for one shipped path. -
changesEndings
Does a later rule leavetextoreolsaying something other than the block does? git resolves attributes one at a time, so a rule reaches only those it names: the block setslinguist-vendoredbeside the endings, and a project that turns that back off has not touched what this check protects.A token that is not
textoreolmay still be either of them wearing a macro's name, which is whymacrosis passed rather than assumed empty:binaryis git's own, expands to-diff -merge -text, and un-pins the endings while naming neither. Expansion recurses once with no macros, so a macro defined in terms of itself cannot loop. -
attrMacros
The macros in force for this file: git's built-inbinary, plus any the file defines itself. Config-defined macros are out of reach and deliberately so — they are not committed, so they describe one clone rather than the project. -
patternMatches
Does one .gitattributes pattern match one path flixw ships? -
checkGitattributes
gitattributes resolves by *last* matching pattern, so a rule after the wrapper block silently overrides it -- and a checked-out shim with the wrong line endings is exactly the failure the block exists to prevent. What counts as an override is the resulting attribute, not the mere presence of a later rule: a repetition of what the block already says changes nothing, and neither does a rule setting some unrelated attribute on the same path. Calling either harmful would send someone hunting for a problem they do not have. -
count
-
git
Runsgit <args>in root; null when git is absent or the command fails to start. -
check
Every check, printed; the count is the caller's to act on. -
writeAtomic
Same-directory temp plus an atomic move. A direct write is not a single event: a termination or a power loss in the middle of one leaves a truncated manifest or a half-written lock, and the rollback that was supposed to cover that cannot run either. Renaming a complete file over the old one has no such window.- Throws:
IOException
-
restore
Best-effort rollback; a failed restore must not mask the failure being reported. -
localCompilerFile
Mutable local state; lock.toml remains the committed, verified fallback. -
readLocalCompiler
A malformed selection is fatal, never an implicit switch to another compiler. -
writeLocalCompiler
-
clearLocalCompiler
-
selectLocalCompiler
Resolves either a built compiler JAR or a Flix checkout containing Mill's output. -
editorJarPrefsFile
.flixw/local/editor-jar.toml: a per-machine preference for how./flix.jar-- the file the official VS Code Flix extension checks for at a workspace root, before its own global cache and before it ever downloads anything itself -- is kept in sync with the pin. Not a lock setting and never committed: whether a symlink is even permitted, and which volume the cache lives on relative to the project, both vary by machine, so this belongs beside.flixw/local/java. -
readEditorJarPref
-
writeEditorJarPref
-
ownsEditorJar
Whetherlinkis a file this project's own flixw put there -- a symlink resolving into this machine's compiler cache, or a regular file (a copy, or a hard link, indistinguishable from one on disk) whose digest matches what was last recorded here. Anything else is a stranger's file, real or coincidental, and is never silently replaced. -
ownsEditorJar
Also recognizes a selected local link, including one broken by a clean build. -
tryEditorJarLink
Attempts a symlink or hard link; failure lets the caller try its fallback. -
ensureGitignored
One line, appended if missing --/flix.jaris generated, machine-specific state, the same reason.flixw/local/itself is never committed. No marked block: unlike.gitattributes, this is one static line with nothing to regenerate, so "already present" is the only question worth asking. -
maintainEditorJar
Keeps./flix.jarpointing at exactly the JAR this pin just verified, for the one consumer that looks for it: the official VS Code Flix extension, which checks a workspace root before its own global cache and before it ever downloads anything. flixw itself never reads this file.A symlink is tried first, always, regardless of any recorded preference -- it costs nothing to keep current, and once a machine's symlink privilege changes this silently upgrades it off the copy fallback with no separate action. A hard link is tried next, for Windows without that privilege, but only succeeds on the same volume as the cache, which a project directory has no reason to be. Only once both fail does this ever fall back to a plain copy, which can go stale the moment a future pin moves the digest --
doctorchecks a copy's digest against the current pin for exactly that reason.requestedModeis--editor-jar's value this run, or null; it, and only it, can authorise replacing a file this project's flixw did not create. -
cachedFor
The cached jar an earlierpinor run fetched for exactly this repository and version, or null -- and then pin downloads, as it always did.Re-pinning used to download unconditionally, because
flix.jarhas no published checksum and the download was the only source of the digest. The cache already holds both halves of that answer: the jar's name carries its digest, andfetchedFrom(java.lang.String)lists the URLs a download actually produced those bytes from. So a second project, or the same one re-pinned, needs no network -- and a GitHub hiccup can no longer fail a pin whose bytes are already on disk.pinstill re-hashes the jar before trusting its name.A jar qualifies only if the URL this pin would fetch is among them: upstream's one constructed URL, or either of a fork's two asset names under the exact tag. When several builds of one tag are cached -- an asset replaced under the same tag, both pinned with
--fetch-- the one the lock already names wins, and without that there is nothing to choose by: null, download. -
pin
-
updateWrapper
doctor --fix: the asset rewrites the files it owns, stage 0 refreshes the lock, and the two counts are added up here.Split that way because the lock is stage 0's alone -- it is the one file in the project whose *meaning* the wrapper has to understand, and `refreshLock` rewrites it from values it has already validated. Handing that to the installer would give a fetched asset write access to the trust root.
-
warnMissingJava
-
tomlEscape
The two escapes a TOML basic string needs. Every other lock value is pattern-checked into a shape that cannot contain either, so this exists for the one free-text key: a description comes from a plugin's manifest and is only whitespace-collapsed. -
lockText
-
refreshLock
- Throws:
IOException
-
refreshPin
`./flixw pin --refresh`. Offline: the compiler is not re-resolved, not re-downloaded and not re-hashed, and the pin does not move. What changes is the file's shape -- the `#:schema` line a lock written before it existed does not carry, the recorded wrapper version, the layout -- which is why it is a form of `pin` and not of `upgrade`. -
olderOrSame
Is `a` no newer than `b`? Both are the wrapper's own dotted versions. -
num
-
latestBase
Wherewrapper --upgradelooks for the newest release.latest/downloadresolves without asking an API anything. Overridable the same shapeFLIXW_ASSET_SOURCEgives the companion assets, and for the same reason: without it this path cannot be tested at all. The suite could assert that upgrade declines to walk backwards and nothing else, so the half that actually moves a project -- fetch, verify, refuse a downgrade, hand the verified bytes to the setup asset -- ran for the first time only in somebody's project.That is the worst place for a first run: upgrading is the one command whose failure leaves a user with no way forward, because the way forward *is* upgrading.
Note that GitHub's
latestskips pre-releases, so a 0.x pre-release is deliberately not offered here -- an adopter asks for one by tag, or by--pre-release(seelatestPrereleaseTag()) for whichever is newest. -
releaseBase
Where one release's assets live: a named version's, or whateverlatestmeans.FLIXW_RELEASE_SOURCEstill wins over both. It names one release outright -- a mirror, or a staging directory during a test -- so a version argument has nothing left to select, and quietly appending one to it would ask for a release inside a release. -
latestPrereleaseTag
Thetag_nameof the single most recently published flixw release, whether or not it is a pre-release -- which is the one thing/releases/latestcannot say, by GitHub's own design.--upgrade --pre-releaseexists becausereleaseBase(java.lang.String)'slatestshortcut needs no API quota but is exactly the thing that stays blind to a release still finishingverifyin.github/workflows/release.yaml: published as a pre-release, promoted only once the regression suite passes. Reaching it before promotion means asking a different endpoint, one that does not filter -- the releases API returns newest-first by creation date, so the first entry is the one wanted regardless of its own pre-release flag, andper_page=1keeps the response to that one object.Extraction is a single regex rather than a JSON parser: stage 0 has no dependency to spend on one, and a release object is large -- pulling one field out of it costs less than reading the rest to throw it away.
extractTagName(java.lang.String)is the pure half of this, split out so the parsing can be asserted without a live request. -
extractTagName
The first"tag_name"value in a GitHub releases API response, or null. -
digestFor
The digest aSHA256SUMSfile names for one file, or null if it does not. -
sumsName
The file name in oneSHA256SUMSline.GNU coreutils marks a file it read in binary mode with a
*before the name, and on Windows that is the default -- so a mirror whose digests were generated there lists*flixw.java, and an exact comparison finds nothing. The failure is then "no digest for flixw.java" while the digest is plainly in the file.flixw's own releases are built on Linux and never carry the marker; this is for everyone else's.
-
publishedAssets
Every companion asset a release publishes, read out of that release's ownSHA256SUMSrather than from a list in here.That is the difference between warming the assets this stage 0 knows about and warming the ones the release actually has. An upgrade runs in the *old* stage 0, which cannot know what the new release added -- so a hard-coded list would silently stop warming the day a fourth asset shipped, and nothing would report it. Reading the manifest means an older wrapper warms assets it has never heard of.
flixw.javaitself is excluded: it is the wrapper, not a companion to it, and the upgrade installs it by a different route. -
warmAssets
Fetches and verifies every companion asset of one release into the cache, so that the commands needing them work offline afterwards.Best-effort per asset, and never fatal. Warming is an optimisation on a command that has already done its real work: an upgrade that installed a new stage 0 and then failed to pre-fetch a completion generator has still upgraded, and the asset will be fetched on demand the first time it is wanted. Failing the upgrade over it would turn a slow network into a broken wrapper.
- Returns:
- how many assets are now cached and verified for that version
-
upgradeWrapper
Moves this project to the newest published flixw --latest's pick, a version named outright, or, withpre, the newest release regardless of its own pre-release flag (seelatestPrereleaseTag()). The old `--upgrade` rewrote the files from the stage 0 already in the tree, which is a repair rather than a version change -- so it printed a note on every run explaining that it had not done what its name says. That repair is now `./flixw doctor --fix`, and this does what the word means. The new stage 0 installs itself. It is the only thing that knows its own shim bytes, and having the old one write files for a version it has never seen is how the two drift apart. The digest is checked against the SHA256SUMS published beside it -- same origin, same TLS, so this catches a corrupted or truncated download and not a compromised release. That is the same footing as the compiler pin, and docs/LIMITATIONS.md says so; a self-update is simply where it matters most. -
wrapperNamespace
flixw's own namespace.wrapperUsage(java.lang.String)is the one list of what it offers. One verb, and every flixw-only operation under it as a flag. These are not stand-ins for anything Flix might one day ship, so they neither retire nor compete for a name with something that will: `pin`, `info`, `doctor` and `validate` deliberately collide with names Flix could claim, and step aside the day it does. Rewriting flixw's own files, or reporting flixw's own version, never will. Answered before the project, the lock, the network and the compiler, for the same reason the flags it replaces were: a bare verb is subject to compiler-first dispatch, and a compiler that happened to claim `wrapper` would make these unreachable at exactly the moment someone needs them to repair the installation. FLIX_BACKEND does not reach them either. -
wrapperUsage
-
completionEarly
completion, answered before the project is resolved -- and enriched from the cache if there is one.It is intercepted this early because the script is what somebody generates while setting up a shell, routinely before any flixw project exists on the machine; requiring one would make the setup step depend on having finished the setup. But a project *is* the interesting case, so the lock and the verb record are read here directly -- both are file reads. Nothing is acquired, launched or downloaded: a completion is not worth a compiler download, and a project whose compiler is not cached yet still gets a working script built from the verbs flixw knows.
The verb set decides its own dispatch. If a pinned compiler has claimed
completion, this stands aside and lets compiler-first routing take it, exactly as a bare wrapper verb would -- which is why the word is not inWRAPPER_VERBS: it is not answered from there, so listing it would advertise a route that does not run.Note: because completion runs before compiler acquisition,
jarandjvmare passed as null tohelpContext(java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String, boolean);flixw-cli.java'stree()model must never probe or launch a subprocess during tree construction. -
completionShell
The one shell name in these arguments, validated.Both entry points ask this rather than parsing for themselves. They validated separately at first, which is two chances to disagree about what a shell name is, on a command whose whole contract is that it produces the same bytes either way.
-
completionScript
static void completionScript(List<String> args, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity) The project-independent completer, on stdout.Reached from two places on purpose: early in
realMain(java.util.List<java.lang.String>), so it answers with no project at all, and from the wrapper verb, so `./flixw completion fish` inside a project takes the same path and cannot produce different bytes. -
storedHelp
The stored help for this compiler, re-verified against its own provenance record.The digest in
.helpmetais not decoration: this is the one place it is read, and without the check a truncated or edited.helpwould be rendered as the compiler's own words for as long as that cache entry lived. Returning null re-runs the capture, which is the same answer a missing record already gets. -
helpContext
static String helpContext(Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, boolean override) Everything the renderer is given, so it re-gathers none of it; seehelpTopic(java.util.List<java.lang.String>, java.nio.file.Path, flixw.Lock, java.nio.file.Path, flixw.Jvm, java.util.List<java.lang.String>, java.lang.String, java.util.List<java.lang.String>, boolean). -
esc
Escapes a value for the tab-separated rows above.Load-bearing for tasks specifically. A task is an arbitrary shell string the project wrote, and nothing stops it holding a tab or a newline -- a lock's decoded
\\nreaches here as a real one -- which would split one row into two, or shift every field after it by one. The renderer reverses this, so the two must change together. -
helpTopic
static void helpTopic(List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts, boolean degrade) Only interactive help may degrade. -
renderHelp
static int renderHelp(List<String> rest, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts) throws IOException Runs the renderer and deletes its context.- Throws:
IOException
-
compilerVerbHelp
static boolean compilerVerbHelp(String verb, String flag, Path root, flixw.Lock lock, Path jar, flixw.Jvm jvm, List<String> compilerVerbs, String identity, List<String> jvmOpts) On renderer failure, launch the original compiler argv. -
renderWrapperHelp
-
renderWrapperHelp
-
offlineHelp
Help with no renderer: the routing table, then the compiler's own captured help.This is the path when the asset or picocli cannot be fetched, and it must not be worse than what
./flixw helpdid before there was a renderer at all -- that printed the wrapper's table *and* the compiler's, and it worked on a cold network because the compiler was already on disk. Both halves survive here, and the compiler half now needs no subprocess either: it is the text the last capture stored, verified against its own digest on the way out. -
runSetupAsset
Runs the installer asset, fetching and verifying it first.A child process rather than an in-process call, for the same reason the JDK provisioner is one: it is a separate program with its own diagnostics, and its exit status is the answer, and its messages go to this process's own streams.
-
assetSourceBase
Wrapper-owned, not a plugin -- fetched and verified against the release this stage 0 itself is, never installed by a user and never carrying the "3rd-party, unaudited" warning a real plugin does. Overridable the same shapeFLIX_DIST_URLgives the compiler's own distribution base: a self-hosted mirror, or (unset in production) a local fixture for this project's own tests. -
assetDir
Version-keyed, so a release's assets can be cached forever: the entry cannot go stale except by a new release, which is exactly when this path moves. -
readSums
The digest manifest for one release base, from wherever that base points.A
file://base is not a mirror, it is this project's own tests standing a release up locally -- and the JDK HTTP client refuses the scheme outright rather than falling back, so the two cases cannot share one code path. Factored out because they went out of step once already: warming read the manifest with httpGet while fetching read it with this, so `install` threw a raw IllegalArgumentException with no FLIXW code the first time it ran against a fixture. -
fileUrlHint
Says what is wrong with afile://URL that a shell wrote and a JVM cannot read.Git Bash reports paths as
/d/a/proj, which is meaningful to it and to nothing else:file:///d/a/projresolves to\d\a\projon the current drive, and nothing is there. The failure is then a diagnostic naming a path the user never typed, in a form they do not recognise, with no clue that the shell rewrote it.Only offered when it applies -- a Windows path with no drive letter -- so it does not become noise on every unreadable file.
-
ensureAsset
-
ensureAsset
The version is a parameter becausewrapper --upgradewarms the assets of the release it is upgrading *to*, from the stage 0 it is upgrading *from*. Everything else asks for its own. -
main
The one entry point. Every failure inside is aflixw.Fail, which carries both theFLIXWnnncode printed on stderr and the advisory exit status; nothing else writes an exit status, so a code the user's own program returns cannot be confused with one of ours by accident of where it was thrown.- Parameters:
args- the wrapper's argv, passed on to the compiler unchanged when dispatch decides the compiler owns them
-
realMain
-
exactCompilerHelp
-
isHelpFlag
-
routingNotice
Which side handled a verb, under FLIXW_TRACE only. It used to print on every wrapper-handled command, and it told the caller what they had already said: typing `./flixw doctor` and being told that doctor went to the wrapper is not news. Worse, it read as a warning -- something had happened worth mentioning -- when nothing had. The hot path was already silent; now the rest is too, and the routing is still visible to anyone debugging it. -
wrapperHelp
static void wrapperHelp()The last-resort help when the renderer itself cannot be reached. -
sourceLaunchPath
The .java file this stage 0 was launched from, or null when it is running as the compiled class out of the cache. A source launch knows its own path, and that knowledge outranks FLIXW_SOURCE. FLIXW_SOURCE is the shim telling the *compiled* stage 0 which source it was built from; it says nothing about a stage 0 launched by path. `wrapper --upgrade` hands its environment to a freshly downloaded stage 0 in a temporary directory, which is a different file in a different project-less place -- and believing the inherited variable there anchored the new wrapper in the old project, where a lock exists, so `install` was no longer first contact and went to the compiler: `Unrecognized file extension: 'install'.` Every upgrade failed that way. -
selfSource
-
recordJava
Leaves the shim a note saying which JDK this project resolved to, so the next run can start on it instead of starting on whatever `java` is first on PATH and then relaunching. Without it a project that pins a Java the machine does not use by default pays a whole extra stage 0 -- about 100ms -- on every command. Machine-specific, therefore not committed: `.flixw/.gitignore` keeps `local/` out of git, and flixw writes that file itself rather than editing the project's own .gitignore. It names an executable the shim will run, which sounds like a new trust boundary and is not one: anyone who can write `.flixw/local/` can edit `./flixw` itself, which is simpler and does more. Every failure here is discarded. A read-only checkout, a directory someone deleted, a race with another run -- none of it is worth a diagnostic for a cache whose only job is to save a process start, and whose absence is already the old behaviour. -
relaunch
At most one relaunch, guarded by an env marker, so a stale release file cannot loop. -
awaitWithReaper
Waits for a child that owns the terminal, and guarantees it dies with us. Java has no exec(2): stage 0 must stay resident for the child's whole life. The child keeps the terminal, so SIGINT reaches it through the foreground process group. The hook covers the rest: without it, a SIGTERM to stage 0 orphans a compiler that then runs forever. SIGKILL still orphans it -- no Java code can prevent that, and the README says so. The relaunch path shares this. It used to wait bare, so terminating a stage 0 that had relaunched itself into another JVM orphaned the entire subtree beneath it -- the same defect the compiler launch had a hook for, one process further down.- Throws:
InterruptedException
-
javaHomeOf
exe's JDK home: two directories up frombin/java. Null whenexehas no parent, which cannot happen for a real path but costs nothing to guard. -
pluginEnv
static Map<String,String> pluginEnv(Path root, flixw.Lock lock, flixw.Jvm jvm, Path compilerJar, String pluginName, flixw.ResolvedPlugin p, List<String> args) The context a plugin ABI version 1 promises: a flat environment-variable tier for the common case, plusFLIXW_CONTEXTnaming a versioned JSON file for anything structured. Both are built here, once, for every format --.flixincluded: stock Flix'sSys.Env.getVarreads these even though a.flixplugin cannot receiveargs(verified against a real compiler, not assumed), so the ABI is the one thing every format can rely on regardless of whether it can take CLI arguments. Compiler and Java fields are simply absent when this project has no lock yet or no Java was resolved -- a `.jar`/`.java` plugin that does not need a compiler must not be handed a context it has to guess is incomplete. -
writeContextFile
static Path writeContextFile(Path root, flixw.Lock lock, flixw.Jvm jvm, Path compilerJar, String pluginName, flixw.ResolvedPlugin p, List<String> args) The structured half of the ABI: everythingpluginEnv(java.nio.file.Path, flixw.Lock, flixw.Jvm, java.nio.file.Path, java.lang.String, flixw.ResolvedPlugin, java.util.List<java.lang.String>)'s flat variables carry, plus the arguments this invocation was given, as one versioned JSON object. Written to a fresh temp file per invocation and deleted by a shutdown hook -- not a `finally` in the caller, becauseSystem.exit(int)does not run one. -
runArtifact
static void runArtifact(Path artifact, Path javaExe, Path compilerJar, List<String> args, Map<String, String> env) Launches one plugin artifact as an opaque subprocess, inheriting cwd and the three streams exactly likelaunch(java.nio.file.Path, java.util.List<java.lang.String>, java.nio.file.Path, java.util.List<java.lang.String>)does for the compiler -- three formats, one launcher, because a plugin is not otherwise different from the compiler stage 0 already knows how to run.envis the ABI: everythingpluginEnv(java.nio.file.Path, flixw.Lock, flixw.Jvm, java.nio.file.Path, java.lang.String, flixw.ResolvedPlugin, java.util.List<java.lang.String>)built, merged into the child's environment alongside whatever it already inherits..flixalways runs against *this project's own pinned compiler*, never a version the plugin names: a plugin can extend what Flix does here, not choose which Flix does it, so it cannot pull in a second, unverified compiler. A.flixplugin cannot receiveargs: stock Flix has norun <file>mode --run"runs main for the current project" and refuses a file argument outright -- so the only way to execute one standalone is the bare-file form (java -jar flix.jar plugin.flix), and there every extra positional word is parsed as one more source file to compile, not a program argument -- verified against a real compiler, not assumed. A.jaror.javaplugin wanting arguments is the workaround until Flix's own CLI grows one; every format can still read the ABI's environment variables andFLIXW_CONTEXT. -
autoRunBoundary
run <word>, with no leading flag and no--already, can only mean a forgotten forwarding boundary for upstream Flix: unlikecheck/test, where the same shape is a legitimate extra file to compile, stockrunrejects a bare trailing word outright ("does not support file arguments") rather than trying to load it. That fact was verified against flix/flix, not against every fork orFLIX_JARoverride -- a fork'srunmay legitimately define its own positional operand, and inserting--in front of it would silently turn that operand into a forwarded program argument instead. Callers gate this onisUpstream(flixw.Lock, boolean); it is not re-checked here; a leading flag is left alone regardless -- telling--entrypoint's value from the boundary needs the same value-taking-option knowledgeexamples' ownsplitVerbFlagshas, which would mean carrying that parser for every compiler verb here rather than the one place it already earns its keep. -
launch
Inherit cwd and the three streams; propagate the child's status.
-