Skip to content

Commit

Permalink
Claify the naming and purpose of the workspace file
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Bottriell <[email protected]>
  • Loading branch information
rydrman committed Jan 14, 2025
1 parent 50010a2 commit f775b5c
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 26 deletions.
6 changes: 3 additions & 3 deletions crates/spk-workspace/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::path::PathBuf;

#[derive(thiserror::Error, miette::Diagnostic, Debug)]
pub enum LoadWorkspaceError {
pub enum LoadWorkspaceFileError {
#[error(
"workspace not found, no {} in {0:?} or any parent",
crate::Workspace::FILE_NAME
crate::WorkspaceFile::FILE_NAME
)]
WorkspaceNotFound(PathBuf),
#[error("'{}' not found in {0:?}", crate::Workspace::FILE_NAME)]
#[error("'{}' not found in {0:?}", crate::WorkspaceFile::FILE_NAME)]
NoWorkspaceFile(PathBuf),
#[error(transparent)]
ReadFailed(std::io::Error),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,42 @@ use std::path::Path;
use serde::{Deserialize, Serialize};
use spk_schema_foundation::FromYaml;

use crate::error::LoadWorkspaceError;
use crate::error::LoadWorkspaceFileError;

#[cfg(test)]
#[path = "spec_test.rs"]
mod spec_test;
#[path = "file_test.rs"]
mod file_test;

/// Describes a workspace configuration.
///
/// Contains information about the layout of the workspace,
/// and where to find data, usually loaded from a file on disk.
/// It must still be fully validated and loaded into a
/// [`super::Workspace`] to be operated on.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Deserialize, Serialize)]
pub struct Workspace {
pub struct WorkspaceFile {
#[serde(default, skip_serializing_if = "Vec::is_empty", with = "glob_from_str")]
pub recipes: Vec<glob::Pattern>,
}

impl Workspace {
impl WorkspaceFile {
pub const FILE_NAME: &str = "workspace.spk.yaml";

/// Load a workspace from its root directory on disk
pub fn load<P: AsRef<Path>>(root: P) -> Result<Self, LoadWorkspaceError> {
pub fn load<P: AsRef<Path>>(root: P) -> Result<Self, LoadWorkspaceFileError> {
let root = root
.as_ref()
.canonicalize()
.map_err(|_| LoadWorkspaceError::NoWorkspaceFile(root.as_ref().into()))?;
.map_err(|_| LoadWorkspaceFileError::NoWorkspaceFile(root.as_ref().into()))?;

let workspace_file = std::fs::read_to_string(root.join(Workspace::FILE_NAME))
.map_err(LoadWorkspaceError::ReadFailed)?;
Workspace::from_yaml(workspace_file).map_err(LoadWorkspaceError::InvalidYaml)
let workspace_file = std::fs::read_to_string(root.join(WorkspaceFile::FILE_NAME))
.map_err(LoadWorkspaceFileError::ReadFailed)?;
WorkspaceFile::from_yaml(workspace_file).map_err(LoadWorkspaceFileError::InvalidYaml)
}

/// Load the workspace for a given dir, looking at parent directories
/// as necessary to find the workspace root
pub fn discover<P: AsRef<Path>>(cwd: P) -> Result<Self, LoadWorkspaceError> {
pub fn discover<P: AsRef<Path>>(cwd: P) -> Result<Self, LoadWorkspaceFileError> {
let cwd = if cwd.as_ref().is_absolute() {
cwd.as_ref().to_owned()
} else {
Expand All @@ -48,7 +54,7 @@ impl Workspace {
let mut last_found = None;

loop {
if candidate.join(Workspace::FILE_NAME).is_file() {
if candidate.join(WorkspaceFile::FILE_NAME).is_file() {
last_found = Some(candidate.clone());
}
if !candidate.pop() {
Expand All @@ -57,7 +63,7 @@ impl Workspace {
}
match last_found {
Some(path) => Self::load(path),
None => Err(LoadWorkspaceError::WorkspaceNotFound(cwd)),
None => Err(LoadWorkspaceFileError::WorkspaceNotFound(cwd)),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rstest::{fixture, rstest};

use super::Workspace;
use super::WorkspaceFile;

#[fixture]
pub fn tmpdir() -> tempfile::TempDir {
Expand All @@ -17,30 +17,30 @@ recipes: []

#[rstest]
fn test_workspace_roundtrip() {
let workspace = Workspace {
let workspace = WorkspaceFile {
recipes: vec![
glob::Pattern::new("packages/*/*.spk.yml").unwrap(),
glob::Pattern::new("platforms/*/*.spk.yml").unwrap(),
],
};

let serialized = serde_json::to_string(&workspace).unwrap();
let deserialized: Workspace = serde_json::from_str(&serialized).unwrap();
let deserialized: WorkspaceFile = serde_json::from_str(&serialized).unwrap();

assert_eq!(workspace, deserialized);
}

#[rstest]
fn test_empty_workspace_loading(tmpdir: tempfile::TempDir) {
let root = tmpdir.path();
std::fs::write(root.join(Workspace::FILE_NAME), EMPTY_WORKSPACE).unwrap();
let _workspace = Workspace::load(root).expect("failed to load empty workspace");
std::fs::write(root.join(WorkspaceFile::FILE_NAME), EMPTY_WORKSPACE).unwrap();
let _workspace = WorkspaceFile::load(root).expect("failed to load empty workspace");
}

#[rstest]
fn test_must_have_file(tmpdir: tempfile::TempDir) {
let root = tmpdir.path();
Workspace::load(root).expect_err("workspace should fail to load for empty dir");
WorkspaceFile::load(root).expect_err("workspace should fail to load for empty dir");
}

#[rstest]
Expand All @@ -63,7 +63,7 @@ fn test_workspace_discovery(

std::fs::create_dir_all(&cwd).unwrap();
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join(Workspace::FILE_NAME), EMPTY_WORKSPACE).unwrap();
std::fs::write(root.join(WorkspaceFile::FILE_NAME), EMPTY_WORKSPACE).unwrap();

Workspace::discover(&cwd).expect("failed to load workspace");
WorkspaceFile::discover(&cwd).expect("failed to load workspace");
}
4 changes: 2 additions & 2 deletions crates/spk-workspace/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod error;
mod spec;
mod file;

pub use spec::Workspace;
pub use file::WorkspaceFile;

0 comments on commit f775b5c

Please sign in to comment.