1+ mod deserialize_vec;
2+
13use anyhow:: Context ;
24use clap:: Parser ;
35use codeql_extractor:: trap;
6+ use deserialize_vec:: deserialize_newline_or_comma_separated;
47use figment:: {
58 providers:: { Env , Format , Serialized , Yaml } ,
69 value:: Value ,
710 Figment ,
811} ;
912use itertools:: Itertools ;
13+ use log:: warn;
1014use num_traits:: Zero ;
15+ use ra_ap_cfg:: { CfgAtom , CfgDiff } ;
16+ use ra_ap_intern:: Symbol ;
17+ use ra_ap_paths:: Utf8PathBuf ;
18+ use ra_ap_project_model:: { CargoConfig , CargoFeatures , CfgOverrides , RustLibSource } ;
1119use rust_extractor_macros:: extractor_cli_config;
1220use serde:: { Deserialize , Serialize } ;
1321use std:: fmt:: Debug ;
@@ -38,6 +46,9 @@ pub struct Config {
3846 pub trap_dir : PathBuf ,
3947 pub source_archive_dir : PathBuf ,
4048 pub cargo_target_dir : Option < PathBuf > ,
49+ pub cargo_target : Option < String > ,
50+ pub cargo_features : Vec < String > ,
51+ pub cargo_cfg_overrides : Vec < String > ,
4152 pub verbose : u8 ,
4253 pub compression : Compression ,
4354 pub inputs : Vec < PathBuf > ,
@@ -52,7 +63,7 @@ impl Config {
5263 . context ( "expanding parameter files" ) ?;
5364 let cli_args = CliConfig :: parse_from ( args) ;
5465 let mut figment = Figment :: new ( )
55- . merge ( Env :: prefixed ( "CODEQL_" ) )
66+ . merge ( Env :: raw ( ) . only ( [ "CODEQL_VERBOSE" ] . as_slice ( ) ) )
5667 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_" ) )
5768 . merge ( Env :: prefixed ( "CODEQL_EXTRACTOR_RUST_OPTION_" ) )
5869 . merge ( Serialized :: defaults ( cli_args) ) ;
@@ -72,4 +83,81 @@ impl Config {
7283 }
7384 figment. extract ( ) . context ( "loading configuration" )
7485 }
86+
87+ pub fn to_cargo_config ( & self ) -> CargoConfig {
88+ let sysroot = Some ( RustLibSource :: Discover ) ;
89+
90+ let target_dir = self
91+ . cargo_target_dir
92+ . clone ( )
93+ . unwrap_or_else ( || self . scratch_dir . join ( "target" ) ) ;
94+ let target_dir = Utf8PathBuf :: from_path_buf ( target_dir) . ok ( ) ;
95+
96+ let features = if self . cargo_features . is_empty ( ) {
97+ Default :: default ( )
98+ } else if self . cargo_features . contains ( & "*" . to_string ( ) ) {
99+ CargoFeatures :: All
100+ } else {
101+ CargoFeatures :: Selected {
102+ features : self . cargo_features . clone ( ) ,
103+ no_default_features : false ,
104+ }
105+ } ;
106+
107+ let target = self . cargo_target . clone ( ) ;
108+
109+ let cfg_overrides = to_cfg_overrides ( & self . cargo_cfg_overrides ) ;
110+
111+ CargoConfig {
112+ sysroot,
113+ target_dir,
114+ features,
115+ target,
116+ cfg_overrides,
117+ ..Default :: default ( )
118+ }
119+ }
120+ }
121+
122+ fn to_cfg_override ( spec : & str ) -> CfgAtom {
123+ if let Some ( ( key, value) ) = spec. split_once ( "=" ) {
124+ CfgAtom :: KeyValue {
125+ key : Symbol :: intern ( key) ,
126+ value : Symbol :: intern ( value) ,
127+ }
128+ } else {
129+ CfgAtom :: Flag ( Symbol :: intern ( spec) )
130+ }
131+ }
132+
133+ fn to_cfg_overrides ( specs : & Vec < String > ) -> CfgOverrides {
134+ let mut enabled_cfgs = Vec :: new ( ) ;
135+ let mut disabled_cfgs = Vec :: new ( ) ;
136+ let mut has_test_explicitly_enabled = false ;
137+ for spec in specs {
138+ if spec. starts_with ( "-" ) {
139+ disabled_cfgs. push ( to_cfg_override ( & spec[ 1 ..] ) ) ;
140+ } else {
141+ enabled_cfgs. push ( to_cfg_override ( spec) ) ;
142+ if spec == "test" {
143+ has_test_explicitly_enabled = true ;
144+ }
145+ }
146+ }
147+ if !has_test_explicitly_enabled {
148+ disabled_cfgs. push ( to_cfg_override ( "test" ) ) ;
149+ }
150+ if let Some ( global) = CfgDiff :: new ( enabled_cfgs, disabled_cfgs) {
151+ CfgOverrides {
152+ global,
153+ ..Default :: default ( )
154+ }
155+ } else {
156+ warn ! ( "non-disjoint cfg overrides, ignoring: {}" , specs. join( ", " ) ) ;
157+ CfgOverrides {
158+ global : CfgDiff :: new ( Vec :: new ( ) , vec ! [ to_cfg_override( "test" ) ] )
159+ . expect ( "disabling one cfg should always succeed" ) ,
160+ ..Default :: default ( )
161+ }
162+ }
75163}
0 commit comments