11//! Cargo-like environment variables injection.
22use base_db:: Env ;
3+ use paths:: Utf8Path ;
34use rustc_hash:: FxHashMap ;
45use toolchain:: Tool ;
56
@@ -63,7 +64,7 @@ pub(crate) fn cargo_config_env(
6364 manifest : & ManifestPath ,
6465 extra_env : & FxHashMap < String , String > ,
6566 sysroot : & Sysroot ,
66- ) -> FxHashMap < String , String > {
67+ ) -> Env {
6768 let mut cargo_config = sysroot. tool ( Tool :: Cargo , manifest. parent ( ) ) ;
6869 cargo_config. envs ( extra_env) ;
6970 cargo_config
@@ -75,7 +76,7 @@ pub(crate) fn cargo_config_env(
7576 // if successful we receive `env.key.value = "value" per entry
7677 tracing:: debug!( "Discovering cargo config env by {:?}" , cargo_config) ;
7778 utf8_stdout ( & mut cargo_config)
78- . map ( parse_output_cargo_config_env)
79+ . map ( |stdout| parse_output_cargo_config_env ( manifest , stdout ) )
7980 . inspect ( |env| {
8081 tracing:: debug!( "Discovered cargo config env: {:?}" , env) ;
8182 } )
@@ -85,18 +86,38 @@ pub(crate) fn cargo_config_env(
8586 . unwrap_or_default ( )
8687}
8788
88- fn parse_output_cargo_config_env ( stdout : String ) -> FxHashMap < String , String > {
89- stdout
90- . lines ( )
91- . filter_map ( |l| l. strip_prefix ( "env." ) )
92- . filter_map ( |l| l. split_once ( " = " ) )
93- . filter_map ( |( k, v) | {
94- if k. contains ( '.' ) {
95- k. strip_suffix ( ".value" ) . zip ( Some ( v) )
96- } else {
97- Some ( ( k, v) )
89+ fn parse_output_cargo_config_env ( manifest : & ManifestPath , stdout : String ) -> Env {
90+ let mut env = Env :: default ( ) ;
91+ let mut relatives = vec ! [ ] ;
92+ for ( key, val) in
93+ stdout. lines ( ) . filter_map ( |l| l. strip_prefix ( "env." ) ) . filter_map ( |l| l. split_once ( " = " ) )
94+ {
95+ let val = val. trim_matches ( '"' ) . to_owned ( ) ;
96+ if let Some ( ( key, modifier) ) = key. split_once ( '.' ) {
97+ match modifier {
98+ "relative" => relatives. push ( ( key, val) ) ,
99+ "value" => _ = env. insert ( key, val) ,
100+ _ => {
101+ tracing:: warn!(
102+ "Unknown modifier in cargo config env: {}, expected `relative` or `value`" ,
103+ modifier
104+ ) ;
105+ continue ;
106+ }
98107 }
99- } )
100- . map ( |( key, value) | ( key. to_owned ( ) , value. trim_matches ( '"' ) . to_owned ( ) ) )
101- . collect ( )
108+ } else {
109+ env. insert ( key, val) ;
110+ }
111+ }
112+ // FIXME: The base here should be the parent of the `.cargo/config` file, not the manifest.
113+ // But cargo does not provide this information.
114+ let base = <_ as AsRef < Utf8Path > >:: as_ref ( manifest. parent ( ) ) ;
115+ for ( key, val) in relatives {
116+ if let Some ( val) = env. get ( & val) {
117+ env. insert ( key, base. join ( val) . to_string ( ) ) ;
118+ } else {
119+ env. insert ( key, base. to_string ( ) ) ;
120+ }
121+ }
122+ env
102123}
0 commit comments