code_passenger 0.3.0 — scans a workspace with klepto, then does the writing klepto never does:
feature gates across every crate, cargo edits, headers, reports, and the history of it all.
workspace features (new in 0.3.0)
one document at the workspace root says what every crate's features are.
it is a 1o document, v1.workspace.1o.features; features.toml is accepted
for the same document (keep one of the two):
{
features {
default {
feature "log"
}
feature {
name "log"
dep "store:logsink"
dep "app:logsink"
}
}
}
# features.toml, the same document
= ["log"]
[]
= ["store:logsink", "app:logsink"]
feature log with dep "store:logsink" means: crate store gets a feature
log, and its dependency logsink becomes optional behind it. one feature
can stack several dependencies and span every crate. default turns the
workspace features on by default in every crate that has them. a crate's own
lines (crate { name "app" ... }, [crates.app]) replace a list verbatim
where the derived one is not what that crate needs.
what happens, in one run for the whole workspace:
- each crate's klepto spec is derived from the document.
- klepto plans each crate's gates: every use of a dependency that is now
optional gets
#[cfg(feature = "log")]on its carrier, and everything in the crate depending on those gets one too. - across crates: when
appuses an itemstorenow gates,app'slogturns onstore's (store/log) and the item inappis gated the same way (a module-levelusegets ausegate). this repeats until nothing new is gated. - the cargo check: one scratch copy of the workspace holds every crate's edits, and every crate the plan touches, and every crate using one, is checked with every feature combination that matters. a compiler error klepto maps to an item becomes a gate and the workspace is planned again.
- with each feature off, the report says what goes: the items unavailable, the unit each one is (a function, an item, a whole module, a whole file, the whole crate), every use site with its unit, and the callers in other crates that lose them.
exit codes: 0 nothing to do, converged, or written; 1 check found work
or the cargo check gave up; 2 refused, with a code: [CP0020] something a
person has to decide (a carrier klepto cannot judge, a compiler error no gate
answers), [CP0021] --write --no-cargo without --unproven (an unproven
plan is written only when you say so). nothing is written on 1 or 2.
the document's keys, rendered from its schema (schema/features/v1.schema.json,
declared once; a test holds this table to it):
| 1o key | TOML | value | meaning |
|---|---|---|---|
features |
(the document) |
block, required | The one block of the document. |
features crate |
[crates.<name>] |
block | One crate's own lines. Repeats: one block per crate. |
features crate default |
default |
block | The crate's default list as Cargo spells it, replacing the derived one. |
features crate default feature |
default = ["<entry>", ...] |
string | One entry of the crate's default list. Repeats: one value per line, in order. |
features crate feature |
[crates.<name>.features] |
block | One feature's whole list in this crate, as Cargo spells it; it replaces the derived list, in this order. Repeats: one block per feature. |
features crate feature enable |
<feature> = ["<entry>", ...] |
string | One entry of the list: dep:x, x/feat, x?/feat or another feature. Repeats: one value per line, in order. |
features crate feature name |
<feature> |
string, required | The feature. |
features crate name |
<name> |
string, required | The crate, by its package name. |
features crate optional |
optional = ["<dependency>", ...] |
string | A dependency made optional with no workspace feature (Cargo's implicit feature). Repeats: one value per line, in order. |
features default |
default |
block | The workspace features on by default, in every crate that has them. Absent: each crate's default list stays as it is. |
features default feature |
default = ["<feature>", ...] |
string | A workspace feature on by default. Repeats: one value per line, in order. |
features feature |
[features.<name>] |
block | One workspace feature. Repeats: one block per feature. |
features feature dep |
deps = ["<crate>:<dependency>", ...] |
string | <crate>:<dependency>: the crate gets the feature, and the dependency becomes optional behind it. Repeats: one value per line, in order. |
features feature name |
<name> |
string, required | The feature's name, the same in every crate. |
init also copies the schema to .passenger/config/schema/ and lists that
folder in oneo.project.json, where core-1o's workspace (and so
language-server-1o) looks: the document is checked live while you edit it.
headers
every file gets a header between //! code_passenger:begin and
//! code_passenger:end, written from the features plan: for each feature
with an item of the file behind it, the dependencies the file uses that the
feature turns on, the units of the file behind it, the items unavailable
with it off and the callers in other crates that lose them. a file wholly
behind a feature carries it as #![cfg(feature = "...")]:
//! feature_name:log
//! deps:["logsink"]
//! scope:["file store/src/sink.rs"]
//! corpus:true
//! unavailable:["store::sink::flush", "store::sink::flush_twice"]
//!
//! ----------------------------------------------
//! CORPUS FEATURES ------------------------------
//!
#![cfg(feature = "log")]
a header describes gates the code has, so annotate refuses ([CP0023])
while the features plan has work left. without a document it plans the one
init would write.
history
features apply --write checkpoints the workspace into the passenger store
before and after it writes (scan.json, analysis.json, the plan and the
document beside the snapshot). the store is the workspace root's
(<root>/.passenger/), whatever directory you run from; it tracks the files
klepto's scan reads and the document.
checkout refuses ([CP0042]) when a tracked file changed since HEAD's
snapshot (checkpoint first, or --force); a file the snapshot does not
hold is left as it is.
agent mode
one template per kind. features is custodian_kit's job, written by its
agent layout: the eligibility reading (public API, dependents, reach) that
changes nothing. features-apply is code-passenger's, the job that edits,
in .custodian/config/jobs/features-apply.toml.
the features-apply job is a folder that moves queued → running → done. its
steps are code-passenger lines started by custodian_kit's executor: the plan
(proven, written into the folder), the apply of exactly that plan (it reads
the plan step's receipt and refuses if the code changed since), and the
headers (it reads the apply step's receipt). each step's receipt is in
.custodian/data/receipts/; the folder ends with closing.md and
closing.json.
the writers custodian routes to
custodian never edits a manifest or a source file itself; these do.
dep add without a version or a path is refused ([CP0060]) unless the
workspace table already holds the dependency; adding one that is there
updates its version and adds its features. dep remove refuses while a
feature still names the dependency ([CP0062]).
attr place puts one attribute line on the item at klepto's location of
it, by the rule the gates use: a #[cfg(...)] merges into the item's own
cfg (all(old, new)) or goes right above the declaration; any other
attribute goes above the item's first attribute, after its doc comments.
The same line already there is nothing to do. --item is klepto's id
(app::store::Engine::new), or crate::... for the file's own package; an
item klepto does not name in that file is refused ([CP0063]).
every command is a declared line
every command is declared once as an xccute line (simple_impl_derive), read
back from its words, validated, and decided by its own exit statuses; every
run ends with a receipt. with a .custodian/ folder the receipt is kept in
its journal, otherwise its digest is printed on stderr. both spellings work:
the program is behind the bin feature (on by default, so cargo install
keeps working); a library user turns it off with default-features = false
and gets no command line.
one crate, a klepto.toml spec (0.2.0's loop, unchanged)
# klepto.toml — move `beta` behind a feature `b` in package `app`
[]
= ["beta"]
= []
[]
= ["dep:beta"]
review before you gate
--json on any of them prints the structure instead of the text.
the rest of klepto, on the command line
notes
- klepto 0.3.1 and custodian_kit 0.1.0 come from crates.io; there are no path dependencies.
- the cargo check runs
cargooffline; path dependencies only, nothing is downloaded and nothing outside the scratch copy is touched. - edits inside macro bodies are out of scope; carriers klepto cannot name
are listed under
unknownand a person decides.