xtask_lib/tasks/util/
workspace.rs

1//! Workspace root resolution and metadata helpers.
2//!
3//! The xtask binary can be invoked from any directory inside the Cargo
4//! workspace.  All tasks need the workspace root so they can locate source
5//! files, thirdparty directories, and build outputs.
6
7use std::path::PathBuf;
8
9use anyhow::{Context, Result};
10use toml;
11
12/// Returns the absolute path to the Cargo workspace root.
13///
14/// Uses `CARGO_MANIFEST_DIR`, which Cargo sets to the `xtask/` directory when
15/// building the xtask binary.  The workspace root is one level up.
16///
17/// # Errors
18///
19/// Returns an error if the workspace root cannot be located (e.g. the binary
20/// is run outside the repository).
21///
22/// # Examples
23///
24/// ```no_run
25/// # use std::path::PathBuf;
26/// // Note: requires running inside the Cadmus workspace.
27/// let root = xtask_lib::tasks::util::workspace::root().unwrap();
28/// assert!(root.join("Cargo.toml").exists());
29/// ```
30pub fn root() -> Result<PathBuf> {
31    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
32        .context("CARGO_MANIFEST_DIR not set — run via `cargo xtask`")?;
33
34    let xtask_dir = PathBuf::from(manifest_dir);
35    let workspace_root = xtask_dir
36        .parent()
37        .context("xtask directory has no parent")?
38        .to_path_buf();
39
40    Ok(workspace_root)
41}
42
43/// Returns the version of the `cadmus` binary crate from its `Cargo.toml`.
44///
45/// # Errors
46///
47/// Returns an error if the workspace root cannot be found, the `Cargo.toml`
48/// cannot be read, or the version field is missing.
49pub fn current_version() -> Result<String> {
50    let workspace_root = root()?;
51    let cargo_toml_path = workspace_root.join("crates/cadmus/Cargo.toml");
52
53    let content = std::fs::read_to_string(&cargo_toml_path)
54        .with_context(|| format!("failed to read {}", cargo_toml_path.display()))?;
55
56    let doc: toml::Table = content
57        .parse()
58        .with_context(|| format!("failed to parse {}", cargo_toml_path.display()))?;
59
60    doc.get("package")
61        .and_then(|p| p.get("version"))
62        .and_then(|v| v.as_str())
63        .map(str::to_owned)
64        .context("version field not found in crates/cadmus/Cargo.toml")
65}