@@ -14,12 +14,14 @@ use std::{
1414 fmt:: Write ,
1515 fs,
1616 io:: { BufRead , BufReader } ,
17- process:: Stdio ,
17+ path:: Path ,
18+ process:: { Command , Stdio } ,
1819 sync:: { Arc , Mutex } ,
1920} ;
2021
2122use anyhow:: { Context , Result , bail} ;
2223use indicatif:: { ProgressBar , ProgressStyle } ;
24+ use walkdir:: WalkDir ;
2325
2426use crate :: { generate, resolve:: LockedRoots , scanner:: AnnealArtifact , setup:: Tool } ;
2527
@@ -376,6 +378,193 @@ pub fn generate_lean_workspace(roots: &LockedRoots, artifacts: &[AnnealArtifact]
376378 write_if_changed ( & lean_generated_root. join ( "Generated.lean" ) , & generated_imports)
377379 . context ( "Failed to write Generated.lean" ) ?;
378380
381+ // 1. Write Manifest
382+ println ! ( "Writing modified manifest to generated workspace..." ) ;
383+ let lean_root = roots. lean_root ( ) ;
384+ let toolchain = crate :: setup:: Toolchain :: resolve ( ) ?;
385+ let toolchain_manifest_path =
386+ toolchain. root . join ( "backends" ) . join ( "lean" ) . join ( "lake-manifest.json" ) ;
387+ let user_manifest_path = lean_root. join ( "lake-manifest.json" ) ;
388+
389+ if toolchain_manifest_path. exists ( ) {
390+ let content = fs:: read_to_string ( & toolchain_manifest_path)
391+ . context ( "Failed to read toolchain manifest" ) ?;
392+ let mut manifest: serde_json:: Value =
393+ serde_json:: from_str ( & content) . context ( "Failed to parse toolchain manifest" ) ?;
394+
395+ // Change name to anneal_verification
396+ manifest[ "name" ] = serde_json:: Value :: String ( "anneal_verification" . to_string ( ) ) ;
397+
398+ // Read actual HEAD commit of Aeneas in toolchain
399+ let toolchain_aeneas_dir = toolchain. root . join ( "backends" ) . join ( "lean" ) ;
400+ let output = Command :: new ( "git" )
401+ . args ( [ "rev-parse" , "HEAD" ] )
402+ . current_dir ( & toolchain_aeneas_dir)
403+ . output ( )
404+ . context ( "Failed to run `git rev-parse HEAD` in toolchain Aeneas" ) ?;
405+
406+ if !output. status . success ( ) {
407+ bail ! ( "`git rev-parse HEAD` failed in toolchain Aeneas" ) ;
408+ }
409+ let aeneas_rev = String :: from_utf8 ( output. stdout )
410+ . context ( "Failed to parse git output" ) ?
411+ . trim ( )
412+ . to_string ( ) ;
413+
414+ // Inject aeneas dependency
415+ let aeneas_dep = serde_json:: json!( {
416+ "configFile" : "lakefile.lean" ,
417+ "inherited" : false ,
418+ "inputRev" : "main" ,
419+ "manifestFile" : "lake-manifest.json" ,
420+ "name" : "aeneas" ,
421+ "rev" : aeneas_rev,
422+ "scope" : "" ,
423+ "subDir" : null,
424+ "type" : "git" ,
425+ "url" : format!( "file://{}" , toolchain_aeneas_dir. to_str( ) . unwrap( ) )
426+ } ) ;
427+
428+ if let Some ( packages) = manifest[ "packages" ] . as_array_mut ( ) {
429+ packages. insert ( 0 , aeneas_dep) ;
430+ } else {
431+ bail ! ( "Manifest packages is not an array" ) ;
432+ }
433+
434+ let new_content = serde_json:: to_string_pretty ( & manifest)
435+ . context ( "Failed to serialize modified manifest" ) ?;
436+ fs:: write ( & user_manifest_path, new_content) . context ( "Failed to write user manifest" ) ?;
437+ } else {
438+ bail ! ( "Toolchain manifest missing at {}" , toolchain_manifest_path. display( ) ) ;
439+ }
440+
441+ // 2. Materialize Packages (Manual Copy)
442+ println ! ( "Materializing packages by copying from toolchain..." ) ;
443+ let user_project_packages = lean_root. join ( ".lake" ) . join ( "packages" ) ;
444+
445+ // Ensure .lake/packages exists
446+ fs:: create_dir_all ( & user_project_packages)
447+ . context ( "Failed to create .lake/packages directory" ) ?;
448+
449+ // Copy Aeneas
450+ let toolchain_aeneas_dir = toolchain. root . join ( "backends" ) . join ( "lean" ) ;
451+ let user_aeneas_dir = user_project_packages. join ( "aeneas" ) ;
452+
453+ if toolchain_aeneas_dir. exists ( ) {
454+ if user_aeneas_dir. exists ( ) {
455+ fs:: remove_dir_all ( & user_aeneas_dir)
456+ . context ( "Failed to remove existing Aeneas directory in workspace" ) ?;
457+ }
458+ let status = Command :: new ( "cp" )
459+ . args ( [ "-r" , toolchain_aeneas_dir. to_str ( ) . unwrap ( ) , user_aeneas_dir. to_str ( ) . unwrap ( ) ] )
460+ . status ( )
461+ . context ( "Failed to copy Aeneas directory" ) ?;
462+ if !status. success ( ) {
463+ bail ! ( "Failed to copy Aeneas directory from toolchain to workspace" ) ;
464+ }
465+
466+ // Add Git remote 'origin' to match manifest
467+ let status = Command :: new ( "git" )
468+ . args ( [
469+ "remote" ,
470+ "add" ,
471+ "origin" ,
472+ & format ! ( "file://{}" , toolchain_aeneas_dir. to_str( ) . unwrap( ) ) ,
473+ ] )
474+ . current_dir ( & user_aeneas_dir)
475+ . status ( )
476+ . context ( "Failed to run `git remote add` in Aeneas clone" ) ?;
477+ if !status. success ( ) {
478+ bail ! ( "`git remote add` failed in Aeneas clone" ) ;
479+ }
480+ }
481+
482+ // Copy dependencies
483+ let toolchain_packages_dir = toolchain. root . join ( "packages" ) ;
484+ if toolchain_packages_dir. exists ( ) {
485+ for entry in fs:: read_dir ( & toolchain_packages_dir)
486+ . context ( "Failed to read toolchain packages directory" ) ?
487+ {
488+ let entry = entry. context ( "Failed to read directory entry" ) ?;
489+ let path = entry. path ( ) ;
490+ if path. is_dir ( ) {
491+ let pkg_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
492+ let user_pkg_dir = user_project_packages. join ( pkg_name) ;
493+
494+ if user_pkg_dir. exists ( ) {
495+ fs:: remove_dir_all ( & user_pkg_dir)
496+ . context ( "Failed to remove existing package directory in workspace" ) ?;
497+ }
498+ let status = Command :: new ( "cp" )
499+ . args ( [ "-r" , path. to_str ( ) . unwrap ( ) , user_pkg_dir. to_str ( ) . unwrap ( ) ] )
500+ . status ( )
501+ . context ( "Failed to copy package directory" ) ?;
502+ if !status. success ( ) {
503+ bail ! ( "Failed to copy package directory for {}" , pkg_name) ;
504+ }
505+
506+ // Update Git remote URL to match manifest
507+ let status = Command :: new ( "git" )
508+ . args ( [
509+ "remote" ,
510+ "set-url" ,
511+ "origin" ,
512+ & format ! ( "file://{}" , path. to_str( ) . unwrap( ) ) ,
513+ ] )
514+ . current_dir ( & user_pkg_dir)
515+ . status ( )
516+ . context ( "Failed to run `git remote set-url` in package clone" ) ?;
517+ if !status. success ( ) {
518+ bail ! ( "`git remote set-url` failed in package clone for {}" , pkg_name) ;
519+ }
520+ }
521+ }
522+ }
523+
524+ // 3. Post-Process Traces in the Clone
525+ println ! ( "Post-processing traces in the clone..." ) ;
526+ let toolchain_aeneas = toolchain. root . join ( "backends" ) . join ( "lean" ) ;
527+ let toolchain_aeneas_str = toolchain_aeneas. to_str ( ) . unwrap ( ) ;
528+ let user_project_aeneas = user_project_packages. join ( "aeneas" ) ;
529+ let user_project_aeneas_str = user_project_aeneas. to_str ( ) . unwrap ( ) ;
530+ let toolchain_packages_str = toolchain_packages_dir. to_str ( ) . unwrap ( ) ;
531+ let user_project_packages_str = user_project_packages. to_str ( ) . unwrap ( ) ;
532+
533+ let process_build_dir = |dir : & Path | -> Result < ( ) > {
534+ if dir. exists ( ) {
535+ let walker = WalkDir :: new ( dir) . into_iter ( ) ;
536+ for entry in walker {
537+ let entry = entry. context ( "Failed to walk build directory" ) ?;
538+ let path = entry. path ( ) ;
539+ if path. is_file ( ) && path. extension ( ) . map_or ( false , |ext| ext == "trace" ) {
540+ let content = fs:: read_to_string ( path) . context ( "Failed to read trace file" ) ?;
541+ let mut new_content =
542+ content. replace ( toolchain_aeneas_str, user_project_aeneas_str) ;
543+ new_content =
544+ new_content. replace ( toolchain_packages_str, user_project_packages_str) ;
545+
546+ if new_content != content {
547+ fs:: write ( path, new_content) . context ( "Failed to write trace file" ) ?;
548+ }
549+ }
550+ }
551+ }
552+ Ok ( ( ) )
553+ } ;
554+
555+ // Process all packages in .lake/packages
556+ if user_project_packages. exists ( ) {
557+ for entry in
558+ fs:: read_dir ( & user_project_packages) . context ( "Failed to read user project packages" ) ?
559+ {
560+ let entry = entry. context ( "Failed to read directory entry" ) ?;
561+ let path = entry. path ( ) ;
562+ if path. is_dir ( ) {
563+ process_build_dir ( & path. join ( ".lake" ) . join ( "build" ) ) ?;
564+ }
565+ }
566+ }
567+
379568 Ok ( ( ) )
380569}
381570
0 commit comments