Skip to content

Commit 1b3a5cd

Browse files
author
Paolo Tranquilli
committed
Rust: make the cli flags override automatic
This makes the clap flags overlay over `Config` entirely derived via an attribute macro. Also, the `--intputs-file` option is replaced by a more standard and versatile `@` parameter file mechanism.
1 parent fea6017 commit 1b3a5cd

File tree

7 files changed

+111
-39
lines changed

7 files changed

+111
-39
lines changed

Cargo.lock

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ members = [
66
"shared/tree-sitter-extractor",
77
"ruby/extractor",
88
"rust/extractor",
9+
"rust/extractor/macros",
910
]
1011

1112
[patch.crates-io]

rust/extractor/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ serde = "1.0.209"
2222
serde_with = "3.9.0"
2323
stderrlog = "0.6.0"
2424
triomphe = "0.1.13"
25-
# Ideally, we'd like to pull this in via a relative path.
26-
# However, our bazel/rust tooling chokes on this, c.f. https://github.com/bazelbuild/rules_rust/issues/1525
27-
# Therefore, we have a pretty bad hack in place instead, see README.md in the codeql-extractor-fake-crate directory.
25+
argfile = "0.2.1"
2826
codeql-extractor = { path = "../../shared/tree-sitter-extractor" }
27+
rust-extractor-macros = { path = "macros" }

rust/extractor/macros/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "rust-extractor-macros"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
proc-macro = true
8+
9+
[dependencies]
10+
quote = "1.0.37"
11+
syn = { version = "2.0.77", features = ["full"] }

rust/extractor/macros/src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use proc_macro::TokenStream;
2+
use quote::{quote, format_ident};
3+
use syn;
4+
5+
6+
/// Allow all fields in the extractor config to be also overrideable by extractor CLI flags
7+
#[proc_macro_attribute]
8+
pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStream {
9+
let ast = syn::parse_macro_input!(item as syn::ItemStruct);
10+
let name = &ast.ident;
11+
let new_name = format_ident!("Cli{}", name);
12+
let fields: Vec<_> = ast.fields.iter().map(|f| {
13+
let id = f.ident.as_ref().unwrap();
14+
let ty = &f.ty;
15+
if let syn::Type::Path(p) = ty {
16+
if p.path.is_ident(&format_ident!("bool")) {
17+
return quote! {
18+
#[arg(long)]
19+
#id: bool,
20+
};
21+
}
22+
}
23+
if id == &format_ident!("verbose") {
24+
quote! {
25+
#[arg(long, short, action=clap::ArgAction::Count)]
26+
#id: u8,
27+
}
28+
} else if id == &format_ident!("inputs") {
29+
quote! {
30+
#id: #ty,
31+
}
32+
} else {
33+
quote! {
34+
#[arg(long)]
35+
#id: Option<#ty>,
36+
}
37+
}
38+
}).collect();
39+
let gen = quote! {
40+
#[serde_with::apply(_ => #[serde(default)])]
41+
#[derive(Debug, Deserialize, Default)]
42+
#ast
43+
44+
#[serde_with::skip_serializing_none]
45+
#[derive(clap::Parser, Serialize)]
46+
#[command(about, long_about = None)]
47+
struct #new_name {
48+
#(#fields)*
49+
}
50+
};
51+
gen.into()
52+
}

rust/extractor/src/config.rs

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use anyhow::Context;
2-
use clap::{ArgAction, Parser, ValueEnum};
2+
use clap::Parser;
33
use codeql_extractor::trap;
44
use figment::{
55
providers::{Env, Serialized},
66
Figment,
77
};
8+
use rust_extractor_macros::extractor_cli_config;
89
use serde::{Deserialize, Serialize};
910
use std::path::PathBuf;
1011

11-
#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone, Copy, ValueEnum)]
12+
#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone, Copy, clap::ValueEnum)]
1213
#[serde(rename_all = "lowercase")]
1314
#[clap(rename_all = "lowercase")]
1415
pub enum Compression {
@@ -26,8 +27,7 @@ impl From<Compression> for trap::Compression {
2627
}
2728
}
2829

29-
#[serde_with::apply(_ => #[serde(default)])]
30-
#[derive(Debug, Deserialize, Default)]
30+
#[extractor_cli_config]
3131
pub struct Config {
3232
pub scratch_dir: PathBuf,
3333
pub trap_dir: PathBuf,
@@ -38,39 +38,10 @@ pub struct Config {
3838
pub inputs: Vec<PathBuf>,
3939
}
4040

41-
#[serde_with::apply(_ => #[serde(skip_serializing_if = "is_default")])]
42-
#[derive(clap::Parser, Serialize)]
43-
#[command(about, long_about = None)]
44-
struct CliArgs {
45-
#[arg(long)]
46-
scratch_dir: Option<PathBuf>,
47-
#[arg(long)]
48-
trap_dir: Option<PathBuf>,
49-
#[arg(long)]
50-
source_archive_dir: Option<PathBuf>,
51-
#[arg(long)]
52-
compression: Option<Compression>,
53-
#[arg(short, long, action = ArgAction::Count)]
54-
verbose: u8,
55-
#[arg(long)]
56-
inputs_file: Option<PathBuf>,
57-
58-
inputs: Vec<PathBuf>,
59-
}
60-
61-
fn is_default<T: Default + PartialEq>(t: &T) -> bool {
62-
*t == Default::default()
63-
}
64-
6541
impl Config {
6642
pub fn extract() -> anyhow::Result<Config> {
67-
let mut cli_args = CliArgs::parse();
68-
if let Some(inputs_file) = cli_args.inputs_file.take() {
69-
let inputs_list = std::fs::read_to_string(inputs_file).context("reading file list")?;
70-
cli_args
71-
.inputs
72-
.extend(inputs_list.split_terminator("\n").map(PathBuf::from));
73-
}
43+
let args = argfile::expand_args(argfile::parse_fromfile, argfile::PREFIX)?;
44+
let cli_args = CliConfig::parse_from(args);
7445
Figment::new()
7546
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
7647
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_OPTION_"))

rust/tools/index-files.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
set -eu
44

5-
exec "$CODEQL_EXTRACTOR_RUST_ROOT/tools/$CODEQL_PLATFORM/extractor" --inputs-file="$1"
5+
exec "$CODEQL_EXTRACTOR_RUST_ROOT/tools/$CODEQL_PLATFORM/extractor" @"$1"

0 commit comments

Comments
 (0)