@@ -7,9 +7,14 @@ use figment::{
77 Figment ,
88} ;
99use itertools:: Itertools ;
10+ use log:: warn;
1011use num_traits:: Zero ;
12+ use ra_ap_cfg:: { CfgAtom , CfgDiff } ;
13+ use ra_ap_intern:: Symbol ;
14+ use ra_ap_paths:: Utf8PathBuf ;
15+ use ra_ap_project_model:: { CargoConfig , CargoFeatures , CfgOverrides , RustLibSource } ;
1116use rust_extractor_macros:: extractor_cli_config;
12- use serde:: { Deserialize , Serialize } ;
17+ use serde:: { Deserialize , Deserializer , Serialize } ;
1318use std:: fmt:: Debug ;
1419use std:: ops:: Not ;
1520use std:: path:: PathBuf ;
@@ -32,12 +37,23 @@ impl From<Compression> for trap::Compression {
3237 }
3338}
3439
40+ // required by the extractor_cli_config macro.
41+ fn deserialize_newline_or_comma_separated < ' a , D : Deserializer < ' a > , T : for < ' b > From < & ' b str > > (
42+ deserializer : D ,
43+ ) -> Result < Vec < T > , D :: Error > {
44+ let value = String :: deserialize ( deserializer) ?;
45+ Ok ( value. split ( [ '\n' , ',' ] ) . map ( T :: from) . collect ( ) )
46+ }
47+
3548#[ extractor_cli_config]
3649pub struct Config {
3750 pub scratch_dir : PathBuf ,
3851 pub trap_dir : PathBuf ,
3952 pub source_archive_dir : PathBuf ,
4053 pub cargo_target_dir : Option < PathBuf > ,
54+ pub cargo_target : Option < String > ,
55+ pub cargo_features : Vec < String > ,
56+ pub cargo_cfg_overrides : Vec < String > ,
4157 pub verbose : u8 ,
4258 pub compression : Compression ,
4359 pub inputs : Vec < PathBuf > ,
@@ -51,7 +67,7 @@ impl Config {
5167 . context ( "expanding parameter files" ) ?;
5268 let cli_args = CliConfig :: parse_from ( args) ;
5369 let mut figment = Figment :: new ( )
54- . merge ( Env :: prefixed ( "CODEQL_" ) )
70+ . merge ( Env :: raw ( ) . only ( [ "CODEQL_VERBOSE" ] . as_slice ( ) ) )
5571 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_" ) )
5672 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_OPTION_" ) )
5773 . merge ( Serialized :: defaults ( cli_args) ) ;
@@ -71,4 +87,70 @@ impl Config {
7187 }
7288 figment. extract ( ) . context ( "loading configuration" )
7389 }
90+
91+ pub fn to_cargo_config ( & self ) -> CargoConfig {
92+ let sysroot = Some ( RustLibSource :: Discover ) ;
93+
94+ let target_dir = self
95+ . cargo_target_dir
96+ . clone ( )
97+ . unwrap_or_else ( || self . scratch_dir . join ( "target" ) ) ;
98+ let target_dir = Utf8PathBuf :: from_path_buf ( target_dir) . ok ( ) ;
99+
100+ let features = if self . cargo_features . is_empty ( ) {
101+ Default :: default ( )
102+ } else if self . cargo_features . contains ( & "*" . to_string ( ) ) {
103+ CargoFeatures :: All
104+ } else {
105+ CargoFeatures :: Selected {
106+ features : self . cargo_features . clone ( ) ,
107+ no_default_features : false ,
108+ }
109+ } ;
110+
111+ let target = self . cargo_target . clone ( ) ;
112+
113+ let cfg_overrides = to_cfg_overrides ( & self . cargo_cfg_overrides ) ;
114+
115+ CargoConfig {
116+ sysroot,
117+ target_dir,
118+ features,
119+ target,
120+ cfg_overrides,
121+ ..Default :: default ( )
122+ }
123+ }
124+ }
125+
126+ fn to_cfg_override ( spec : & str ) -> CfgAtom {
127+ if let Some ( ( key, value) ) = spec. split_once ( "=" ) {
128+ CfgAtom :: KeyValue {
129+ key : Symbol :: intern ( key) ,
130+ value : Symbol :: intern ( value) ,
131+ }
132+ } else {
133+ CfgAtom :: Flag ( Symbol :: intern ( spec) )
134+ }
135+ }
136+
137+ fn to_cfg_overrides ( specs : & Vec < String > ) -> CfgOverrides {
138+ let mut enabled_cfgs = Vec :: new ( ) ;
139+ let mut disabled_cfgs = Vec :: new ( ) ;
140+ for spec in specs {
141+ if spec. starts_with ( "-" ) {
142+ disabled_cfgs. push ( to_cfg_override ( & spec[ 1 ..] ) ) ;
143+ } else {
144+ enabled_cfgs. push ( to_cfg_override ( spec) ) ;
145+ }
146+ }
147+ if let Some ( global) = CfgDiff :: new ( enabled_cfgs, disabled_cfgs) {
148+ CfgOverrides {
149+ global,
150+ ..Default :: default ( )
151+ }
152+ } else {
153+ warn ! ( "non-disjoint cfg overrides, ignoring: {}" , specs. join( ", " ) ) ;
154+ CfgOverrides :: default ( )
155+ }
74156}
0 commit comments