1
1
use anyhow:: Context as _;
2
2
3
- use crate :: core:: Workspace ;
4
3
use crate :: CargoResult ;
5
4
use crate :: Config ;
6
5
@@ -9,21 +8,13 @@ const DEFAULT_EDITION: crate::core::features::Edition =
9
8
const DEFAULT_VERSION : & str = "0.0.0" ;
10
9
const DEFAULT_PUBLISH : bool = false ;
11
10
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) ,
27
18
Err ( err) => {
28
19
log:: trace!( "failed to extract doc comment: {err}" ) ;
29
20
None
@@ -38,83 +29,19 @@ fn parse(body: &str, path: &std::path::Path) -> CargoResult<RawScript> {
38
29
}
39
30
}
40
31
. 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( ) ) ) ?;
112
34
let manifest = toml:: to_string_pretty ( & manifest) ?;
113
35
Ok ( manifest)
114
36
}
115
37
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) ?;
118
45
119
46
for key in [ "workspace" , "lib" , "bin" , "example" , "test" , "bench" ] {
120
47
if manifest. contains_key ( key) {
@@ -135,14 +62,13 @@ fn expand_manifest_(script: &RawScript, config: &Config) -> CargoResult<toml::Ta
135
62
anyhow:: bail!( "`package.{key}` is not allowed in embedded manifests" )
136
63
}
137
64
}
138
- let file_name = script
139
- . path
65
+ let file_name = path
140
66
. file_stem ( )
141
67
. ok_or_else ( || anyhow:: format_err!( "no file name" ) ) ?
142
68
. to_string_lossy ( ) ;
143
69
let separator = '_' ;
144
70
let name = sanitize_package_name ( file_name. as_ref ( ) , separator) ;
145
- let hash = hash ( script ) ;
71
+ let hash = hash ( content ) ;
146
72
let bin_name = format ! ( "{name}{separator}{hash}" ) ;
147
73
package
148
74
. entry ( "name" . to_owned ( ) )
@@ -166,9 +92,7 @@ fn expand_manifest_(script: &RawScript, config: &Config) -> CargoResult<toml::Ta
166
92
bin. insert (
167
93
"path" . to_owned ( ) ,
168
94
toml:: Value :: String (
169
- script
170
- . path
171
- . to_str ( )
95
+ path. to_str ( )
172
96
. ok_or_else ( || anyhow:: format_err!( "path is not valid UTF-8" ) ) ?
173
97
. into ( ) ,
174
98
) ,
@@ -217,26 +141,8 @@ fn sanitize_package_name(name: &str, placeholder: char) -> String {
217
141
slug
218
142
}
219
143
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 ( ) )
240
146
}
241
147
242
148
/// Locates a "code block manifest" in Rust source.
@@ -438,10 +344,12 @@ mod test_expand {
438
344
439
345
macro_rules! si {
440
346
( $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) )
445
353
} } ;
446
354
}
447
355
@@ -693,73 +601,6 @@ fn main() {}
693
601
}
694
602
}
695
603
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
-
763
604
#[ cfg( test) ]
764
605
mod test_manifest {
765
606
use super :: * ;
0 commit comments