diff --git a/packages/zpm-switch/src/commands/mod.rs b/packages/zpm-switch/src/commands/mod.rs index 283ddc7f..b2631717 100644 --- a/packages/zpm-switch/src/commands/mod.rs +++ b/packages/zpm-switch/src/commands/mod.rs @@ -29,7 +29,7 @@ pub async fn run_default() -> ExitCode { cwd, args, version, - } = extract_bin_meta(); + } = extract_bin_meta().expect("Failed to extract binary metadata"); if let Some(cwd) = cwd { set_fake_cwd(cwd); diff --git a/packages/zpm-switch/src/commands/proxy.rs b/packages/zpm-switch/src/commands/proxy.rs index 950583c7..0894a829 100644 --- a/packages/zpm-switch/src/commands/proxy.rs +++ b/packages/zpm-switch/src/commands/proxy.rs @@ -3,7 +3,7 @@ use std::process::ExitStatus; use clipanion::cli; use zpm_utils::ToFileString; -use crate::{cwd::{get_fake_cwd, get_final_cwd}, errors::Error, manifest::{find_closest_package_manager, validate_package_manager}, yarn::get_default_yarn_version, yarn_enums::ReleaseLine}; +use crate::{cwd::{get_final_cwd, restore_args}, errors::Error, manifest::{find_closest_package_manager, validate_package_manager}, yarn::get_default_yarn_version, yarn_enums::ReleaseLine}; use super::switch::explicit::ExplicitCommand; @@ -39,9 +39,7 @@ impl ProxyCommand { = self.args.clone(); // Don't forget to add back the cwd parameter that was removed earlier on! - if let Some(cwd) = get_fake_cwd() { - args.insert(0, cwd.to_file_string()); - } + restore_args(&mut args); ExplicitCommand::run(&reference, &args).await } diff --git a/packages/zpm-switch/src/commands/switch/explicit.rs b/packages/zpm-switch/src/commands/switch/explicit.rs index 5a7833fa..b29f78ba 100644 --- a/packages/zpm-switch/src/commands/switch/explicit.rs +++ b/packages/zpm-switch/src/commands/switch/explicit.rs @@ -3,7 +3,7 @@ use std::process::{Command, ExitStatus, Stdio}; use clipanion::cli; use zpm_utils::ToFileString; -use crate::{cwd::{get_fake_cwd, get_final_cwd}, errors::Error, install::install_package_manager, manifest::{find_closest_package_manager, PackageManagerReference, VersionPackageManagerReference}, yarn::resolve_selector, yarn_enums::Selector}; +use crate::{cwd::{get_final_cwd, restore_args}, errors::Error, install::install_package_manager, manifest::{find_closest_package_manager, PackageManagerReference, VersionPackageManagerReference}, yarn::resolve_selector, yarn_enums::Selector}; #[cli::command(proxy)] #[cli::path("switch")] @@ -44,9 +44,7 @@ impl ExplicitCommand { = self.args.clone(); // Don't forget to add back the cwd parameter that was removed earlier on! - if let Some(cwd) = get_fake_cwd() { - args.insert(0, cwd.to_file_string()); - } + restore_args(&mut args); let version = resolve_selector(&self.selector).await?; diff --git a/packages/zpm-switch/src/cwd.rs b/packages/zpm-switch/src/cwd.rs index 1de4b474..16bf2f87 100644 --- a/packages/zpm-switch/src/cwd.rs +++ b/packages/zpm-switch/src/cwd.rs @@ -6,7 +6,7 @@ use std::sync::Mutex; -use zpm_utils::{Path, PathError}; +use zpm_utils::{Path, PathError, ToFileString}; static FAKE_CWD: Mutex> = Mutex::new(None); @@ -25,3 +25,10 @@ pub fn get_final_cwd() -> Result { Path::current_dir() } } + +pub fn restore_args(args: &mut Vec) { + if let Some(cwd) = get_fake_cwd() { + // We add an explicit `--cwd` so that both implicit and explicit cwd arguments are correctly forwarded. + args.insert(0, format!("--cwd={}", cwd.to_file_string())); + } +} diff --git a/packages/zpm-switch/src/yarn.rs b/packages/zpm-switch/src/yarn.rs index a652d5cc..b7cf8886 100644 --- a/packages/zpm-switch/src/yarn.rs +++ b/packages/zpm-switch/src/yarn.rs @@ -2,7 +2,7 @@ use serde::Deserialize; use serde_with::serde_as; use std::{collections::BTreeMap, str::FromStr}; use zpm_semver::{Range, Version}; -use zpm_utils::{ExplicitPath, FromFileString, Path, ToFileString}; +use zpm_utils::{ExplicitPath, FromFileString, Path, PathError, RawPath, ToFileString}; use crate::{errors::Error, http::fetch, manifest::{PackageManagerReference, VersionPackageManagerReference}, yarn_enums::{ChannelSelector, Selector}}; @@ -105,29 +105,52 @@ pub fn get_bin_version() -> String { .to_string() } -pub fn extract_bin_meta() -> BinMeta { +const CWD_FLAG: &str = "--cwd"; +const CWD_FLAG_EQUALS: &str = "--cwd="; + +pub fn extract_bin_meta() -> Result { let mut cwd = None; let mut args = std::env::args() .skip(1) .collect::>(); + if args.len() >= 2 && args[0] == CWD_FLAG { + let raw_path + = RawPath::from_str(&args[1])?; + + cwd = Some(raw_path.path); + args.drain(..2); + } else if args.len() >= 1 && args[0].starts_with(CWD_FLAG_EQUALS) { + let raw_path + = RawPath::from_str(&args[0][CWD_FLAG_EQUALS.len()..])?; + + cwd = Some(raw_path.path); + args.remove(0); + } + if let Some(first_arg) = args.first() { let explicit_path = ExplicitPath::from_str(first_arg); - if let Ok(explicit_path) = explicit_path { - cwd = Some(explicit_path.raw_path.path); - args.remove(0); + match explicit_path { + Ok(explicit_path) => { + cwd = Some(explicit_path.raw_path.path); + args.remove(0); + }, + Err(PathError::InvalidExplicitPathParameter(_)) => { + // This is not a valid explicit path, so we don't modify `cwd`. + }, + Err(err) => return Err(err), } } let version = get_bin_version(); - BinMeta { + Ok(BinMeta { cwd, args, version, - } + }) } diff --git a/packages/zpm/src/commands/entries/cwd.rs b/packages/zpm/src/commands/entries/cwd.rs new file mode 100644 index 00000000..a470c770 --- /dev/null +++ b/packages/zpm/src/commands/entries/cwd.rs @@ -0,0 +1,23 @@ +use std::{path::PathBuf, process::ExitCode}; + +use clipanion::{cli, prelude::Cli}; + +use crate::{commands::YarnCli, error::Error}; + +// TODO: Use clipanion to error on incorrect placement of `--cwd` argument. +#[cli::command(default, proxy)] +#[derive(Debug)] +pub struct Cwd { + #[cli::option("--cwd")] + cwd: String, + + args: Vec, +} + +impl Cwd { + pub fn execute(&self) -> Result { + std::env::set_current_dir(PathBuf::from(&self.cwd))?; + + Ok(YarnCli::run(self.cli_environment.clone().with_argv(self.args.clone()))) + } +} diff --git a/packages/zpm/src/commands/entries/mod.rs b/packages/zpm/src/commands/entries/mod.rs new file mode 100644 index 00000000..d794bea7 --- /dev/null +++ b/packages/zpm/src/commands/entries/mod.rs @@ -0,0 +1,2 @@ +pub mod cwd; +pub mod run; diff --git a/packages/zpm/src/commands/entries/run.rs b/packages/zpm/src/commands/entries/run.rs new file mode 100644 index 00000000..288e7220 --- /dev/null +++ b/packages/zpm/src/commands/entries/run.rs @@ -0,0 +1,37 @@ +use std::{process::ExitCode, str::FromStr}; + +use clipanion::{cli, prelude::Cli}; +use zpm_utils::{ExplicitPath, PathError}; + +use crate::{commands::YarnCli, error::Error}; + +#[cli::command(default, proxy)] +#[derive(Debug)] +pub struct Run { + leading_argument: String, + + args: Vec, +} + +impl Run { + pub fn execute(&self) -> Result { + match ExplicitPath::from_str(&self.leading_argument) { + Ok(explicit_path) => { + std::env::set_current_dir(explicit_path.raw_path.path.to_path_buf())?; + + Ok(YarnCli::run(self.cli_environment.clone().with_argv(self.args.clone()))) + }, + + Err(PathError::InvalidExplicitPathParameter(_)) => { + Ok(YarnCli::run(self.cli_environment.clone().with_argv( + ["run".to_owned(), self.leading_argument.clone()] + .into_iter() + .chain(self.args.clone()) + .collect() + ))) + }, + + Err(err) => Err(err.into()), + } + } +} diff --git a/packages/zpm/src/commands/mod.rs b/packages/zpm/src/commands/mod.rs index 63bbcffd..59fb5835 100644 --- a/packages/zpm/src/commands/mod.rs +++ b/packages/zpm/src/commands/mod.rs @@ -2,9 +2,10 @@ use std::process::ExitCode; use clipanion::{prelude::*, program, Environment}; use zpm_macros::track_time; -use zpm_switch::{extract_bin_meta, BinMeta}; +use zpm_switch::{extract_bin_meta, get_bin_version, BinMeta}; mod debug; +mod entries; mod add; mod bin; @@ -33,6 +34,9 @@ program!(YarnCli, [ debug::check_semver_version::CheckSemverVersion, debug::print_platform::PrintPlatform, + entries::cwd::Cwd, + entries::run::Run, + add::Add, bin::BinList, bin::Bin, @@ -58,23 +62,12 @@ program!(YarnCli, [ #[track_time] pub fn run_default() -> ExitCode { - let BinMeta { - cwd, - args, - version, - } = extract_bin_meta(); - - if let Some(cwd) = cwd { - cwd.sys_set_current_dir() - .expect("Failed to set current directory"); - } - let env = Environment::default() .with_program_name("Yarn Package Manager".to_string()) .with_binary_name("yarn".to_string()) - .with_version(version) - .with_argv(args); + .with_version(get_bin_version()) + .with_argv(std::env::args().skip(1).collect()); YarnCli::run(env) } diff --git a/packages/zpm/src/commands/run.rs b/packages/zpm/src/commands/run.rs index 60138d01..eaf2f9db 100644 --- a/packages/zpm/src/commands/run.rs +++ b/packages/zpm/src/commands/run.rs @@ -5,7 +5,7 @@ use clipanion::cli; use crate::{error::Error, project, script::ScriptEnvironment}; -#[cli::command(default, proxy)] +#[cli::command(proxy)] #[cli::path("run")] #[cli::category("Scripting commands")] #[cli::description("Run a dependency binary or local script")]