fn prepare_internal(
        &self,
        name: &str,
        prog_args: &[String],
        default_shell: &DefaultShell,
        top_level_args: Option<&[String]>,
    ) -> Result<Bone, String> {
        let args = match top_level_args {
            Some(args) => args,
            None => &self.args,
        };
        let at_top_level = top_level_args.is_none();
        if matches!(self.subcommands, None)
            || (matches!(self.subcommands, Some(_)) && matches!(self.cmd, Some(_)))
        {
            // We have either a direct command or a parent command that has irrelevant subcommands, either way we're interpolating into `cmd`
            // Get the vector of command wrappers
            // Assuming the transformation logic works, an error can't occur here
            let command_wrapper = self.cmd.as_ref().unwrap();
            // Interpolate for each individual command
            // We have to do this in a for loop for `?`
            let mut cmd_strs: Vec<String> = Vec::new();
            let (cmds, shell) = command_wrapper.get_commands_and_shell(default_shell);
            for cmd_str in cmds {
                let with_env_vars = Command::interpolate_env_vars(&cmd_str, &self.env_vars)?;
                let (with_args, remaining_args) =
                    Command::interpolate_specific_args(&with_env_vars, name, args, prog_args)?;
                let ready_cmd =
                    Command::interpolate_remaining_arguments(&with_args, &remaining_args);
                cmd_strs.push(ready_cmd);
            }

            Ok(
                // This does not contain recursive `BonesCommands`, so it's `Bone::Simple`
                Bone::Simple(BonesCore {
                    // We join every stage of the command into one, separated by the given delimiters
                    cmd: cmd_strs.join(&shell.delimiter),
                    // The shell is then just the vector of executable and arguments
                    shell: shell.parts.to_vec(),
                }),
            )
        } else if matches!(self.subcommands, Some(_)) && matches!(self.order, Some(_)) {
            // First, we resolve all the subcommands to vectors of strings to actually run
            let mut cmds: HashMap<String, Bone> = HashMap::new();
            // Now we run checks on whether the correct number of arguments have been provided if we're at the very top level
            // Otherwise error messages will relate to irrelevant subcommands
            // We don't check the case where too few arguments were provided because that's irrelevant (think about it)
            if at_top_level && args.len() > prog_args.len() {
                return Err(
                    format!(
                        "The command '{command}' requires {num_required_args} argument(s), but {num_given_args} argument(s) were provided (too few). Please provide all the required arguments.",
                        command=name,
                        num_required_args=args.len(),
                        num_given_args=&prog_args.len()
                    )
                );
            }
            // We `.unwrap()` here because we know more than the compiler
            for (subcommand_name, subcommand) in self.subcommands.as_ref().unwrap().iter() {
                // Parse the subcommand
                // We parse in the top-level arguments because ordered subcommands can't take their own, they inherit from this level (or the level this level inherits from, etc.)
                let cmd = subcommand.prepare_internal(
                    subcommand_name,
                    prog_args,
                    default_shell,
                    Some(args),
                )?;
                cmds.insert(subcommand_name.to_string(), cmd);
            }

            // Now we return a complex `Bone` (because it contains a `BonesCommand` with a directive)
            Ok(Bone::Complex(
                BonesCommand::new(self.order.as_ref().unwrap(), cmds), // We know more than the compiler by the check above
            ))
        } else {
            // This should not be possible!
            panic!("Critical logic failure in preparing command. You should report this as a bug.");
        }
    }
// This is the internal command preparation logic, which is called recursively.
// This also takes top-level arguments for recursing on ordered subcommands
This is the internal command preparation logic, which is called recursively.
This also takes top-level arguments for recursing on ordered subcommands
This is the internal command preparation logic which is called recursively . This also takes top - level arguments for recursing on ordered subcommands
fn prepare_internal(
        &self,
        name: &str,
        prog_args: &[String],
        default_shell: &DefaultShell,
        top_level_args: Option<&[String]>,
    ) -> Result<Bone, String> {
        let args = match top_level_args {
            Some(args) => args,
            None => &self.args,
        };
        let at_top_level = top_level_args.is_none();
        if matches!(self.subcommands, None)
            || (matches!(self.subcommands, Some(_)) && matches!(self.cmd, Some(_)))
        {
            // We have either a direct command or a parent command that has irrelevant subcommands, either way we're interpolating into `cmd`
            // Get the vector of command wrappers
            // Assuming the transformation logic works, an error can't occur here
            let command_wrapper = self.cmd.as_ref().unwrap();
            // Interpolate for each individual command
            // We have to do this in a for loop for `?`
            let mut cmd_strs: Vec<String> = Vec::new();
            let (cmds, shell) = command_wrapper.get_commands_and_shell(default_shell);
            for cmd_str in cmds {
                let with_env_vars = Command::interpolate_env_vars(&cmd_str, &self.env_vars)?;
                let (with_args, remaining_args) =
                    Command::interpolate_specific_args(&with_env_vars, name, args, prog_args)?;
                let ready_cmd =
                    Command::interpolate_remaining_arguments(&with_args, &remaining_args);
                cmd_strs.push(ready_cmd);
            }
            Ok(
                // This does not contain recursive `BonesCommands`, so it's `Bone::Simple`
                Bone::Simple(BonesCore {
                    // We join every stage of the command into one, separated by the given delimiters
                    cmd: cmd_strs.join(&shell.delimiter),
                    // The shell is then just the vector of executable and arguments
                    shell: shell.parts.to_vec(),
                }),
            )
        } else if matches!(self.subcommands, Some(_)) && matches!(self.order, Some(_)) {
            // First, we resolve all the subcommands to vectors of strings to actually run
            let mut cmds: HashMap<String, Bone> = HashMap::new();
            // Now we run checks on whether the correct number of arguments have been provided if we're at the very top level
            // Otherwise error messages will relate to irrelevant subcommands
            // We don't check the case where too few arguments were provided because that's irrelevant (think about it)
            if at_top_level && args.len() > prog_args.len() {
                return Err(
                    format!(
                        "The command '{command}' requires {num_required_args} argument(s), but {num_given_args} argument(s) were provided (too few). Please provide all the required arguments.",
                        command=name,
                        num_required_args=args.len(),
                        num_given_args=&prog_args.len()
                    )
                );
            }
            // We `.unwrap()` here because we know more than the compiler
            for (subcommand_name, subcommand) in self.subcommands.as_ref().unwrap().iter() {
                // Parse the subcommand
                // We parse in the top-level arguments because ordered subcommands can't take their own, they inherit from this level (or the level this level inherits from, etc.)
                let cmd = subcommand.prepare_internal(
                    subcommand_name,
                    prog_args,
                    default_shell,
                    Some(args),
                )?;
                cmds.insert(subcommand_name.to_string(), cmd);
            }
            // Now we return a complex `Bone` (because it contains a `BonesCommand` with a directive)
            Ok(Bone::Complex(
                BonesCommand::new(self.order.as_ref().unwrap(), cmds), // We know more than the compiler by the check above
            ))
        } else {
            // This should not be possible!
            panic!("Critical logic failure in preparing command. You should report this as a bug.");
        }
    }
fn prepare_internal ( & self , name : & str , prog_args : & [ String ] , default_shell : & DefaultShell , top_level_args : Option < & [ String ] > , ) -> Result < Bone , String > { let args = match top_level_args { Some ( args ) => args , None => & self . args , } ; let at_top_level = top_level_args . is_none ( ) ; if matches ! ( self subcommands None ) || ( matches ! ( self subcommands Some ( ) ) && matches ! ( self cmd Some ( ) ) ) { // We have either a direct command or a parent command that has irrelevant subcommands, either way we're interpolating into `cmd` // Get the vector of command wrappers // Assuming the transformation logic works, an error can't occur here let command_wrapper = self . cmd . as_ref ( ) . unwrap ( ) ; // Interpolate for each individual command // We have to do this in a for loop for `?` let mut cmd_strs : Vec < String > = Vec :: new ( ) ; let ( cmds , shell ) = command_wrapper . get_commands_and_shell ( default_shell ) ; for cmd_str in cmds { let with_env_vars = Command :: interpolate_env_vars ( & cmd_str , & self . env_vars ) ? ; let ( with_args , remaining_args ) = Command :: interpolate_specific_args ( & with_env_vars , name , args , prog_args ) ? ; let ready_cmd = Command :: interpolate_remaining_arguments ( & with_args , & remaining_args ) ; cmd_strs . push ( ready_cmd ) ; } Ok ( // This does not contain recursive `BonesCommands`, so it's `Bone::Simple` Bone :: Simple ( BonesCore { // We join every stage of the command into one, separated by the given delimiters cmd : cmd_strs . join ( & shell . delimiter ) , // The shell is then just the vector of executable and arguments shell : shell . parts . to_vec ( ) , } ) , ) } else if matches ! ( self subcommands Some ( ) ) && matches ! ( self order Some ( ) ) { // First, we resolve all the subcommands to vectors of strings to actually run let mut cmds : HashMap < String , Bone > = HashMap :: new ( ) ; // Now we run checks on whether the correct number of arguments have been provided if we're at the very top level // Otherwise error messages will relate to irrelevant subcommands // We don't check the case where too few arguments were provided because that's irrelevant (think about it) if at_top_level && args . len ( ) > prog_args . len ( ) { return Err ( format ! ( " " command name num_required_args args len ( ) num_given_args prog_args len ( ) ) ) ; } // We `.unwrap()` here because we know more than the compiler for ( subcommand_name , subcommand ) in self . subcommands . as_ref ( ) . unwrap ( ) . iter ( ) { // Parse the subcommand // We parse in the top-level arguments because ordered subcommands can't take their own, they inherit from this level (or the level this level inherits from, etc.) let cmd = subcommand . prepare_internal ( subcommand_name , prog_args , default_shell , Some ( args ) , ) ? ; cmds . insert ( subcommand_name . to_string ( ) , cmd ) ; } // Now we return a complex `Bone` (because it contains a `BonesCommand` with a directive) Ok ( Bone :: Complex ( BonesCommand :: new ( self . order . as_ref ( ) . unwrap ( ) , cmds ) , // We know more than the compiler by the check above ) ) } else { // This should not be possible! panic ! ( " " ) ; } }
This is the internal command preparation logic, which is called recursively.
This is the internal command preparation logic which is called recursively .
&self
name
&str
prog_args
&[String]
default_shell
&DefaultShell
top_level_args
Option<&[String]>