fn parse_scripts(
            raw_scripts: &Scripts,
            is_order_defined: bool,
        ) -> Result<schema::Scripts, String> {
            let mut scripts: schema::Scripts = HashMap::new();
            for (script_name, raw_command) in raw_scripts.iter() {
                let command = match raw_command {
                    Command::Simple(raw_command_wrapper) => schema::Command {
                        args: Vec::new(),
                        env_vars: Vec::new(),
                        subcommands: None,
                        order: None,
                        cmd: Some(raw_command_wrapper.parse()), // In the simple form, a command must be given (no subcommands can be specified)
                        description: None
                    },
                    Command::Complex {
                        args,
                        env_vars,
                        subcommands,
                        order,
                        cmd,
                        desc
                    } => schema::Command {
                        // If `order` is defined at the level above, we can't interpolate environment variables from here (has to be done at the level `order` was specified)
                        args: match is_order_defined {
                            // Unordered subcommands can't take arguments in any case of upper-level `order` definition
                            _ if matches!(subcommands, Some(_)) && matches!(order, None) && matches!(args, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: if `subcommands` is specified without `order`, `args` cannot be specified. This error occurred in in the '{}' script/subscript.", script_name)),
                            // If it was and `args` is specified, return an error
                            true if matches!(args, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: if `order` is specified, subscripts cannot specify `args`, as no environment variables can be provided to them. Environment variables to be interpolated in ordered subcommands must be set at the top-level. This error occurred in the '{}' script/subscript.", script_name)),
                            // If it was but args` isn't specified, it doesn't matter and we just give an empty vector instead
                            true => Vec::new(),
                            // If it wasn't, no validation needed
                            false => args.as_ref().unwrap_or(&Vec::new()).to_vec()
                        },
                        // This doesn't need any transformation, just a simple alternative if it's `None`
                        env_vars: env_vars.as_ref().unwrap_or(&Vec::new()).to_vec(),
                        // The subcommands are parsed recursively as scripts using this very function
                        // We parse through whether or not `order` is defined (has validation implications)
                        subcommands: match subcommands {
                            // We can't use `.map()` for this because we need support for `?`
                            Some(subcommands) => Some(
                                parse_scripts(subcommands, matches!(order, Some(_)))?
                            ),
                            None => None
                        },
                        // If `order` is defined at the level above and `subcommands` is defined here, `order` must be defined here too
                        order: match is_order_defined {
                            true if matches!(subcommands, Some(_)) => match order {
                                // If it was required and was given, no problem
                                Some(order) => Some(parse_directive_str(order)?),
                                // If it was required but not given, return an error
                                None => return Err(format!("Error in parsing Bonnie configuration file: if `order` is specified, all further nested subsubcommands must also specify `order`. This occurred in the '{}' script/subscript.", script_name))
                            }
                            // If it wasn't required, no validation needed
                            true | false => match order {
                                Some(order) => Some(parse_directive_str(order)?),
                                None => None
                            }
                        },
                        // If subcommands were specified, this is optional, otherwise we return an error
                        cmd: match cmd {
                            // It was given, but there are also ordered subcommands here, so execution will be ambiguous, return an error
                            Some(_) if matches!(order, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: both `cmd` and `order` were specified. This would lead to problems of ambiguous execution, so commands can have either the top-level `cmd` property or ordered subcommands, the two are mutually exclusive. This error occurred in in the '{}' script/subscript.", script_name)),
                            // It's optional
                            _ if matches!(subcommands, Some(_)) => cmd.as_ref().map(|cmd| cmd.parse()),
                            // It's mandatory and given
                            Some(cmd) => Some(cmd.parse()),
                            // It's mandatory and not given
                            None => return Err(format!("Error in parsing Bonnie configuration file: if `subcommands` is not specified, `cmd` is mandatory. This error occurred in in the '{}' script/subscript.", script_name))
                        },
                        description: desc.clone()
                    },
                };
                scripts.insert(script_name.to_string(), command);
            }

            Ok(scripts)
        }
// Parse the scripts (brace yourself!)
// We do this inside a function because it's recursive
// Unfortunately we can't define methods on type aliases, so this goes here
// This involves validation logic to ensure invalid property combinations aren't specified, so we need to know whether or not `order` is specified if this is parsing subcommands
Parse the scripts (brace yourself!)
We do this inside a function because it's recursive
Unfortunately we can't define methods on type aliases, so this goes here
This involves validation logic to ensure invalid property combinations aren't specified, so we need to know whether or not `order` is specified if this is parsing subcommands
Parse the scripts ( brace yourself! ) We do this inside a function because it ' s recursive Unfortunately we can ' t define methods on type aliases so this goes here This involves validation logic to ensure invalid property combinations aren ' t specified so we need to know whether or not ` order ` is specified if this is parsing subcommands
fn parse_scripts(
            raw_scripts: &Scripts,
            is_order_defined: bool,
        ) -> Result<schema::Scripts, String> {
            let mut scripts: schema::Scripts = HashMap::new();
            for (script_name, raw_command) in raw_scripts.iter() {
                let command = match raw_command {
                    Command::Simple(raw_command_wrapper) => schema::Command {
                        args: Vec::new(),
                        env_vars: Vec::new(),
                        subcommands: None,
                        order: None,
                        cmd: Some(raw_command_wrapper.parse()), // In the simple form, a command must be given (no subcommands can be specified)
                        description: None
                    },
                    Command::Complex {
                        args,
                        env_vars,
                        subcommands,
                        order,
                        cmd,
                        desc
                    } => schema::Command {
                        // If `order` is defined at the level above, we can't interpolate environment variables from here (has to be done at the level `order` was specified)
                        args: match is_order_defined {
                            // Unordered subcommands can't take arguments in any case of upper-level `order` definition
                            _ if matches!(subcommands, Some(_)) && matches!(order, None) && matches!(args, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: if `subcommands` is specified without `order`, `args` cannot be specified. This error occurred in in the '{}' script/subscript.", script_name)),
                            // If it was and `args` is specified, return an error
                            true if matches!(args, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: if `order` is specified, subscripts cannot specify `args`, as no environment variables can be provided to them. Environment variables to be interpolated in ordered subcommands must be set at the top-level. This error occurred in the '{}' script/subscript.", script_name)),
                            // If it was but args` isn't specified, it doesn't matter and we just give an empty vector instead
                            true => Vec::new(),
                            // If it wasn't, no validation needed
                            false => args.as_ref().unwrap_or(&Vec::new()).to_vec()
                        },
                        // This doesn't need any transformation, just a simple alternative if it's `None`
                        env_vars: env_vars.as_ref().unwrap_or(&Vec::new()).to_vec(),
                        // The subcommands are parsed recursively as scripts using this very function
                        // We parse through whether or not `order` is defined (has validation implications)
                        subcommands: match subcommands {
                            // We can't use `.map()` for this because we need support for `?`
                            Some(subcommands) => Some(
                                parse_scripts(subcommands, matches!(order, Some(_)))?
                            ),
                            None => None
                        },
                        // If `order` is defined at the level above and `subcommands` is defined here, `order` must be defined here too
                        order: match is_order_defined {
                            true if matches!(subcommands, Some(_)) => match order {
                                // If it was required and was given, no problem
                                Some(order) => Some(parse_directive_str(order)?),
                                // If it was required but not given, return an error
                                None => return Err(format!("Error in parsing Bonnie configuration file: if `order` is specified, all further nested subsubcommands must also specify `order`. This occurred in the '{}' script/subscript.", script_name))
                            }
                            // If it wasn't required, no validation needed
                            true | false => match order {
                                Some(order) => Some(parse_directive_str(order)?),
                                None => None
                            }
                        },
                        // If subcommands were specified, this is optional, otherwise we return an error
                        cmd: match cmd {
                            // It was given, but there are also ordered subcommands here, so execution will be ambiguous, return an error
                            Some(_) if matches!(order, Some(_)) => return Err(format!("Error in parsing Bonnie configuration file: both `cmd` and `order` were specified. This would lead to problems of ambiguous execution, so commands can have either the top-level `cmd` property or ordered subcommands, the two are mutually exclusive. This error occurred in in the '{}' script/subscript.", script_name)),
                            // It's optional
                            _ if matches!(subcommands, Some(_)) => cmd.as_ref().map(|cmd| cmd.parse()),
                            // It's mandatory and given
                            Some(cmd) => Some(cmd.parse()),
                            // It's mandatory and not given
                            None => return Err(format!("Error in parsing Bonnie configuration file: if `subcommands` is not specified, `cmd` is mandatory. This error occurred in in the '{}' script/subscript.", script_name))
                        },
                        description: desc.clone()
                    },
                };
                scripts.insert(script_name.to_string(), command);
            }
            Ok(scripts)
        }
fn parse_scripts ( raw_scripts : & Scripts , is_order_defined : bool , ) -> Result < schema :: Scripts , String > { let mut scripts : schema :: Scripts = HashMap :: new ( ) ; for ( script_name , raw_command ) in raw_scripts . iter ( ) { let command = match raw_command { Command :: Simple ( raw_command_wrapper ) => schema :: Command { args : Vec :: new ( ) , env_vars : Vec :: new ( ) , subcommands : None , order : None , cmd : Some ( raw_command_wrapper . parse ( ) ) , // In the simple form, a command must be given (no subcommands can be specified) description : None } , Command :: Complex { args , env_vars , subcommands , order , cmd , desc } => schema :: Command { // If `order` is defined at the level above, we can't interpolate environment variables from here (has to be done at the level `order` was specified) args : match is_order_defined { // Unordered subcommands can't take arguments in any case of upper-level `order` definition _ if matches ! ( subcommands Some ( ) ) && matches ! ( order None ) && matches ! ( args Some ( ) ) => return Err ( format ! ( " " script_name ) ) , // If it was and `args` is specified, return an error true if matches ! ( args Some ( ) ) => return Err ( format ! ( " " script_name ) ) , // If it was but args` isn't specified, it doesn't matter and we just give an empty vector instead true => Vec :: new ( ) , // If it wasn't, no validation needed false => args . as_ref ( ) . unwrap_or ( & Vec :: new ( ) ) . to_vec ( ) } , // This doesn't need any transformation, just a simple alternative if it's `None` env_vars : env_vars . as_ref ( ) . unwrap_or ( & Vec :: new ( ) ) . to_vec ( ) , // The subcommands are parsed recursively as scripts using this very function // We parse through whether or not `order` is defined (has validation implications) subcommands : match subcommands { // We can't use `.map()` for this because we need support for `?` Some ( subcommands ) => Some ( parse_scripts ( subcommands , matches ! ( order Some ( ) ) ) ? ) , None => None } , // If `order` is defined at the level above and `subcommands` is defined here, `order` must be defined here too order : match is_order_defined { true if matches ! ( subcommands Some ( ) ) => match order { // If it was required and was given, no problem Some ( order ) => Some ( parse_directive_str ( order ) ? ) , // If it was required but not given, return an error None => return Err ( format ! ( " " script_name ) ) } // If it wasn't required, no validation needed true | false => match order { Some ( order ) => Some ( parse_directive_str ( order ) ? ) , None => None } } , // If subcommands were specified, this is optional, otherwise we return an error cmd : match cmd { // It was given, but there are also ordered subcommands here, so execution will be ambiguous, return an error Some ( _ ) if matches ! ( order Some ( ) ) => return Err ( format ! ( " " script_name ) ) , // It's optional _ if matches ! ( subcommands Some ( ) ) => cmd . as_ref ( ) . map ( | cmd | cmd . parse ( ) ) , // It's mandatory and given Some ( cmd ) => Some ( cmd . parse ( ) ) , // It's mandatory and not given None => return Err ( format ! ( " " script_name ) ) } , description : desc . clone ( ) } , } ; scripts . insert ( script_name . to_string ( ) , command ) ; } Ok ( scripts ) }
Parse the scripts (brace yourself!)
Parse the scripts ( brace yourself! )
raw_scripts
&Scripts
is_order_defined
bool