@@ -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 > ,
@@ -52,7 +68,7 @@ impl Config {
5268 . context ( "expanding parameter files" ) ?;
5369 let cli_args = CliConfig :: parse_from ( args) ;
5470 let mut figment = Figment :: new ( )
55- . merge ( Env :: prefixed ( "CODEQL_" ) )
71+ . merge ( Env :: raw ( ) . only ( [ "CODEQL_VERBOSE" ] . as_slice ( ) ) )
5672 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_" ) )
5773 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_OPTION_" ) )
5874 . merge ( Serialized :: defaults ( cli_args) ) ;
@@ -78,4 +94,81 @@ impl Config {
7894 }
7995 figment. extract ( ) . context ( "loading configuration" )
8096 }
97+
98+ pub fn to_cargo_config ( & self ) -> CargoConfig {
99+ let sysroot = Some ( RustLibSource :: Discover ) ;
100+
101+ let target_dir = self
102+ . cargo_target_dir
103+ . clone ( )
104+ . unwrap_or_else ( || self . scratch_dir . join ( "target" ) ) ;
105+ let target_dir = Utf8PathBuf :: from_path_buf ( target_dir) . ok ( ) ;
106+
107+ let features = if self . cargo_features . is_empty ( ) {
108+ Default :: default ( )
109+ } else if self . cargo_features . contains ( & "*" . to_string ( ) ) {
110+ CargoFeatures :: All
111+ } else {
112+ CargoFeatures :: Selected {
113+ features : self . cargo_features . clone ( ) ,
114+ no_default_features : false ,
115+ }
116+ } ;
117+
118+ let target = self . cargo_target . clone ( ) ;
119+
120+ let cfg_overrides = to_cfg_overrides ( & self . cargo_cfg_overrides ) ;
121+
122+ CargoConfig {
123+ sysroot,
124+ target_dir,
125+ features,
126+ target,
127+ cfg_overrides,
128+ ..Default :: default ( )
129+ }
130+ }
131+ }
132+
133+ fn to_cfg_override ( spec : & str ) -> CfgAtom {
134+ if let Some ( ( key, value) ) = spec. split_once ( "=" ) {
135+ CfgAtom :: KeyValue {
136+ key : Symbol :: intern ( key) ,
137+ value : Symbol :: intern ( value) ,
138+ }
139+ } else {
140+ CfgAtom :: Flag ( Symbol :: intern ( spec) )
141+ }
142+ }
143+
144+ fn to_cfg_overrides ( specs : & Vec < String > ) -> CfgOverrides {
145+ let mut enabled_cfgs = Vec :: new ( ) ;
146+ let mut disabled_cfgs = Vec :: new ( ) ;
147+ let mut has_test_explicitly_enabled = false ;
148+ for spec in specs {
149+ if spec. starts_with ( "-" ) {
150+ disabled_cfgs. push ( to_cfg_override ( & spec[ 1 ..] ) ) ;
151+ } else {
152+ enabled_cfgs. push ( to_cfg_override ( spec) ) ;
153+ if spec == "test" {
154+ has_test_explicitly_enabled = true ;
155+ }
156+ }
157+ }
158+ if !has_test_explicitly_enabled {
159+ disabled_cfgs. push ( to_cfg_override ( "test" ) ) ;
160+ }
161+ if let Some ( global) = CfgDiff :: new ( enabled_cfgs, disabled_cfgs) {
162+ CfgOverrides {
163+ global,
164+ ..Default :: default ( )
165+ }
166+ } else {
167+ warn ! ( "non-disjoint cfg overrides, ignoring: {}" , specs. join( ", " ) ) ;
168+ CfgOverrides {
169+ global : CfgDiff :: new ( Vec :: new ( ) , vec ! [ to_cfg_override( "test" ) ] )
170+ . expect ( "disabling one cfg should always succeed" ) ,
171+ ..Default :: default ( )
172+ }
173+ }
81174}
0 commit comments