Skip to content

Commit 6fc06b6

Browse files
committed
prioritize and order tests
also check cache before (re)populating it
1 parent f8b50b7 commit 6fc06b6

File tree

3 files changed

+68
-38
lines changed

3 files changed

+68
-38
lines changed

.config/nextest.toml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ default-filter = """\
77
not test(#*rate_limit_secondary) \
88
- test(#git::test::with_*) \
99
- test(#git::test::repo_get_sha) \
10-
- test(#*eval_static_dist)
10+
- test(#*eval_version)
1111
"""
1212

1313
# This will flag any test that runs longer than 10 seconds. Useful when writing new tests.
@@ -16,12 +16,23 @@ slow-timeout = "10s"
1616
# show which tests were skipped
1717
status-level = "skip"
1818

19+
[test-groups]
20+
# keep cache-setup group serialized to avoid race conditions installing clang tools.
21+
cache-setup = { max-threads = 1 }
22+
23+
[[profile.default.overrides]]
24+
# Run these tests with the highest priority.
25+
filter = 'test(#*eval_version)'
26+
priority = 100
27+
# assign it to a test group so that it can be run separately
28+
test-group = 'cache-setup'
29+
1930
[profile.ci]
2031
# A profile to run only tests that use clang-tidy and/or clang-format
2132
# NOTE: This profile is intended to keep CI runtime low. Locally, use default or all profiles
2233

2334
# This is all tests in tests/ folder + unit test for --extra-args.
24-
default-filter = "kind(test) + test(#*use_extra_args)"
35+
default-filter = "kind(test) + test(#*use_extra_args) + test(#*eval_version)"
2536

2637
# show log output from each test
2738
success-output = "final"

clang-installer/src/downloader/native_packages/mod.rs

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,21 @@ pub fn get_available_package_managers() -> Vec<impl PackageManager + Display> {
6666
pub fn try_install_package(
6767
tool: &ClangTool,
6868
version_req: &VersionReq,
69+
min_version: &Version,
6970
) -> Result<Option<ClangVersion>, GetToolError> {
7071
let os_pkg_managers = get_available_package_managers();
7172
if os_pkg_managers.is_empty() {
7273
log::error!("No supported package managers found on the system.");
7374
return Ok(None);
7475
} else {
75-
let min_version = get_min_ver(version_req).ok_or(GetToolError::VersionMajorRequired)?;
7676
for mgr in os_pkg_managers {
7777
if !mgr.is_installed() {
7878
log::debug!("Skipping {mgr} package manager as it is not installed.");
7979
continue;
8080
}
8181
log::info!("Trying to install {tool} v{min_version} using {mgr} package manager.");
8282
let pkg_name = mgr.get_package_name(tool);
83-
if mgr.is_installed_package(&pkg_name, Some(&min_version)) {
83+
if mgr.is_installed_package(&pkg_name, Some(min_version)) {
8484
let path =
8585
tool.get_exe_path(&RequestedVersion::Requirement(version_req.clone()))?;
8686
let version = tool.capture_version(&path)?;
@@ -92,7 +92,7 @@ pub fn try_install_package(
9292
log::info!(
9393
"{mgr} package manager does not have a version of {tool} matching {version_req} installed."
9494
);
95-
match mgr.install_package(&pkg_name, Some(&min_version)) {
95+
match mgr.install_package(&pkg_name, Some(min_version)) {
9696
Ok(()) => {
9797
log::info!(
9898
"Successfully installed {tool} v{min_version} using {mgr} package manager."
@@ -121,22 +121,3 @@ pub fn try_install_package(
121121
}
122122
Ok(None)
123123
}
124-
125-
fn get_min_ver(version_req: &VersionReq) -> Option<Version> {
126-
let mut result = None;
127-
for cmp in &version_req.comparators {
128-
if matches!(cmp.op, semver::Op::Exact | semver::Op::Caret) {
129-
let ver = Version {
130-
major: cmp.major,
131-
minor: cmp.minor.unwrap_or(0),
132-
patch: cmp.patch.unwrap_or(0),
133-
pre: cmp.pre.clone(),
134-
build: Default::default(),
135-
};
136-
if result.as_ref().is_none_or(|r| ver < *r) {
137-
result = Some(ver);
138-
}
139-
}
140-
}
141-
result
142-
}

clang-installer/src/version.rs

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{path::PathBuf, str::FromStr};
22

33
use crate::{
4-
ClangTool, PyPiDownloadError, PyPiDownloader,
4+
Cacher, ClangTool, PyPiDownloadError, PyPiDownloader,
55
downloader::{native_packages::try_install_package, static_dist::StaticDistDownloader},
66
tool::{GetClangPathError, GetClangVersionError},
77
utils::normalize_path,
@@ -92,7 +92,7 @@ impl RequestedVersion {
9292
}))
9393
}
9494
RequestedVersion::SystemDefault => {
95-
let path = tool.get_exe_path(&RequestedVersion::SystemDefault)?;
95+
let path = tool.get_exe_path(&Self::SystemDefault)?;
9696
let version = tool.capture_version(&path)?;
9797
log::info!(
9898
"Found {tool} version {version} at path: {:?}",
@@ -101,9 +101,8 @@ impl RequestedVersion {
101101
Ok(Some(ClangVersion { version, path }))
102102
}
103103
RequestedVersion::Requirement(version_req) => {
104-
if let Ok(path) =
105-
tool.get_exe_path(&RequestedVersion::Requirement(version_req.clone()))
106-
{
104+
// check default available version first (if any)
105+
if let Ok(path) = tool.get_exe_path(&Self::Requirement(version_req.clone())) {
107106
let version = tool.capture_version(&path)?;
108107
if version_req.matches(&version) {
109108
log::info!(
@@ -113,11 +112,33 @@ impl RequestedVersion {
113112
return Ok(Some(ClangVersion { version, path }));
114113
}
115114
}
115+
116+
// check if cache has a suitable version
117+
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
118+
let min_ver = get_min_ver(version_req).ok_or(GetToolError::VersionMajorRequired)?;
119+
let cached_bin = StaticDistDownloader::get_cache_dir()
120+
.join("bin")
121+
.join(format!("{tool}-{min_ver}{bin_ext}"));
122+
if cached_bin.exists() {
123+
let version = tool.capture_version(&cached_bin)?;
124+
if version_req.matches(&version) {
125+
log::info!(
126+
"Found {tool} version {version} in cache at path: {:?}",
127+
cached_bin.to_string_lossy()
128+
);
129+
return Ok(Some(ClangVersion {
130+
version,
131+
path: cached_bin,
132+
}));
133+
}
134+
}
135+
136+
// try to download a suitable version
116137
let bin = match PyPiDownloader::download_tool(tool, version_req).await {
117138
Ok(bin) => bin,
118139
Err(e) => {
119140
log::error!("Failed to download {tool} {version_req} from PyPi: {e}");
120-
if let Some(result) = try_install_package(tool, version_req)? {
141+
if let Some(result) = try_install_package(tool, version_req, &min_ver)? {
121142
return Ok(Some(result));
122143
}
123144
log::info!("Falling back to downloading {tool} static binaries.");
@@ -132,9 +153,10 @@ impl RequestedVersion {
132153
}
133154
}
134155
};
156+
157+
// create a symlink
135158
let bin_dir = bin.parent().ok_or(GetToolError::ExecutablePathNoParent)?;
136-
let symlink_path =
137-
bin_dir.join(format!("{tool}{}", if cfg!(windows) { ".exe" } else { "" }));
159+
let symlink_path = bin_dir.join(format!("{tool}{bin_ext}"));
138160
tool.symlink_bin(&bin, &symlink_path, overwrite_symlink)
139161
.map_err(GetToolError::SymlinkError)?;
140162
let version = tool.capture_version(&bin)?;
@@ -152,6 +174,25 @@ impl RequestedVersion {
152174
}
153175
}
154176

177+
pub fn get_min_ver(version_req: &VersionReq) -> Option<Version> {
178+
let mut result = None;
179+
for cmp in &version_req.comparators {
180+
if matches!(cmp.op, semver::Op::Exact | semver::Op::Caret) {
181+
let ver = Version {
182+
major: cmp.major,
183+
minor: cmp.minor.unwrap_or(0),
184+
patch: cmp.patch.unwrap_or(0),
185+
pre: cmp.pre.clone(),
186+
build: Default::default(),
187+
};
188+
if result.as_ref().is_none_or(|r| ver < *r) {
189+
result = Some(ver);
190+
}
191+
}
192+
}
193+
result
194+
}
195+
155196
/// Represents an error that occurred while parsing a requested version.
156197
#[derive(Debug, thiserror::Error)]
157198
pub enum RequestedVersionParsingError {
@@ -272,13 +313,10 @@ mod tests {
272313
/// It is designed to use the system's package manager to install clang-tidy.
273314
/// If successful, clang-tidy will be installed globally, which may be undesirable.
274315
#[tokio::test]
275-
async fn eval_static_dist() {
276-
let tmp_cache_dir = TempDir::new().unwrap();
277-
unsafe {
278-
std::env::set_var("CPP_LINTER_CACHE", tmp_cache_dir.path());
279-
}
316+
async fn eval_version() {
317+
let clang_version = option_env!("CLANG_VERSION").unwrap_or("12.0.1");
280318
let tool = ClangTool::ClangTidy;
281-
let version_req = VersionReq::parse("=12.0.1").unwrap();
319+
let version_req = VersionReq::parse(clang_version).unwrap();
282320
let clang_path = RequestedVersion::Requirement(version_req.clone())
283321
.eval_tool(&tool, false)
284322
.await

0 commit comments

Comments
 (0)