Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Revert "Rust: allow to specify more cargo configuration options"" #18012

Merged
merged 4 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use_repo(py_deps, "vendor__anyhow-1.0.44", "vendor__cc-1.0.70", "vendor__clap-2.
# deps for ruby+rust
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.132", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.132", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")

dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(dotnet_version = "8.0.101")
Expand Down
12 changes: 12 additions & 0 deletions misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/ast-generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "ast-generator"
version = "0.1.0"
edition = "2021"

# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
# When updating these dependencies, run `rust/update_cargo_deps.sh`
[dependencies]
ungrammar = "1.16.1"
proc-macro2 = "1.0.33"
Expand Down
19 changes: 19 additions & 0 deletions rust/codeql-extractor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,22 @@ options:
reduce execution time of consecutive extractor runs. By default, a new scratch
directory is used for each run.
type: string
cargo_target:
title: Target architecture
description: >
Target architecture to use for analysis, analogous to `cargo --target`. By
default the host architecture is used.
type: string
cargo_features:
title: Cargo features to turn on
description: >
Comma-separated list of features to turn on. If any value is `*` all features
are turned on. By default only default cargo features are enabled. Can be
repeated.
type: array
cargo_cfg_overrides:
title: Cargo cfg overrides
description: >
Comma-separated list of cfg settings to enable, or disable if prefixed with `-`.
Can be repeated.
type: array
4 changes: 3 additions & 1 deletion rust/extractor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "codeql-rust"
version = "0.1.0"
edition = "2021"

# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
# When updating these dependencies, run `rust/update_cargo_deps.sh`
[dependencies]
anyhow = "1.0.86"
clap = { version = "4.5.16", features = ["derive"] }
Expand All @@ -22,6 +22,8 @@ ra_ap_syntax = "0.0.232"
ra_ap_vfs = "0.0.232"
ra_ap_parser = "0.0.232"
ra_ap_span = "0.0.232"
ra_ap_cfg = "0.0.232"
ra_ap_intern = "0.0.232"
serde = "1.0.209"
serde_with = "3.9.0"
stderrlog = "0.6.0"
Expand Down
2 changes: 1 addition & 1 deletion rust/extractor/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
[lib]
proc-macro = true

# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
# When updating these dependencies, run `rust/update_cargo_deps.sh`
[dependencies]
quote = "1.0.37"
syn = { version = "2.0.77", features = ["full"] }
67 changes: 48 additions & 19 deletions rust/extractor/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,74 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{Ident, Type};

fn get_type_tip(t: &Type) -> Option<&Ident> {
let syn::Type::Path(path) = t else {
return None;
};
let segment = path.path.segments.last()?;
Some(&segment.ident)
}

/// Allow all fields in the extractor config to be also overrideable by extractor CLI flags
#[proc_macro_attribute]
pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(item as syn::ItemStruct);
let name = &ast.ident;
let fields = ast
.fields
.iter()
.map(|f| {
if f.ident.as_ref().is_some_and(|i| i != "inputs")
&& get_type_tip(&f.ty).is_some_and(|i| i == "Vec")
{
quote! {
#[serde(deserialize_with="deserialize_newline_or_comma_separated")]
#f
}
} else {
quote! { #f }
}
})
.collect::<Vec<_>>();
let cli_name = format_ident!("Cli{}", name);
let cli_fields = ast
.fields
.iter()
.map(|f| {
let id = f.ident.as_ref().unwrap();
let ty = &f.ty;
if let syn::Type::Path(p) = ty {
if p.path.is_ident(&format_ident!("bool")) {
return quote! {
#[arg(long)]
#[serde(skip_serializing_if="<&bool>::not")]
#id: bool,
};
let type_tip = get_type_tip(ty);
if type_tip.is_some_and(|i| i == "bool") {
quote! {
#[arg(long)]
#[serde(skip_serializing_if="<&bool>::not")]
#id: bool
}
if p.path.segments.len() == 1 && p.path.segments[0].ident == "Option" {
return quote! {
#[arg(long)]
#id: #ty,
};
} else if type_tip.is_some_and(|i| i == "Option") {
quote! {
#[arg(long)]
#f
}
}
if id == &format_ident!("verbose") {
} else if id == &format_ident!("verbose") {
quote! {
#[arg(long, short, action=clap::ArgAction::Count)]
#[serde(skip_serializing_if="u8::is_zero")]
#id: u8,
#id: u8
}
} else if id == &format_ident!("inputs") {
quote! {
#id: #ty,
#f
}
} else if type_tip.is_some_and(|i| i == "Vec") {
quote! {
#[arg(long)]
#id: Option<String>
}
} else {
quote! {
#[arg(long)]
#id: Option<#ty>,
#id: Option<#ty>
}
}
})
Expand All @@ -66,7 +93,9 @@ pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStrea
let gen = quote! {
#[serde_with::apply(_ => #[serde(default)])]
#[derive(Deserialize, Default)]
#ast
pub struct #name {
#(#fields),*
}

impl Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand All @@ -80,7 +109,7 @@ pub fn extractor_cli_config(_attr: TokenStream, item: TokenStream) -> TokenStrea
#[derive(clap::Parser, Serialize)]
#[command(about, long_about = None)]
struct #cli_name {
#(#cli_fields)*
#(#cli_fields),*
}
};
gen.into()
Expand Down
90 changes: 89 additions & 1 deletion rust/extractor/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
mod deserialize_vec;

use anyhow::Context;
use clap::Parser;
use codeql_extractor::trap;
use deserialize_vec::deserialize_newline_or_comma_separated;
use figment::{
providers::{Env, Format, Serialized, Yaml},
value::Value,
Figment,
};
use itertools::Itertools;
use log::warn;
use num_traits::Zero;
use ra_ap_cfg::{CfgAtom, CfgDiff};
use ra_ap_intern::Symbol;
use ra_ap_paths::Utf8PathBuf;
use ra_ap_project_model::{CargoConfig, CargoFeatures, CfgOverrides, RustLibSource};
use rust_extractor_macros::extractor_cli_config;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
Expand Down Expand Up @@ -38,6 +46,9 @@ pub struct Config {
pub trap_dir: PathBuf,
pub source_archive_dir: PathBuf,
pub cargo_target_dir: Option<PathBuf>,
pub cargo_target: Option<String>,
pub cargo_features: Vec<String>,
pub cargo_cfg_overrides: Vec<String>,
pub verbose: u8,
pub compression: Compression,
pub inputs: Vec<PathBuf>,
Expand All @@ -52,7 +63,7 @@ impl Config {
.context("expanding parameter files")?;
let cli_args = CliConfig::parse_from(args);
let mut figment = Figment::new()
.merge(Env::prefixed("CODEQL_"))
.merge(Env::raw().only(["CODEQL_VERBOSE"].as_slice()))
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_OPTION_"))
.merge(Serialized::defaults(cli_args));
Expand All @@ -78,4 +89,81 @@ impl Config {
}
figment.extract().context("loading configuration")
}

pub fn to_cargo_config(&self) -> CargoConfig {
let sysroot = Some(RustLibSource::Discover);

let target_dir = self
.cargo_target_dir
.clone()
.unwrap_or_else(|| self.scratch_dir.join("target"));
let target_dir = Utf8PathBuf::from_path_buf(target_dir).ok();

let features = if self.cargo_features.is_empty() {
Default::default()
} else if self.cargo_features.contains(&"*".to_string()) {
CargoFeatures::All
} else {
CargoFeatures::Selected {
features: self.cargo_features.clone(),
no_default_features: false,
}
};

let target = self.cargo_target.clone();

let cfg_overrides = to_cfg_overrides(&self.cargo_cfg_overrides);

CargoConfig {
sysroot,
target_dir,
features,
target,
cfg_overrides,
..Default::default()
}
}
}

fn to_cfg_override(spec: &str) -> CfgAtom {
if let Some((key, value)) = spec.split_once("=") {
CfgAtom::KeyValue {
key: Symbol::intern(key),
value: Symbol::intern(value),
}
} else {
CfgAtom::Flag(Symbol::intern(spec))
}
}

fn to_cfg_overrides(specs: &Vec<String>) -> CfgOverrides {
let mut enabled_cfgs = Vec::new();
let mut disabled_cfgs = Vec::new();
let mut has_test_explicitly_enabled = false;
for spec in specs {
if spec.starts_with("-") {
disabled_cfgs.push(to_cfg_override(&spec[1..]));
} else {
enabled_cfgs.push(to_cfg_override(spec));
if spec == "test" {
has_test_explicitly_enabled = true;
}
}
}
if !has_test_explicitly_enabled {
disabled_cfgs.push(to_cfg_override("test"));
}
if let Some(global) = CfgDiff::new(enabled_cfgs, disabled_cfgs) {
CfgOverrides {
global,
..Default::default()
}
} else {
warn!("non-disjoint cfg overrides, ignoring: {}", specs.join(", "));
CfgOverrides {
global: CfgDiff::new(Vec::new(), vec![to_cfg_override("test")])
.expect("disabling one cfg should always succeed"),
..Default::default()
}
}
}
Loading