66//! `bundled/provenance.json`. Sharing gloam's acquisition code guarantees the
77//! bundled and `--fetch` provenance are produced identically.
88//!
9- //! `cargo xtask regen <tree-root> [--fresh]` regenerates every gloam output
10- //! tree found under `<tree-root>` (e.g. a gloam-pregen checkout) by re-running
11- //! the command line recorded in each tree's manifest with the current working
12- //! copy of gloam. By default each run is pinned to the tree's recorded
13- //! provenance (`--lock`), so `git diff` in the tree shows only the effect of
14- //! gloam code changes; `--fresh` runs the recorded commands verbatim instead,
15- //! advancing to upstream HEAD (the normal tree-update workflow).
9+ //! `cargo xtask regen [tree-root] [--fresh]` builds the working-copy gloam
10+ //! and runs `gloam regen` over `tree-root` (default: the current directory),
11+ //! regenerating every gloam output tree found beneath it (e.g. `examples/`
12+ //! here, or a gloam-pregen checkout). Discovery, path handling, and the
13+ //! locked-vs-fresh semantics all live in `gloam regen` itself; this task
14+ //! just supplies a freshly built binary.
1615
1716use std:: path:: { Path , PathBuf } ;
1817
@@ -21,7 +20,7 @@ use indexmap::IndexMap;
2120
2221use gloam:: provenance:: acquire:: Github ;
2322use gloam:: provenance:: manifest:: {
24- BundledProvenance , Manifest , ProvenancePin , SCHEMA_VERSION , preserve_unchanged_repos,
23+ BundledProvenance , ProvenancePin , SCHEMA_VERSION , preserve_unchanged_repos,
2524} ;
2625use gloam:: provenance:: { CLUSTERS , bundled_rel_path} ;
2726
@@ -48,23 +47,7 @@ fn regen(args: &[String]) -> Result<()> {
4847 other => bail ! ( "unexpected regen argument '{other}'" ) ,
4948 }
5049 }
51- let root = root. context ( "usage: cargo xtask regen <tree-root> [--fresh]" ) ?;
52- if !root. is_dir ( ) {
53- bail ! ( "tree root {} is not a directory" , root. display( ) ) ;
54- }
55- // Keep the path as given (no canonicalize: Windows turns those into
56- // \\?\ UNC paths, which is noise in every printed command). Child
57- // processes run with this as their cwd, so relative roots work too.
58-
59- // Every gloam manifest records the exact command line that produced its
60- // tree, so the tree set is self-describing: generation trees carry
61- // `.gloam/manifest.json`, lock snapshots are bare `manifest.json` files.
62- let mut manifests: Vec < PathBuf > = Vec :: new ( ) ;
63- find_manifests ( & root, & mut manifests) ;
64- manifests. sort ( ) ;
65- if manifests. is_empty ( ) {
66- bail ! ( "no gloam manifests found under {}" , root. display( ) ) ;
67- }
50+ let root = root. unwrap_or_else ( || PathBuf :: from ( "." ) ) ;
6851
6952 // Build and locate the working-copy gloam binary.
7053 let cargo = std:: env:: var ( "CARGO" ) . unwrap_or_else ( |_| "cargo" . to_string ( ) ) ;
@@ -81,93 +64,24 @@ fn regen(args: &[String]) -> Result<()> {
8164 . join ( "debug" )
8265 . join ( format ! ( "gloam{}" , std:: env:: consts:: EXE_SUFFIX ) ) ;
8366
84- let mut ran = 0usize ;
85- for manifest_path in & manifests {
86- let Some ( recorded) = recorded_command ( manifest_path) else {
87- continue ; // not a gloam manifest (or unreadable) — skip
88- } ;
89-
90- let rel = manifest_path. strip_prefix ( & root) . unwrap_or ( manifest_path) ;
91-
92- // Drop the recorded argv[0] ("gloam"); in locked mode, pin the run to
93- // the tree's own provenance. --lock must precede the subcommand, so
94- // it goes first. The path is root-relative because the child runs
95- // with the tree root as its cwd (recorded --out-path values are too).
96- let mut argv: Vec < String > = recorded
97- . split_whitespace ( )
98- . skip ( 1 )
99- . map ( String :: from)
100- . collect ( ) ;
101- if !fresh {
102- argv. splice ( 0 ..0 , [ "--lock" . to_string ( ) , rel. display ( ) . to_string ( ) ] ) ;
103- }
104- eprintln ! ( "· {} $ gloam {}" , rel. display( ) , argv. join( " " ) ) ;
105-
106- // Recorded --out-path values are relative to the tree root.
107- let status = std:: process:: Command :: new ( & bin)
108- . args ( & argv)
109- . current_dir ( & root)
110- . status ( )
111- . with_context ( || format ! ( "running gloam for {}" , rel. display( ) ) ) ?;
112- if !status. success ( ) {
113- bail ! ( "gloam failed for {}" , rel. display( ) ) ;
114- }
115- ran += 1 ;
67+ // `gloam regen` does the rest: recursive discovery, path handling, and
68+ // locked-vs-fresh replay. It runs with our cwd, so a relative root
69+ // behaves the same as it would for find/grep.
70+ let mut cmd = std:: process:: Command :: new ( & bin) ;
71+ cmd. arg ( "regen" ) ;
72+ if fresh {
73+ cmd. arg ( "--fresh" ) ;
11674 }
117-
118- if ran == 0 {
119- bail ! (
120- "found {} manifest.json file(s) under {}, but none recorded a gloam command line" ,
121- manifests. len( ) ,
122- root. display( )
123- ) ;
75+ cmd. arg ( & root) ;
76+ let status = cmd
77+ . status ( )
78+ . with_context ( || format ! ( "running {} regen" , bin. display( ) ) ) ?;
79+ if !status. success ( ) {
80+ bail ! ( "gloam regen failed" ) ;
12481 }
125-
126- eprintln ! ( "regenerated {ran} tree(s) under {}" , root. display( ) ) ;
127- eprintln ! ( "review with:" ) ;
128- eprintln ! (
129- " git -C {} diff -I'^ \\ * Generated by gloam ' -I'^ \" (version|describe|commit)\" : '" ,
130- root. display( )
131- ) ;
13282 Ok ( ( ) )
13383}
13484
135- /// Recursively collect `manifest.json` files under `dir`, skipping `.git`.
136- fn find_manifests ( dir : & Path , out : & mut Vec < PathBuf > ) {
137- let Ok ( entries) = std:: fs:: read_dir ( dir) else {
138- return ;
139- } ;
140- for entry in entries. flatten ( ) {
141- let path = entry. path ( ) ;
142- if path. is_dir ( ) {
143- if path. file_name ( ) . is_some_and ( |n| n == ".git" ) {
144- continue ;
145- }
146- find_manifests ( & path, out) ;
147- } else if path. file_name ( ) . is_some_and ( |n| n == "manifest.json" ) {
148- out. push ( path) ;
149- }
150- }
151- }
152-
153- /// The gloam command line recorded in a manifest, if the file parses as a
154- /// gloam manifest at the current schema and recorded one.
155- fn recorded_command ( path : & Path ) -> Option < String > {
156- let text = std:: fs:: read_to_string ( path) . ok ( ) ?;
157- let m = Manifest :: from_json ( & text) . ok ( ) ?;
158- if m. schema_version != SCHEMA_VERSION {
159- eprintln ! (
160- "· {}: skipping (schema_version {} != {})" ,
161- path. display( ) ,
162- m. schema_version,
163- SCHEMA_VERSION
164- ) ;
165- return None ;
166- }
167- let cmd = m. gloam . command_line ;
168- ( cmd. split_whitespace ( ) . next ( ) == Some ( "gloam" ) ) . then_some ( cmd)
169- }
170-
17185/// Best-effort read of the checked-in provenance manifest. Missing,
17286/// unreadable, or schema-mismatched files are ignored — the bundle is simply
17387/// recorded fresh at the newly resolved commits.
0 commit comments