diff --git a/src/commands/init.rs b/src/commands/init.rs index 34406d6..d4ad01e 100644 --- a/src/commands/init.rs +++ b/src/commands/init.rs @@ -302,7 +302,7 @@ pub async fn run(cmd: &mut InitArgs) -> Result { }; // Write the manifest to `typst.toml`. - write_manifest(&manif)?; + write_manifest(&manifest, &manif)?; utpm_log!(info, "File created to {typ}"); Ok(true) diff --git a/src/main.rs b/src/main.rs index 3f86149..24e9189 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::process::ExitCode; + use anyhow::Result; use clap::Parser; use tracing::{error, instrument, level_filters::LevelFilter}; @@ -20,7 +22,7 @@ use utpm::{ /// sets up logging, and dispatches to the appropriate command handler. #[instrument] #[tokio::main] -async fn main() { +async fn main() -> ExitCode { // Parse command-line arguments. ARGS.set(Cli::parse()).expect("ARGS should still be empty"); let x = get_args(); @@ -86,6 +88,9 @@ async fn main() { Ok(_) => (), Err(err2) => error!("{err2}"), // If utpm_log errors, it will fallback to that }; + ExitCode::FAILURE + } else { + ExitCode::SUCCESS } } diff --git a/src/utils.rs b/src/utils.rs index 3b6411e..2121993 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -115,21 +115,22 @@ pub fn regex_import() -> Regex { .unwrap() } -/// Writes a `PackageManifest` to `./typst.toml` in pretty TOML format. +/// Writes a `PackageManifest` to the given path in pretty TOML format. /// /// Respects dry-run mode - if dry-run is enabled, the file is not actually written. /// /// # Arguments +/// * `path` - The path of the manifest file to write /// * `data` - The package manifest to write /// /// # Errors /// Returns an error if: /// - The manifest cannot be serialized to TOML /// - The file cannot be written (if not in dry-run mode) -pub fn write_manifest(data: &PackageManifest) -> Result<()> { +pub fn write_manifest(path: impl AsRef, data: &PackageManifest) -> Result<()> { let tomlfy: String = toml::to_string_pretty(data)?; if !crate::utils::dryrun::get_dry_run() { - std::fs::write(Path::new("./typst.toml"), tomlfy)?; + std::fs::write(path, tomlfy)?; } Ok(()) } diff --git a/tests/e2e/harness.rs b/tests/e2e/harness.rs index 67c4b92..811ad8e 100644 --- a/tests/e2e/harness.rs +++ b/tests/e2e/harness.rs @@ -98,6 +98,14 @@ impl Sandbox { pub fn utpm(&self, args: &[&str]) -> Run { Run::new(self.cmd(args)) } + + /// Runs `utpm` like [`Sandbox::utpm`], after letting `cb` adjust the command, e.g. to set + /// environment variables. + pub fn utpm_with(&self, args: &[&str], cb: impl FnOnce(&mut Command)) -> Run { + let mut cmd = self.cmd(args); + cb(&mut cmd); + Run::new(cmd) + } } /// The captured result of one `utpm` invocation. @@ -138,6 +146,18 @@ impl Run { self } + /// Asserts that the process exited with a failure status. + #[track_caller] + pub fn failure(&self) -> &Self { + assert!( + !self.output.status.success(), + "`utpm {}` unexpectedly succeeded\n{}", + self.args, + self.dump(), + ); + self + } + fn dump(&self) -> String { format!( "--- stdout\n{}\n--- stderr\n{}", diff --git a/tests/e2e/init.rs b/tests/e2e/init.rs index 478ec89..9768650 100644 --- a/tests/e2e/init.rs +++ b/tests/e2e/init.rs @@ -53,3 +53,17 @@ fn init_force_overwrites_existing_manifest() { assert_eq!(read_manifest(&sb).package.name, "my-pkg"); } + +#[test] +fn init_writes_manifest_to_utpm_current_dir() { + let sb = Sandbox::new(); + let target = sb.project().join("sub"); + std::fs::create_dir(&target).unwrap(); + + sb.utpm_with(&["prj", "init", "--cli", "--name", "my-pkg"], |cmd| { + cmd.env("UTPM_CURRENT_DIR", &target); + }) + .success(); + + assert_eq!(files_in(sb.project()), ["sub/typst.toml"]); +} diff --git a/tests/e2e/link.rs b/tests/e2e/link.rs index b6690e9..13a1c6e 100644 --- a/tests/e2e/link.rs +++ b/tests/e2e/link.rs @@ -49,7 +49,7 @@ fn link_without_force_keeps_existing_package() { sb.utpm(&["prj", "link"]).success(); sb.write("main.typ", "new"); - sb.utpm(&["prj", "link"]); + sb.utpm(&["prj", "link"]).failure(); let linked = sb.packages().join("local/my-pkg/0.1.0"); assert_eq!( @@ -100,3 +100,13 @@ fn link_dry_run_writes_nothing() { assert!(files_in(sb.packages()).is_empty()); } + +#[test] +fn link_without_manifest_fails() { + let sb = Sandbox::new(); + sb.write("main.typ", ""); + + sb.utpm(&["prj", "link"]).failure(); + + assert!(files_in(sb.packages()).is_empty()); +}