Skip to content

Commit 3f8d438

Browse files
author
Paolo Tranquilli
committed
Rust: move qltest to rust code, add options with cargo check
1 parent 226756e commit 3f8d438

File tree

19 files changed

+262
-59
lines changed

19 files changed

+262
-59
lines changed

Cargo.lock

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

rust/extractor/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
[dependencies]
77
anyhow = "1.0.86"
88
clap = { version = "4.5.16", features = ["derive"] }
9-
figment = { version = "0.10.19", features = ["env"]}
9+
figment = { version = "0.10.19", features = ["env", "yaml"] }
1010
log = "0.4.22"
1111
num-traits = "0.2.19"
1212
ra_ap_base_db = "0.0.232"
@@ -29,3 +29,5 @@ argfile = "0.2.1"
2929
codeql-extractor = { path = "../../shared/tree-sitter-extractor" }
3030
rust-extractor-macros = { path = "macros" }
3131
itertools = "0.13.0"
32+
glob = "0.3.1"
33+
gag = "1.0.0"

rust/extractor/src/config.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ use anyhow::Context;
22
use clap::Parser;
33
use codeql_extractor::trap;
44
use figment::{
5-
providers::{Env, Serialized},
5+
providers::{Env, Format, Serialized, Yaml},
6+
value::Value,
67
Figment,
78
};
9+
use itertools::Itertools;
810
use num_traits::Zero;
911
use rust_extractor_macros::extractor_cli_config;
1012
use serde::{Deserialize, Serialize};
@@ -34,23 +36,39 @@ pub struct Config {
3436
pub scratch_dir: PathBuf,
3537
pub trap_dir: PathBuf,
3638
pub source_archive_dir: PathBuf,
39+
pub log_dir: PathBuf,
3740
pub extract_dependencies: bool,
3841
pub verbose: u8,
3942
pub compression: Compression,
4043
pub inputs: Vec<PathBuf>,
44+
pub qltest: bool,
45+
pub qltest_cargo_check: bool,
4146
}
4247

4348
impl Config {
4449
pub fn extract() -> anyhow::Result<Config> {
4550
let args = argfile::expand_args(argfile::parse_fromfile, argfile::PREFIX)
4651
.context("expanding parameter files")?;
4752
let cli_args = CliConfig::parse_from(args);
48-
Figment::new()
53+
let mut figment = Figment::new()
4954
.merge(Env::prefixed("CODEQL_"))
5055
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_"))
5156
.merge(Env::prefixed("CODEQL_EXTRACTOR_RUST_OPTION_"))
52-
.merge(Serialized::defaults(cli_args))
53-
.extract()
54-
.context("loading configuration")
57+
.merge(Serialized::defaults(cli_args));
58+
if matches!(figment.find_value("qltest"), Ok(Value::Bool(_, true))) {
59+
let cwd = std::env::current_dir()?;
60+
let mut option_files = cwd
61+
.ancestors()
62+
// only travel up while we're within the test pack
63+
.take_while_inclusive(|p| !p.join("qlpack.yml").exists())
64+
.map(|p| p.join("options"))
65+
.filter(|p| p.exists())
66+
.collect_vec();
67+
option_files.reverse();
68+
for path in option_files {
69+
figment = figment.merge(Yaml::file_exact(path));
70+
}
71+
}
72+
figment.extract().context("loading configuration")
5573
}
5674
}

rust/extractor/src/main.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
use std::{
2-
collections::HashMap,
3-
path::{Path, PathBuf},
4-
};
5-
61
use anyhow::Context;
72
use archive::Archiver;
3+
use log::info;
84
use ra_ap_ide_db::line_index::{LineCol, LineIndex};
95
use ra_ap_project_model::ProjectManifest;
106
use rust_analyzer::{ParseResult, RustAnalyzer};
7+
use std::fs::File;
8+
use std::io::{BufRead, BufReader};
9+
use std::{
10+
collections::HashMap,
11+
path::{Path, PathBuf},
12+
};
1113
mod archive;
1214
mod config;
1315
pub mod generated;
16+
mod qltest;
1417
mod rust_analyzer;
1518
mod translate;
1619
pub mod trap;
@@ -65,16 +68,20 @@ fn extract(
6568
)
6669
});
6770
}
68-
fn main() -> anyhow::Result<()> {
69-
let cfg = config::Config::extract().context("failed to load configuration")?;
71+
72+
fn run_extractor(mut cfg: config::Config) -> anyhow::Result<()> {
7073
stderrlog::new()
7174
.module(module_path!())
72-
.verbosity(1 + cfg.verbose as usize)
75+
.verbosity(cfg.verbose as usize)
7376
.init()?;
77+
if cfg.qltest {
78+
qltest::prepare(&mut cfg)?;
79+
}
80+
info!("configuration: {cfg:#?}\n");
7481

7582
let traps = trap::TrapFileProvider::new(&cfg).context("failed to set up trap files")?;
7683
let archiver = archive::Archiver {
77-
root: cfg.source_archive_dir,
84+
root: cfg.source_archive_dir.clone(),
7885
};
7986
let files: Vec<PathBuf> = cfg
8087
.inputs
@@ -118,3 +125,19 @@ fn main() -> anyhow::Result<()> {
118125

119126
Ok(())
120127
}
128+
129+
fn main() -> anyhow::Result<()> {
130+
let cfg = config::Config::extract().context("failed to load configuration")?;
131+
let qltest = cfg.qltest;
132+
let qltest_log = cfg.log_dir.join("qltest.log");
133+
let result = std::panic::catch_unwind(|| run_extractor(cfg));
134+
if qltest && matches!(result, Err(_) | Ok(Err(_))) {
135+
// in case of failure, print out the full log
136+
let log = File::open(qltest_log).context("opening qltest.log")?;
137+
let reader = BufReader::new(log);
138+
for line in reader.lines() {
139+
println!("{}", line.context("reading qltest.log")?);
140+
}
141+
}
142+
result.unwrap()
143+
}

rust/extractor/src/qltest.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::config::Config;
2+
use anyhow::Context;
3+
use glob::glob;
4+
use itertools::Itertools;
5+
use log::info;
6+
use std::fs;
7+
use std::process::Command;
8+
9+
fn dump_lib() -> anyhow::Result<()> {
10+
let path_iterator = glob("*.rs").context("globbing test sources")?;
11+
let paths = path_iterator
12+
.collect::<Result<Vec<_>, _>>()
13+
.context("fetching test sources")?;
14+
let lib = paths
15+
.iter()
16+
.filter(|p| !["lib.rs", "main.rs"].contains(&p.file_name().unwrap().to_str().unwrap()))
17+
.map(|p| format!("mod {};", p.file_stem().unwrap().to_str().unwrap()))
18+
.join("\n");
19+
fs::write("lib.rs", lib).context("writing lib.rs")
20+
}
21+
22+
fn dump_cargo_manifest() -> anyhow::Result<()> {
23+
let mut manifest = String::from(
24+
r#"[workspace]
25+
[package]
26+
name = "test"
27+
version="0.0.1"
28+
edition="2021"
29+
[lib]
30+
path="lib.rs"
31+
"#,
32+
);
33+
if fs::exists("main.rs").context("checking existence of main.rs")? {
34+
manifest.push_str(
35+
r#"[[bin]]
36+
name = "main"
37+
path = "main.rs"
38+
"#,
39+
);
40+
}
41+
fs::write("Cargo.toml", manifest).context("writing Cargo.toml")
42+
}
43+
44+
fn set_sources(config: &mut Config) -> anyhow::Result<()> {
45+
let path_iterator = glob("*.rs").context("globbing test sources")?;
46+
config.inputs = path_iterator
47+
.collect::<Result<Vec<_>, _>>()
48+
.context("fetching test sources")?;
49+
Ok(())
50+
}
51+
52+
fn redirect_output(config: &Config) -> anyhow::Result<()> {
53+
let log_path = config.log_dir.join("qltest.log");
54+
let log = fs::OpenOptions::new()
55+
.append(true)
56+
.create(true)
57+
.open(&log_path)
58+
.context("opening qltest.log")?;
59+
Box::leak(Box::new(
60+
gag::Redirect::stderr(log).context("redirecting stderr")?,
61+
));
62+
Ok(())
63+
}
64+
65+
pub(crate) fn prepare(config: &mut Config) -> anyhow::Result<()> {
66+
redirect_output(config)?;
67+
dump_lib()?;
68+
set_sources(config)?;
69+
dump_cargo_manifest()?;
70+
if config.qltest_cargo_check {
71+
let status = Command::new("cargo")
72+
.env("RUSTFLAGS", "-Awarnings")
73+
.arg("check")
74+
.arg("-q")
75+
.status()
76+
.context("spawning cargo check")?;
77+
if status.success() {
78+
info!("cargo check successful");
79+
} else {
80+
anyhow::bail!("requested cargo check failed");
81+
}
82+
}
83+
Ok(())
84+
}

0 commit comments

Comments
 (0)