blob: 6048ee47f4420d7b409b48c46f031bd41adef8d3 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::mapping::{postprocess, preprocess, replace_regex};
use crate::EnvironmentContext;
use lazy_static::lazy_static;
use regex::Regex;
use serde_json::Value;
use std::path::Path;
fn find_workspace_root(mut current: &Path) -> Option<&Path> {
loop {
if current.join("WORKSPACE").exists() || current.join("WORKSPACE.bazel").exists() {
return Some(current);
} else {
current = current.parent()?;
}
}
}
/// Replaces `$FIND_WORKSPACE_ROOT` with the path to the nearest parent directory
/// with a WORKSPACE or WORKSPACE.bazel file in it. If it doesn't find one,
/// this value will be skipped.
pub(crate) fn workspace(ctx: &EnvironmentContext, value: Value) -> Option<Value> {
lazy_static! {
static ref REGEX: Regex = Regex::new(r"\$(FIND_WORKSPACE_ROOT)").unwrap();
}
let Some(s) = preprocess(&value).filter(|s| REGEX.is_match(s)) else { return Some(value) };
let workspace_root = find_workspace_root(ctx.project_root()?).and_then(Path::to_str)?;
Some(postprocess(replace_regex(&s, &*REGEX, |_| Ok(workspace_root.to_owned()))))
}
////////////////////////////////////////////////////////////////////////////////
// tests
#[cfg(test)]
mod test {
use std::fs::File;
use tempfile::{tempdir, TempDir};
use crate::environment::ExecutableKind;
use ffx_config_domain::ConfigDomain;
use super::*;
fn make_temp_workspace_dir(workspace_filename: Option<&str>) -> TempDir {
let workspace = tempdir().expect("temp directory");
if let Some(name) = workspace_filename {
File::create(workspace.path().join(name)).expect("workspace file");
}
workspace
}
fn make_test_env(workspace_dir: &TempDir) -> EnvironmentContext {
let config_domain = ConfigDomain::load_from_contents(
workspace_dir.path().join("fuchsia_env.toml").try_into().unwrap(),
Default::default(),
)
.unwrap();
EnvironmentContext::config_domain(
ExecutableKind::Test,
config_domain,
Default::default(),
Some(workspace_dir.path().to_owned()),
)
}
#[test]
fn test_find_workspace() {
for filename in ["WORKSPACE", "WORKSPACE.bazel"] {
let workspace_dir = make_temp_workspace_dir(Some(filename));
assert_eq!(
None,
find_workspace_root(workspace_dir.path().parent().unwrap()),
"Shouldn't find workspace in outer directory"
);
assert_eq!(
Some(workspace_dir.path()),
find_workspace_root(workspace_dir.path()),
"Find workspace in the root"
);
std::fs::create_dir_all(workspace_dir.path().join("first/second/third")).unwrap();
for subdir in ["first", "first/second", "first/second/third"] {
let subdir = workspace_dir.path().join(subdir);
assert_eq!(
Some(workspace_dir.path()),
find_workspace_root(&subdir),
"Find workspace in a subdirectory"
);
}
}
}
#[test]
fn test_mapper_no_workspace() {
let workspace_dir = make_temp_workspace_dir(None);
let ctx = make_test_env(&workspace_dir);
let test = Value::String("$FIND_WORKSPACE_ROOT".to_string());
assert_eq!(workspace(&ctx, test), None);
}
#[test]
fn test_mapper() {
let workspace_dir = make_temp_workspace_dir(Some("WORKSPACE"));
let ctx = make_test_env(&workspace_dir);
let value = workspace_dir.path().to_string_lossy().to_string();
let test = Value::String("$FIND_WORKSPACE_ROOT".to_string());
assert_eq!(workspace(&ctx, test), Some(Value::String(value)));
}
#[test]
fn test_mapper_multiple() {
let workspace_dir = make_temp_workspace_dir(Some("WORKSPACE"));
let ctx = make_test_env(&workspace_dir);
let value = workspace_dir.path().to_string_lossy().to_string();
let test = Value::String("$FIND_WORKSPACE_ROOT/$FIND_WORKSPACE_ROOT".to_string());
assert_eq!(workspace(&ctx, test), Some(Value::String(format!("{}/{}", value, value))));
}
#[test]
fn test_mapper_returns_pass_through() {
let workspace_dir = make_temp_workspace_dir(Some("WORKSPACE"));
let ctx = make_test_env(&workspace_dir);
let test = Value::String("$WHATEVER".to_string());
assert_eq!(workspace(&ctx, test), Some(Value::String("$WHATEVER".to_string())));
}
}