Add support for canonical output and work directories
Change-Id: Ie8038805822fca12d387f577f39c654e4949b526
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/qg/+/126668
Pigweed-Auto-Submit: Erik Gilling <konkers@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Commit-Queue: Erik Gilling <konkers@google.com>
diff --git a/qg/src/executor.rs b/qg/src/executor.rs
index 0efc07d..ac3887a 100644
--- a/qg/src/executor.rs
+++ b/qg/src/executor.rs
@@ -244,14 +244,16 @@
async fn dispatch_target(&mut self, target: Arc<Target>) -> Result<()> {
self.pending_targets
.insert(target.full_name(), target.clone());
+ let output_dir = self.project.target_output_directory(&target)?;
+ let work_dir = self.project.target_work_directory(&target)?;
+
self.dispatch_tx
.send(ExecutionContext {
target,
// TODO(frolv): Allow setting platforms dynamically.
target_platform: Platform::current(),
- // TODO(konkers): Add canonical location for `output_dir` and `work_dir`.
- output_dir: "".into(),
- work_dir: "".into(),
+ output_dir,
+ work_dir,
})
.await
.map_err(|e| Error::StringErrorPlaceholder(format!("Error dispatching target: {e}")))
diff --git a/qg/src/project/mod.rs b/qg/src/project/mod.rs
index 35efbbf..dc22fbf 100644
--- a/qg/src/project/mod.rs
+++ b/qg/src/project/mod.rs
@@ -14,11 +14,12 @@
use std::{
ffi::OsStr,
+ fs,
path::{Path, PathBuf},
sync::Arc,
};
-use crate::registry::Registry;
+use crate::{registry::Registry, Target};
use crate::{Error, Result};
use manifest::Manifest;
@@ -32,14 +33,14 @@
#[derive(Debug)]
pub struct Project {
root: PathBuf,
- cache_dir: PathBuf,
+ qg_dir: PathBuf,
name: String,
registry: Arc<Registry>,
}
impl Project {
const MANIFEST_FILE: &str = "qg.toml";
- const CACHE_DIRECTORY: &str = "qg-cache";
+ const QG_DIRECTORY: &str = "qg";
/// Checks if a project name is valid.
///
@@ -103,7 +104,7 @@
Ok(Self {
root: project_root.to_owned(),
- cache_dir: project_root.join(Self::CACHE_DIRECTORY),
+ qg_dir: project_root.join(Self::QG_DIRECTORY),
name: manifest.project.name,
registry: Arc::new(registry),
})
@@ -159,13 +160,46 @@
Self::relative_file(&self.root, Path::new(path.as_ref()))
}
- /// Returns a [`File`](self::File) representing some file located at `path`
- /// within the project's cache directory.
+ /// Returns a `PathBuf` pointing to the directory located at `path` within
+ /// the project root. Will create the directory if it does not exist.
///
/// # Errors
- /// Returns an [`Error::InvalidPath`] if the provided path is absolute.
- pub fn cache_file(&self, path: impl AsRef<OsStr>) -> Result<self::File> {
- Self::relative_file(&self.cache_dir, Path::new(path.as_ref()))
+ /// Returns an error if the directory does not exist and can not be
+ /// created.
+ fn directory(&self, path: impl AsRef<Path>) -> Result<PathBuf> {
+ let dir_path = self.root.join(path.as_ref());
+ fs::create_dir_all(&dir_path)?;
+ Ok(dir_path)
+ }
+
+ /// Returns a `PathBuf` pointing to the output directory for a given target.
+ /// Will create the directory if it does not exist.
+ ///
+ /// # Errors
+ /// Returns an error if the directory does not exist and can not be
+ /// created.
+ pub fn target_output_directory(&self, target: &Target) -> Result<PathBuf> {
+ self.directory(
+ self.qg_dir
+ .join("out")
+ .join(target.provider())
+ .join(target.name()),
+ )
+ }
+
+ /// Returns a `PathBuf` pointing to the output directory for a given target.
+ /// Will create the directory if it does not exist.
+ ///
+ /// # Errors
+ /// Returns an error if the directory does not exist and can not be
+ /// created.
+ pub fn target_work_directory(&self, target: &Target) -> Result<PathBuf> {
+ self.directory(
+ self.qg_dir
+ .join("work")
+ .join(target.provider())
+ .join(target.name()),
+ )
}
/// Returns the target registry for this project.
@@ -187,7 +221,7 @@
mod tests {
use std::collections::HashSet;
- use crate::target::Metadata;
+ use crate::{target::Metadata, test_util::TestProject};
use super::*;
@@ -210,7 +244,7 @@
fn file_valid_path() {
let root = PathBuf::from("/qg");
let project = Project {
- cache_dir: root.join("qg-cache"),
+ qg_dir: root.join("qg"),
root,
name: "qg2".into(),
registry: Arc::new(Registry::new()),
@@ -224,17 +258,13 @@
project.file("secrets/nuclear_codes.toml").unwrap().path(),
Path::new("/qg/secrets/nuclear_codes.toml")
);
- assert_eq!(
- project.cache_file("downloads.xml").unwrap().path(),
- Path::new("/qg/qg-cache/downloads.xml")
- );
}
#[test]
fn file_invalid_path() {
let root = PathBuf::from("/qg");
let project = Project {
- cache_dir: root.join("qg-cache"),
+ qg_dir: root.join("qg"),
root,
name: "qg2".into(),
registry: Arc::new(Registry::new()),
@@ -244,15 +274,7 @@
project.file("/bin").unwrap_err(),
Error::InvalidPath,
));
- assert!(matches!(
- project.cache_file("/").unwrap_err(),
- Error::InvalidPath,
- ));
assert!(matches!(project.file("").unwrap_err(), Error::InvalidPath));
- assert!(matches!(
- project.cache_file("").unwrap_err(),
- Error::InvalidPath,
- ));
}
#[test]
@@ -274,8 +296,29 @@
}
#[test]
+ fn out_and_work_directories() {
+ let test_project = TestProject::new("./src/test_projects/dependency_test").unwrap();
+ let project = &test_project.project;
+ assert_eq!(project.name, "dep-test");
+
+ // Neither dep-test:a's out or work directories should exist before we
+ // ask for their paths.
+ assert!(!test_project.relative_path("qg/out/dep-test/a").exists());
+ assert!(!test_project.relative_path("qg/work/dep-test/a").exists());
+
+ let target = project.registry().get_target("dep-test:a").unwrap();
+
+ let _ = project.target_output_directory(&target).unwrap();
+ assert!(test_project.relative_path("qg/out/dep-test/a").exists());
+
+ let _ = project.target_work_directory(&target).unwrap();
+ assert!(test_project.relative_path("qg/work/dep-test/a").exists());
+ }
+
+ #[test]
fn simple_dependencies() {
- let project = Project::load("./src/test_projects/dependency_test").unwrap();
+ let test_project = TestProject::new("./src/test_projects/dependency_test").unwrap();
+ let project = &test_project.project;
assert_eq!(project.name, "dep-test");
let registry = project.registry();
diff --git a/qg/src/test_util.rs b/qg/src/test_util.rs
index e4db038..156a629 100644
--- a/qg/src/test_util.rs
+++ b/qg/src/test_util.rs
@@ -47,7 +47,6 @@
/// Returns a `PathBuf` to the file at the relative path `path` within
/// the `TestProject` temporary copy.
- #[allow(unused)]
pub fn relative_path(&self, path: impl AsRef<Path>) -> PathBuf {
self.project_root.path().join(path)
}