77// This file may not be copied, modified, or distributed except according to
88// those terms.
99
10+ use anyhow:: Context as _;
1011use clap:: Parser as _;
1112
13+ mod charon;
14+ mod diagnostics;
15+ mod resolve;
16+ mod scanner;
17+ mod setup;
18+ mod util;
19+
1220/// Anneal
1321#[ derive( clap:: Parser , Debug ) ]
1422#[ command( name = "cargo-anneal" , version, about, long_about = None ) ]
@@ -21,50 +29,77 @@ struct Cli {
2129enum Commands {
2230 /// Setup Anneal dependencies
2331 Setup ( SetupArgs ) ,
32+ /// Expand a crate (runs Charon)
33+ Expand ( ExpandArgs ) ,
34+
35+ /// Helper to acquire shared or exclusive locks for multi-process integration testing (dev only)
36+ #[ cfg( feature = "exocrate_tests" ) ]
37+ TestLockHelper {
38+ /// The role to run as: 'reader-a', 'reader-b', 'writer-a', or 'reader-exclusion'
39+ #[ arg( long) ]
40+ role : String ,
41+ /// Path to the directory to lock
42+ #[ arg( long) ]
43+ lock_dir : std:: path:: PathBuf ,
44+ /// Path to the shared log file where lock transitions are appended
45+ #[ arg( long) ]
46+ log_file : std:: path:: PathBuf ,
47+ /// Path to the temporary synchronization signal file
48+ #[ arg( long) ]
49+ sig_file : std:: path:: PathBuf ,
50+ } ,
2451}
2552
2653#[ derive( clap:: Parser , Debug ) ]
2754pub struct SetupArgs {
28- /// Path to a local dependency archive to use instead of downloading.
55+ /// Path to a local dependency archive to use instead of downloading
2956 #[ arg( long, value_name = "path-to-local-archive" ) ]
3057 pub local_archive : Option < std:: path:: PathBuf > ,
3158}
3259
33- exocrate:: config! {
34- const CONFIG : Config = Config {
35- rel_dir_path: [ ".anneal" , "toolchain" ] ,
36- versioned_files: & [ "../Cargo.toml" , "../Cargo.lock" ] ,
37- } ;
60+ #[ derive( clap:: Parser , Debug ) ]
61+ pub struct ExpandArgs {
62+ #[ command( flatten) ]
63+ pub resolve_args : crate :: resolve:: Args ,
64+
65+ /// Controls where LLBC output is placed on the filesystem
66+ #[ arg( long, value_name = "output-dir" ) ]
67+ pub output_dir : Option < std:: path:: PathBuf > ,
68+
69+ /// Do not show compilation progress bars
70+ #[ arg( long) ]
71+ pub no_progress : bool ,
3872}
3973
40- exocrate:: parse_remote_archive! {
41- const REMOTE : RemoteArchive = "Cargo.toml" [
42- ( linux, x86_64) ,
43- ( macos, x86_64) ,
44- ( linux, aarch64) ,
45- ( macos, aarch64) ,
46- ] ;
74+ fn setup ( args : SetupArgs ) -> anyhow:: Result < ( ) > {
75+ crate :: setup:: run_setup ( crate :: setup:: SetupArgs { local_archive : args. local_archive } )
76+ . context ( "Failed to setup toolchain" )
4777}
4878
49- fn setup ( args : SetupArgs ) {
50- let location = if std:: env:: var ( "__ANNEAL_LOCAL_DEV" ) . is_ok ( ) {
51- exocrate:: Location :: LocalDev
52- } else {
53- exocrate:: Location :: UserGlobal
54- } ;
55- let source = match args. local_archive {
56- Some ( local_archive) => exocrate:: Source :: Local ( local_archive) ,
57- None => exocrate:: Source :: Remote ( REMOTE ) ,
58- } ;
59-
60- let installation_dir = CONFIG
61- . resolve_installation_dir_or_install ( location, source)
62- // FIXME: Implement unified error reporting (e.g., via `anyhow`).
63- . expect ( "failed to resolve-or-install dependencies" ) ;
64- log:: info!( "anneal toolchain is installed at {:?}" , installation_dir) ;
79+ fn expand ( args : ExpandArgs ) -> anyhow:: Result < ( ) > {
80+ let roots = crate :: resolve:: resolve_roots ( & args. resolve_args ) ?;
81+ let packages = crate :: scanner:: scan_workspace ( & roots) ?;
82+ if packages. is_empty ( ) {
83+ log:: warn!( "No targets found to expand." ) ;
84+ return Ok ( ( ) ) ;
85+ }
86+ let mut locked_roots = roots. lock_run_root ( ) ?;
87+ if let Some ( output_dir) = args. output_dir {
88+ locked_roots. llbc_override = Some ( output_dir) ;
89+ }
90+ let toolchain = crate :: setup:: Toolchain :: resolve ( ) ?;
91+ let show_progress = !args. no_progress ;
92+ crate :: charon:: run_charon (
93+ & args. resolve_args ,
94+ & toolchain,
95+ & locked_roots,
96+ & packages,
97+ show_progress,
98+ ) ?;
99+ Ok ( ( ) )
65100}
66101
67- fn main ( ) {
102+ fn main ( ) -> anyhow :: Result < ( ) > {
68103 // Suppressing timestamps removes a source of nondeterminism that is
69104 // difficult to work around in integration tests.
70105 env_logger:: builder ( ) . format_timestamp ( None ) . init ( ) ;
@@ -79,18 +114,55 @@ fn main() {
79114
80115 match args. command {
81116 Commands :: Setup ( args) => setup ( args) ,
117+ Commands :: Expand ( args) => expand ( args) ,
118+
119+ #[ cfg( feature = "exocrate_tests" ) ]
120+ Commands :: TestLockHelper { role, lock_dir, log_file, sig_file } => {
121+ crate :: util:: run_test_lock_helper ( & role, & lock_dir, & log_file, & sig_file)
122+ }
82123 }
83124}
84125
85126#[ cfg( test) ]
86127mod tests {
87128 #[ cfg( feature = "exocrate_tests" ) ]
88129 #[ test]
89- fn test_setup ( ) {
130+ fn test_setup_and_toolchain_paths ( ) {
131+ // 1. Run setup.
90132 super :: setup ( super :: SetupArgs {
91133 // ASSUMPTION: Dependency builder installs archive at
92134 // `target/anneal-exocrate.tar.zst`.
93135 local_archive : Some ( "target/anneal-exocrate.tar.zst" . into ( ) ) ,
94136 } )
137+ . expect ( "Failed to run setup" ) ;
138+
139+ // 2. Once setup completes successfully, resolve the toolchain.
140+ let toolchain = crate :: setup:: Toolchain :: resolve ( ) . expect ( "Failed to resolve toolchain" ) ;
141+
142+ // 3. Verify that all returned paths exist as directories.
143+ // Note: these assertions would be more appropriate in the setup.rs module,
144+ // but including them here avoids introducing multiple tests that attempt to
145+ // extract the (large) anneal exocrate archive.
146+ assert ! ( toolchain. root( ) . is_dir( ) , "root is not a directory: {:?}" , toolchain. root( ) ) ;
147+ assert ! (
148+ toolchain. aeneas_bin_dir( ) . is_dir( ) ,
149+ "aeneas_bin_dir is not a directory: {:?}" ,
150+ toolchain. aeneas_bin_dir( )
151+ ) ;
152+ assert ! (
153+ toolchain. rust_sysroot( ) . is_dir( ) ,
154+ "rust_sysroot is not a directory: {:?}" ,
155+ toolchain. rust_sysroot( )
156+ ) ;
157+ assert ! (
158+ toolchain. rust_bin( ) . is_dir( ) ,
159+ "rust_bin is not a directory: {:?}" ,
160+ toolchain. rust_bin( )
161+ ) ;
162+ assert ! (
163+ toolchain. rust_lib( ) . is_dir( ) ,
164+ "rust_lib is not a directory: {:?}" ,
165+ toolchain. rust_lib( )
166+ ) ;
95167 }
96168}
0 commit comments