diff --git a/crates/turborepo-lib/src/cli.rs b/crates/turborepo-lib/src/cli.rs index 7c2a460f133ed..82be20ce08861 100644 --- a/crates/turborepo-lib/src/cli.rs +++ b/crates/turborepo-lib/src/cli.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Result}; use camino::Utf8PathBuf; use clap::{ArgAction, CommandFactory, Parser, Subcommand, ValueEnum}; use clap_complete::{generate, Shell}; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use tracing::{debug, error}; use turbopath::AbsoluteSystemPathBuf; @@ -202,8 +203,42 @@ pub enum LinkTarget { impl Args { pub fn new() -> Result { - let mut clap_args = match Args::try_parse() { - Ok(args) => args, + // We always pass --single-package in from the shim. + // We need to omit it, and then add it in for run. + let arg_separator_position = + std::env::args_os().position(|input_token| input_token == "--"); + + let single_package_position = + std::env::args_os().position(|input_token| input_token == "--single-package"); + + let is_single_package = match (arg_separator_position, single_package_position) { + (_, None) => false, + (None, Some(_)) => true, + (Some(arg_separator_position), Some(single_package_position)) => { + single_package_position < arg_separator_position + } + }; + + // Clap supports arbitrary iterators as input. + // We can remove all instances of --single-package + let single_package_free = std::env::args_os() + .enumerate() + .filter(|(index, input_token)| { + arg_separator_position + .is_some_and(|arg_separator_position| index > &arg_separator_position) + || input_token != "--single-package" + }) + .map(|(_, input_token)| input_token); + + let mut clap_args = match Args::try_parse_from(single_package_free) { + Ok(mut args) => { + // And then only add them back in when we're in `run`. + if let Some(ref mut run_args) = args.run_args { + run_args.single_package = is_single_package + } + + args + } // Don't use error logger when displaying help text Err(e) if matches!(