11//! Cargo-like environment variables injection.
22use base_db:: Env ;
3+ use paths:: Utf8Path ;
34use rustc_hash:: FxHashMap ;
45use toolchain:: Tool ;
56
@@ -85,7 +86,7 @@ pub(crate) fn cargo_config_env(
8586 // if successful we receive `env.key.value = "value" per entry
8687 tracing:: debug!( "Discovering cargo config env by {:?}" , cargo_config) ;
8788 utf8_stdout ( & mut cargo_config)
88- . map ( parse_output_cargo_config_env)
89+ . map ( |stdout| parse_output_cargo_config_env ( manifest , stdout ) )
8990 . inspect ( |env| {
9091 tracing:: debug!( "Discovered cargo config env: {:?}" , env) ;
9192 } )
@@ -95,18 +96,38 @@ pub(crate) fn cargo_config_env(
9596 . unwrap_or_default ( )
9697}
9798
98- fn parse_output_cargo_config_env ( stdout : String ) -> Env {
99- stdout
100- . lines ( )
101- . filter_map ( |l| l. strip_prefix ( "env." ) )
102- . filter_map ( |l| l. split_once ( " = " ) )
103- . filter_map ( |( k, v) | {
104- if k. contains ( '.' ) {
105- k. strip_suffix ( ".value" ) . zip ( Some ( v) )
106- } else {
107- Some ( ( k, v) )
99+ fn parse_output_cargo_config_env ( manifest : & ManifestPath , stdout : String ) -> Env {
100+ let mut env = Env :: default ( ) ;
101+ let mut relatives = vec ! [ ] ;
102+ for ( key, val) in
103+ stdout. lines ( ) . filter_map ( |l| l. strip_prefix ( "env." ) ) . filter_map ( |l| l. split_once ( " = " ) )
104+ {
105+ let val = val. trim_matches ( '"' ) . to_owned ( ) ;
106+ if let Some ( ( key, modifier) ) = key. split_once ( '.' ) {
107+ match modifier {
108+ "relative" => relatives. push ( ( key, val) ) ,
109+ "value" => _ = env. insert ( key, val) ,
110+ _ => {
111+ tracing:: warn!(
112+ "Unknown modifier in cargo config env: {}, expected `relative` or `value`" ,
113+ modifier
114+ ) ;
115+ continue ;
116+ }
108117 }
109- } )
110- . map ( |( key, value) | ( key. to_owned ( ) , value. trim_matches ( '"' ) . to_owned ( ) ) )
111- . collect ( )
118+ } else {
119+ env. insert ( key, val) ;
120+ }
121+ }
122+ // FIXME: The base here should be the parent of the `.cargo/config` file, not the manifest.
123+ // But cargo does not provide this information.
124+ let base = <_ as AsRef < Utf8Path > >:: as_ref ( manifest. parent ( ) ) ;
125+ for ( key, val) in relatives {
126+ if let Some ( val) = env. get ( & val) {
127+ env. insert ( key, base. join ( val) . to_string ( ) ) ;
128+ } else {
129+ env. insert ( key, base. to_string ( ) ) ;
130+ }
131+ }
132+ env
112133}
0 commit comments