11use anyhow:: Context as _;
22
3- use crate :: core:: Workspace ;
43use crate :: CargoResult ;
54use crate :: Config ;
65
@@ -9,21 +8,13 @@ const DEFAULT_EDITION: crate::core::features::Edition =
98const DEFAULT_VERSION : & str = "0.0.0" ;
109const DEFAULT_PUBLISH : bool = false ;
1110
12- pub struct RawScript {
13- manifest : String ,
14- body : String ,
15- path : std:: path:: PathBuf ,
16- }
17-
18- pub fn parse_from ( path : & std:: path:: Path ) -> CargoResult < RawScript > {
19- let body = std:: fs:: read_to_string ( path)
20- . with_context ( || format ! ( "failed to script at {}" , path. display( ) ) ) ?;
21- parse ( & body, path)
22- }
23-
24- fn parse ( body : & str , path : & std:: path:: Path ) -> CargoResult < RawScript > {
25- let comment = match extract_comment ( body) {
26- Ok ( manifest) => Some ( manifest) ,
11+ pub fn expand_manifest (
12+ content : & str ,
13+ path : & std:: path:: Path ,
14+ config : & Config ,
15+ ) -> CargoResult < String > {
16+ let comment = match extract_comment ( content) {
17+ Ok ( comment) => Some ( comment) ,
2718 Err ( err) => {
2819 log:: trace!( "failed to extract doc comment: {err}" ) ;
2920 None
@@ -38,83 +29,19 @@ fn parse(body: &str, path: &std::path::Path) -> CargoResult<RawScript> {
3829 }
3930 }
4031 . unwrap_or_default ( ) ;
41- let body = body. to_owned ( ) ;
42- let path = path. to_owned ( ) ;
43- Ok ( RawScript {
44- manifest,
45- body,
46- path,
47- } )
48- }
49-
50- pub fn to_workspace < ' cfg > (
51- script : & RawScript ,
52- config : & ' cfg Config ,
53- ) -> CargoResult < Workspace < ' cfg > > {
54- let target_dir = config
55- . target_dir ( )
56- . transpose ( )
57- . unwrap_or_else ( || default_target_dir ( ) . map ( crate :: util:: Filesystem :: new) ) ?;
58- // HACK: without cargo knowing about embedded manifests, the only way to create a
59- // `Workspace` is either
60- // - Create a temporary one on disk
61- // - Create an "ephemeral" workspace **but** compilation re-loads ephemeral workspaces
62- // from the registry rather than what we already have on memory, causing it to fail
63- // because the registry doesn't know about embedded manifests.
64- let manifest_path = write ( script, config, target_dir. as_path_unlocked ( ) ) ?;
65- let workspace = Workspace :: new ( & manifest_path, config) ?;
66- Ok ( workspace)
67- }
68-
69- fn write (
70- script : & RawScript ,
71- config : & Config ,
72- target_dir : & std:: path:: Path ,
73- ) -> CargoResult < std:: path:: PathBuf > {
74- let hash = hash ( script) . to_string ( ) ;
75- assert_eq ! ( hash. len( ) , 64 ) ;
76-
77- let file_name = script
78- . path
79- . file_stem ( )
80- . ok_or_else ( || anyhow:: format_err!( "no file name" ) ) ?
81- . to_string_lossy ( ) ;
82- let separator = '_' ;
83- let name = sanitize_package_name ( file_name. as_ref ( ) , separator) ;
84-
85- let mut workspace_root = target_dir. to_owned ( ) ;
86- workspace_root. push ( "eval" ) ;
87- workspace_root. push ( & hash[ 0 ..2 ] ) ;
88- workspace_root. push ( & hash[ 2 ..4 ] ) ;
89- workspace_root. push ( & hash[ 4 ..] ) ;
90- workspace_root. push ( name) ;
91- std:: fs:: create_dir_all ( & workspace_root) . with_context ( || {
92- format ! (
93- "failed to create temporary workspace at {}" ,
94- workspace_root. display( )
95- )
96- } ) ?;
97- let manifest_path = workspace_root. join ( "Cargo.toml" ) ;
98- let manifest = expand_manifest ( script, config) ?;
99- write_if_changed ( & manifest_path, & manifest) ?;
100- Ok ( manifest_path)
101- }
102-
103- fn expand_manifest ( script : & RawScript , config : & Config ) -> CargoResult < String > {
104- let manifest = expand_manifest_ ( script, config)
105- . with_context ( || format ! ( "failed to parse manifest at {}" , script. path. display( ) ) ) ?;
106- let manifest = remap_paths (
107- manifest,
108- script. path . parent ( ) . ok_or_else ( || {
109- anyhow:: format_err!( "no parent directory for {}" , script. path. display( ) )
110- } ) ?,
111- ) ?;
32+ let manifest = expand_manifest_ ( content, & manifest, path, config)
33+ . with_context ( || format ! ( "failed to parse manifest at {}" , path. display( ) ) ) ?;
11234 let manifest = toml:: to_string_pretty ( & manifest) ?;
11335 Ok ( manifest)
11436}
11537
116- fn expand_manifest_ ( script : & RawScript , config : & Config ) -> CargoResult < toml:: Table > {
117- let mut manifest: toml:: Table = toml:: from_str ( & script. manifest ) ?;
38+ fn expand_manifest_ (
39+ content : & str ,
40+ manifest : & str ,
41+ path : & std:: path:: Path ,
42+ config : & Config ,
43+ ) -> CargoResult < toml:: Table > {
44+ let mut manifest: toml:: Table = toml:: from_str ( & manifest) ?;
11845
11946 for key in [ "workspace" , "lib" , "bin" , "example" , "test" , "bench" ] {
12047 if manifest. contains_key ( key) {
@@ -135,14 +62,13 @@ fn expand_manifest_(script: &RawScript, config: &Config) -> CargoResult<toml::Ta
13562 anyhow:: bail!( "`package.{key}` is not allowed in embedded manifests" )
13663 }
13764 }
138- let file_name = script
139- . path
65+ let file_name = path
14066 . file_stem ( )
14167 . ok_or_else ( || anyhow:: format_err!( "no file name" ) ) ?
14268 . to_string_lossy ( ) ;
14369 let separator = '_' ;
14470 let name = sanitize_package_name ( file_name. as_ref ( ) , separator) ;
145- let hash = hash ( script ) ;
71+ let hash = hash ( content ) ;
14672 let bin_name = format ! ( "{name}{separator}{hash}" ) ;
14773 package
14874 . entry ( "name" . to_owned ( ) )
@@ -166,9 +92,7 @@ fn expand_manifest_(script: &RawScript, config: &Config) -> CargoResult<toml::Ta
16692 bin. insert (
16793 "path" . to_owned ( ) ,
16894 toml:: Value :: String (
169- script
170- . path
171- . to_str ( )
95+ path. to_str ( )
17296 . ok_or_else ( || anyhow:: format_err!( "path is not valid UTF-8" ) ) ?
17397 . into ( ) ,
17498 ) ,
@@ -217,26 +141,8 @@ fn sanitize_package_name(name: &str, placeholder: char) -> String {
217141 slug
218142}
219143
220- fn hash ( script : & RawScript ) -> blake3:: Hash {
221- blake3:: hash ( script. body . as_bytes ( ) )
222- }
223-
224- fn default_target_dir ( ) -> CargoResult < std:: path:: PathBuf > {
225- let mut cargo_home = home:: cargo_home ( ) ?;
226- cargo_home. push ( "eval" ) ;
227- cargo_home. push ( "target" ) ;
228- Ok ( cargo_home)
229- }
230-
231- fn write_if_changed ( path : & std:: path:: Path , new : & str ) -> CargoResult < ( ) > {
232- let write_needed = match std:: fs:: read_to_string ( path) {
233- Ok ( current) => current != new,
234- Err ( _) => true ,
235- } ;
236- if write_needed {
237- std:: fs:: write ( path, new) . with_context ( || format ! ( "failed to write {}" , path. display( ) ) ) ?;
238- }
239- Ok ( ( ) )
144+ fn hash ( content : & str ) -> blake3:: Hash {
145+ blake3:: hash ( content. as_bytes ( ) )
240146}
241147
242148/// Locates a "code block manifest" in Rust source.
@@ -438,10 +344,12 @@ mod test_expand {
438344
439345 macro_rules! si {
440346 ( $i: expr) => { {
441- let script = parse( $i, std:: path:: Path :: new( "/home/me/test.rs" ) )
442- . unwrap_or_else( |err| panic!( "{}" , err) ) ;
443- expand_manifest( & script, & Config :: default ( ) . unwrap( ) )
444- . unwrap_or_else( |err| panic!( "{}" , err) )
347+ expand_manifest(
348+ $i,
349+ std:: path:: Path :: new( "/home/me/test.rs" ) ,
350+ & Config :: default ( ) . unwrap( ) ,
351+ )
352+ . unwrap_or_else( |err| panic!( "{}" , err) )
445353 } } ;
446354 }
447355
@@ -693,73 +601,6 @@ fn main() {}
693601 }
694602}
695603
696- /// Given a Cargo manifest, attempts to rewrite relative file paths to absolute ones, allowing the manifest to be relocated.
697- fn remap_paths (
698- mani : toml:: Table ,
699- package_root : & std:: path:: Path ,
700- ) -> anyhow:: Result < toml:: value:: Table > {
701- // Values that need to be rewritten:
702- let paths: & [ & [ & str ] ] = & [
703- & [ "build-dependencies" , "*" , "path" ] ,
704- & [ "dependencies" , "*" , "path" ] ,
705- & [ "dev-dependencies" , "*" , "path" ] ,
706- & [ "package" , "build" ] ,
707- & [ "target" , "*" , "dependencies" , "*" , "path" ] ,
708- ] ;
709-
710- let mut mani = toml:: Value :: Table ( mani) ;
711-
712- for path in paths {
713- iterate_toml_mut_path ( & mut mani, path, & mut |v| {
714- if let toml:: Value :: String ( s) = v {
715- if std:: path:: Path :: new ( s) . is_relative ( ) {
716- let p = package_root. join ( & * s) ;
717- if let Some ( p) = p. to_str ( ) {
718- * s = p. into ( )
719- }
720- }
721- }
722- Ok ( ( ) )
723- } ) ?
724- }
725-
726- match mani {
727- toml:: Value :: Table ( mani) => Ok ( mani) ,
728- _ => unreachable ! ( ) ,
729- }
730- }
731-
732- /// Iterates over the specified TOML values via a path specification.
733- fn iterate_toml_mut_path < F > (
734- base : & mut toml:: Value ,
735- path : & [ & str ] ,
736- on_each : & mut F ,
737- ) -> anyhow:: Result < ( ) >
738- where
739- F : FnMut ( & mut toml:: Value ) -> anyhow:: Result < ( ) > ,
740- {
741- if path. is_empty ( ) {
742- return on_each ( base) ;
743- }
744-
745- let cur = path[ 0 ] ;
746- let tail = & path[ 1 ..] ;
747-
748- if cur == "*" {
749- if let toml:: Value :: Table ( tab) = base {
750- for ( _, v) in tab {
751- iterate_toml_mut_path ( v, tail, on_each) ?;
752- }
753- }
754- } else if let toml:: Value :: Table ( tab) = base {
755- if let Some ( v) = tab. get_mut ( cur) {
756- iterate_toml_mut_path ( v, tail, on_each) ?;
757- }
758- }
759-
760- Ok ( ( ) )
761- }
762-
763604#[ cfg( test) ]
764605mod test_manifest {
765606 use super :: * ;
0 commit comments