diff --git a/src/errors.rs b/src/errors.rs index 5a3a80c..3c9d7d1 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -122,4 +122,20 @@ pub enum AxoprojectError { /// Version we were looking for version: Version, }, + + /// Root dist.toml contains no expected keys + #[error("Root dist.toml at {path} is malformed.")] + #[diagnostic(help("We expected either a [workspace] or [package] section in the root dist.toml file, but found neither."))] + DistTomlMalformedError { + /// Path ofthe file + path: Utf8PathBuf, + }, + + /// Loading a package-specific dist.toml with no root \[package\] element + #[error("Couldn't find a [package] section in {path}.")] + #[diagnostic(help("We expected this dist.toml to belong to a package."))] + PackageMissingError { + /// Path ofthe file + path: Utf8PathBuf, + }, } diff --git a/src/generic.rs b/src/generic.rs index 754fa2a..35f5b66 100644 --- a/src/generic.rs +++ b/src/generic.rs @@ -4,11 +4,19 @@ use axoasset::SourceFile; use camino::{Utf8Path, Utf8PathBuf}; use serde::Deserialize; -use crate::{PackageInfo, Result, Version, WorkspaceInfo, WorkspaceSearch}; +use crate::{ + errors::AxoprojectError, PackageInfo, Result, Version, WorkspaceInfo, WorkspaceSearch, +}; #[derive(Deserialize)] struct Manifest { - package: Package, + workspace: Option, + package: Option, +} + +#[derive(Deserialize)] +struct Workspace { + members: Option>, } #[derive(Deserialize)] @@ -53,17 +61,56 @@ pub fn get_workspace(start_dir: &Utf8Path, clamp_to_dir: Option<&Utf8Path>) -> W } } +fn manifest_workspace_members(manifest: &Manifest) -> Option> { + if let Some(workspace) = &manifest.workspace { + if let Some(members) = &workspace.members { + Some(members.to_owned()) + } else { + None + } + } else { + None + } +} + fn workspace_from(manifest_path: &Utf8Path) -> Result { let workspace_dir = manifest_path.parent().unwrap().to_path_buf(); - let root_auto_includes = crate::find_auto_includes(&workspace_dir)?; - let manifest: Manifest = load_root_dist_toml(manifest_path)?; - let package = manifest.package; - let version = package.version.map(Version::Generic); + let manifest = load_root_dist_toml(manifest_path)?; + // If this is a workspace, read its members and map those entries + // to expected paths on disk + let expected_paths = if let Some(members) = manifest_workspace_members(&manifest) { + members + .iter() + .map(|name| workspace_dir.join(name)) + .map(Utf8PathBuf::from) + .collect() + // If this *isn't* a workspace, the root is the only app + } else if manifest.package.is_some() { + vec![workspace_dir.to_path_buf()] + } else { + return Err(AxoprojectError::DistTomlMalformedError { + path: manifest_path.to_path_buf(), + }); + }; - let manifest_path = manifest_path.to_path_buf(); + workspace_info(manifest_path, &workspace_dir, &expected_paths) +} - let package_info = PackageInfo { +fn package_info(manifest_root: &Utf8PathBuf) -> Result { + let manifest_path = manifest_root.join("dist.toml"); + let manifest = load_root_dist_toml(&manifest_path)?; + + let package = if let Some(package) = manifest.package { + package + } else { + return Err(AxoprojectError::PackageMissingError { + path: manifest_path, + }); + }; + let version = package.version.map(Version::Generic); + + Ok(PackageInfo { manifest_path: manifest_path.clone(), package_root: manifest_path.clone(), name: package.name, @@ -86,18 +133,36 @@ fn workspace_from(manifest_path: &Utf8Path) -> Result { cargo_metadata_table: None, #[cfg(feature = "cargo-projects")] cargo_package_id: None, - }; + build_command: Some(package.build_command), + }) +} + +fn workspace_info( + manifest_path: &Utf8Path, + workspace_dir: &Utf8PathBuf, + expected_paths: &[Utf8PathBuf], +) -> Result { + let root_auto_includes = crate::find_auto_includes(workspace_dir)?; + + let package_info = expected_paths + .iter() + .map(|path| package_info(path).unwrap()) + .collect::>(); + + let repository_url = package_info + .first() + .map(|p| p.repository_url.to_owned()) + .unwrap_or(None); Ok(WorkspaceInfo { kind: crate::WorkspaceKind::Generic, target_dir: workspace_dir.join("target"), - workspace_dir, - package_info: vec![package_info], - manifest_path, - repository_url: package.repository, + workspace_dir: workspace_dir.to_owned(), + package_info, + manifest_path: manifest_path.to_owned(), + repository_url, root_auto_includes, warnings: vec![], - build_command: Some(package.build_command), #[cfg(feature = "cargo-projects")] cargo_metadata_table: None, #[cfg(feature = "cargo-projects")] diff --git a/src/javascript.rs b/src/javascript.rs index ad5ab36..bb8b08f 100644 --- a/src/javascript.rs +++ b/src/javascript.rs @@ -134,6 +134,7 @@ fn read_workspace(manifest_path: &Utf8Path) -> Result { cargo_metadata_table: None, #[cfg(feature = "cargo-projects")] cargo_package_id: None, + build_command: None, }; crate::merge_auto_includes(&mut info, &root_auto_includes); @@ -148,7 +149,6 @@ fn read_workspace(manifest_path: &Utf8Path) -> Result { repository_url, root_auto_includes, warnings: vec![], - build_command: None, #[cfg(feature = "cargo-projects")] cargo_metadata_table: None, #[cfg(feature = "cargo-projects")] diff --git a/src/lib.rs b/src/lib.rs index e9a4c15..476fcc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,8 +148,6 @@ pub struct WorkspaceInfo { pub root_auto_includes: AutoIncludes, /// Non-fatal issues that were encountered and should probably be reported pub warnings: Vec, - /// Build command to run for this workspace; not required for cargo - pub build_command: Option>, /// Raw cargo `[workspace.metadata]` table #[cfg(feature = "cargo-projects")] pub cargo_metadata_table: Option, @@ -300,6 +298,8 @@ pub struct PackageInfo { /// A unique id used by Cargo to refer to the package #[cfg(feature = "cargo-projects")] pub cargo_package_id: Option, + /// Build command to run for this workspace; not required for cargo + pub build_command: Option>, } impl PackageInfo { diff --git a/src/rust.rs b/src/rust.rs index 667fa15..bfcdfa5 100644 --- a/src/rust.rs +++ b/src/rust.rs @@ -136,7 +136,6 @@ fn workspace_info(pkg_graph: &PackageGraph) -> Result { cargo_profiles, warnings, - build_command: None, }) } @@ -259,6 +258,7 @@ fn package_info(_workspace_root: &Utf8Path, package: &PackageMetadata) -> Result cstaticlibs, cargo_metadata_table, cargo_package_id, + build_command: None, }; // Find files we might want to auto-include