Allow setting more command-line options with environment variables (#2161)
This commit is contained in:
parent
b05a75d168
commit
1547af08b5
325
src/config.rs
325
src/config.rs
@ -7,10 +7,6 @@ use {
|
||||
},
|
||||
};
|
||||
|
||||
const CHOOSE_HELP: &str = "Select one or more recipes to run using a binary chooser. \
|
||||
If `--chooser` is not passed the chooser defaults to the \
|
||||
value of $JUST_CHOOSER, falling back to `fzf`";
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct Config {
|
||||
pub(crate) check: bool,
|
||||
@ -154,17 +150,20 @@ impl Config {
|
||||
.trailing_var_arg(true)
|
||||
.styles(
|
||||
Styles::styled()
|
||||
.header(AnsiColor::Yellow.on_default())
|
||||
.usage(AnsiColor::Yellow.on_default())
|
||||
.literal(AnsiColor::Green.on_default())
|
||||
.placeholder(AnsiColor::Green.on_default())
|
||||
.header(AnsiColor::Yellow.on_default())
|
||||
.literal(AnsiColor::Green.on_default())
|
||||
.placeholder(AnsiColor::Green.on_default())
|
||||
.usage(AnsiColor::Yellow.on_default()),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::CHECK)
|
||||
.long("check")
|
||||
.action(ArgAction::SetTrue)
|
||||
.requires(cmd::FORMAT)
|
||||
.help("Run `--fmt` in 'check' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required."),
|
||||
.help(
|
||||
"Run `--fmt` in 'check' mode. Exits with 0 if justfile is formatted correctly. \
|
||||
Exits with 1 and prints a diff if formatting is required.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::CHOOSER)
|
||||
@ -173,6 +172,13 @@ impl Config {
|
||||
.action(ArgAction::Set)
|
||||
.help("Override binary invoked by `--choose`"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::CLEAR_SHELL_ARGS)
|
||||
.long("clear-shell-args")
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(arg::SHELL_ARG)
|
||||
.help("Clear shell arguments"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::COLOR)
|
||||
.long("color")
|
||||
@ -190,7 +196,21 @@ impl Config {
|
||||
.value_parser(PossibleValuesParser::new(arg::COMMAND_COLOR_VALUES))
|
||||
.help("Echo recipe lines in <COMMAND-COLOR>"),
|
||||
)
|
||||
.arg(Arg::new(arg::YES).long("yes").action(ArgAction::SetTrue).help("Automatically confirm all recipes."))
|
||||
.arg(
|
||||
Arg::new(arg::DOTENV_FILENAME)
|
||||
.long("dotenv-filename")
|
||||
.action(ArgAction::Set)
|
||||
.help("Search for environment file named <DOTENV-FILENAME> instead of `.env`")
|
||||
.conflicts_with(arg::DOTENV_PATH),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::DOTENV_PATH)
|
||||
.short('E')
|
||||
.long("dotenv-path")
|
||||
.action(ArgAction::Set)
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.help("Load <DOTENV-PATH> as environment file instead of searching for one"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::DRY_RUN)
|
||||
.short('n')
|
||||
@ -203,66 +223,30 @@ impl Config {
|
||||
.arg(
|
||||
Arg::new(arg::DUMP_FORMAT)
|
||||
.long("dump-format")
|
||||
.env("JUST_DUMP_FORMAT")
|
||||
.action(ArgAction::Set)
|
||||
.value_parser(PossibleValuesParser::new(arg::DUMP_FORMAT_VALUES))
|
||||
.default_value(arg::DUMP_FORMAT_JUST)
|
||||
.value_name("FORMAT")
|
||||
.help("Dump justfile as <FORMAT>"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::GLOBAL_JUSTFILE)
|
||||
.action(ArgAction::SetTrue)
|
||||
.long("global-justfile")
|
||||
.short('g')
|
||||
.conflicts_with(arg::JUSTFILE)
|
||||
.conflicts_with(arg::WORKING_DIRECTORY)
|
||||
.help("Use global justfile"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::HIGHLIGHT)
|
||||
.long("highlight")
|
||||
.env("JUST_HIGHLIGHT")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Highlight echoed recipe lines in bold")
|
||||
.overrides_with(arg::NO_HIGHLIGHT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_HEADING)
|
||||
.long("list-heading")
|
||||
.help("Print <TEXT> before list")
|
||||
.value_name("TEXT")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_PREFIX)
|
||||
.long("list-prefix")
|
||||
.help("Print <TEXT> before each list item")
|
||||
.value_name("TEXT")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_SUBMODULES)
|
||||
.long("list-submodules")
|
||||
.help("List recipes in submodules")
|
||||
.action(ArgAction::SetTrue)
|
||||
.env("JUST_LIST_SUBMODULES"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_ALIASES)
|
||||
.long("no-aliases")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't show aliases in list"),
|
||||
)
|
||||
.arg (
|
||||
Arg::new(arg::NO_DEPS)
|
||||
.long("no-deps")
|
||||
.alias("no-dependencies")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't run recipe dependencies")
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_DOTENV)
|
||||
.long("no-dotenv")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't load `.env` file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_HIGHLIGHT)
|
||||
.long("no-highlight")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't highlight echoed recipe lines in bold")
|
||||
.overrides_with(arg::HIGHLIGHT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::JUSTFILE)
|
||||
.short('f')
|
||||
@ -272,6 +256,60 @@ impl Config {
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.help("Use <JUSTFILE> as justfile"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_HEADING)
|
||||
.long("list-heading")
|
||||
.env("JUST_LIST_HEADING")
|
||||
.help("Print <TEXT> before list")
|
||||
.value_name("TEXT")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_PREFIX)
|
||||
.long("list-prefix")
|
||||
.env("JUST_LIST_PREFIX")
|
||||
.help("Print <TEXT> before each list item")
|
||||
.value_name("TEXT")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::LIST_SUBMODULES)
|
||||
.long("list-submodules")
|
||||
.env("JUST_LIST_SUBMODULES")
|
||||
.help("List recipes in submodules")
|
||||
.action(ArgAction::SetTrue)
|
||||
.env("JUST_LIST_SUBMODULES"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_ALIASES)
|
||||
.long("no-aliases")
|
||||
.env("JUST_NO_ALIASES")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't show aliases in list"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_DEPS)
|
||||
.long("no-deps")
|
||||
.env("JUST_NO_DEPS")
|
||||
.alias("no-dependencies")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't run recipe dependencies"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_DOTENV)
|
||||
.long("no-dotenv")
|
||||
.env("JUST_NO_DOTENV")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't load `.env` file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::NO_HIGHLIGHT)
|
||||
.long("no-highlight")
|
||||
.env("JUST_NO_HIGHLIGHT")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Don't highlight echoed recipe lines in bold")
|
||||
.overrides_with(arg::HIGHLIGHT),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::QUIET)
|
||||
.short('q')
|
||||
@ -311,15 +349,24 @@ impl Config {
|
||||
.help("Invoke <COMMAND> with the shell used to run recipe lines and backticks"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::CLEAR_SHELL_ARGS)
|
||||
.long("clear-shell-args")
|
||||
Arg::new(arg::TIMESTAMP)
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(arg::SHELL_ARG)
|
||||
.help("Clear shell arguments"),
|
||||
.long("timestamp")
|
||||
.env("JUST_TIMESTAMP")
|
||||
.help("Print recipe command timestamps"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::TIMESTAMP_FORMAT)
|
||||
.action(ArgAction::Set)
|
||||
.long("timestamp-format")
|
||||
.env("JUST_TIMESTAMP_FORMAT")
|
||||
.default_value("%H:%M:%S")
|
||||
.help("Timestamp format string"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::UNSORTED)
|
||||
.long("unsorted")
|
||||
.env("JUST_UNSORTED")
|
||||
.short('u')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Return list and summary entries in source order"),
|
||||
@ -350,13 +397,28 @@ impl Config {
|
||||
.help("Use <WORKING-DIRECTORY> as working directory. --justfile must also be set")
|
||||
.requires(arg::JUSTFILE),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::YES)
|
||||
.long("yes")
|
||||
.env("JUST_YES")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Automatically confirm all recipes."),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::CHANGELOG)
|
||||
.long("changelog")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Print changelog"),
|
||||
)
|
||||
.arg(Arg::new(cmd::CHOOSE).long("choose").action(ArgAction::SetTrue).help(CHOOSE_HELP))
|
||||
.arg(
|
||||
Arg::new(cmd::CHOOSE)
|
||||
.long("choose")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Select one or more recipes to run using a binary chooser. If `--chooser` is not \
|
||||
passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::COMMAND)
|
||||
.long("command")
|
||||
@ -395,6 +457,7 @@ impl Config {
|
||||
.arg(
|
||||
Arg::new(cmd::EVALUATE)
|
||||
.long("evaluate")
|
||||
.alias("eval")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(
|
||||
"Evaluate and print all variables. If a variable name is given as an argument, only \
|
||||
@ -408,6 +471,12 @@ impl Config {
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Format and overwrite justfile"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::GROUPS)
|
||||
.long("groups")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("List recipe groups"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::INIT)
|
||||
.long("init")
|
||||
@ -425,12 +494,6 @@ impl Config {
|
||||
.conflicts_with(arg::ARGUMENTS)
|
||||
.help("List available recipes"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::GROUPS)
|
||||
.long("groups")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("List recipe groups")
|
||||
)
|
||||
.arg(
|
||||
Arg::new(cmd::MAN)
|
||||
.long("man")
|
||||
@ -459,21 +522,6 @@ impl Config {
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("List names of variables"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::DOTENV_FILENAME)
|
||||
.long("dotenv-filename")
|
||||
.action(ArgAction::Set)
|
||||
.help("Search for environment file named <DOTENV-FILENAME> instead of `.env`")
|
||||
.conflicts_with(arg::DOTENV_PATH),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::DOTENV_PATH)
|
||||
.short('E')
|
||||
.long("dotenv-path")
|
||||
.action(ArgAction::Set)
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.help("Load <DOTENV-PATH> as environment file instead of searching for one")
|
||||
)
|
||||
.group(ArgGroup::new("SUBCOMMAND").args(cmd::ALL))
|
||||
.arg(
|
||||
Arg::new(arg::ARGUMENTS)
|
||||
@ -481,30 +529,6 @@ impl Config {
|
||||
.action(ArgAction::Append)
|
||||
.help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::GLOBAL_JUSTFILE)
|
||||
.action(ArgAction::SetTrue)
|
||||
.long("global-justfile")
|
||||
.short('g')
|
||||
.conflicts_with(arg::JUSTFILE)
|
||||
.conflicts_with(arg::WORKING_DIRECTORY)
|
||||
.help("Use global justfile")
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::TIMESTAMP)
|
||||
.action(ArgAction::SetTrue)
|
||||
.long("timestamp")
|
||||
.env("JUST_TIMESTAMP")
|
||||
.help("Print recipe command timestamps")
|
||||
)
|
||||
.arg(
|
||||
Arg::new(arg::TIMESTAMP_FORMAT)
|
||||
.action(ArgAction::Set)
|
||||
.long("timestamp-format")
|
||||
.env("JUST_TIMESTAMP_FORMAT")
|
||||
.default_value("%H:%M:%S")
|
||||
.help("Timestamp format string")
|
||||
)
|
||||
}
|
||||
|
||||
fn color_from_matches(matches: &ArgMatches) -> ConfigResult<Color> {
|
||||
@ -611,17 +635,6 @@ impl Config {
|
||||
}
|
||||
|
||||
pub(crate) fn from_matches(matches: &ArgMatches) -> ConfigResult<Self> {
|
||||
let invocation_directory = env::current_dir().context(config_error::CurrentDirContext)?;
|
||||
|
||||
let verbosity = if matches.get_flag(arg::QUIET) {
|
||||
Verbosity::Quiet
|
||||
} else {
|
||||
Verbosity::from_flag_occurrences(matches.get_count(arg::VERBOSE))
|
||||
};
|
||||
|
||||
let color = Self::color_from_matches(matches)?;
|
||||
let command_color = Self::command_color_from_matches(matches)?;
|
||||
|
||||
let mut overrides = BTreeMap::new();
|
||||
if let Some(mut values) = matches.get_many::<String>(arg::SET) {
|
||||
while let (Some(k), Some(v)) = (values.next(), values.next()) {
|
||||
@ -684,28 +697,10 @@ impl Config {
|
||||
}
|
||||
} else if let Some(&shell) = matches.get_one::<completions::Shell>(cmd::COMPLETIONS) {
|
||||
Subcommand::Completions { shell }
|
||||
} else if matches.get_flag(cmd::EDIT) {
|
||||
Subcommand::Edit
|
||||
} else if matches.get_flag(cmd::SUMMARY) {
|
||||
Subcommand::Summary
|
||||
} else if matches.get_flag(cmd::DUMP) {
|
||||
Subcommand::Dump
|
||||
} else if matches.get_flag(cmd::FORMAT) {
|
||||
Subcommand::Format
|
||||
} else if matches.get_flag(cmd::INIT) {
|
||||
Subcommand::Init
|
||||
} else if let Some(path) = matches.get_many::<String>(cmd::LIST) {
|
||||
Subcommand::List {
|
||||
path: Self::parse_module_path(path)?,
|
||||
}
|
||||
} else if matches.get_flag(cmd::GROUPS) {
|
||||
Subcommand::Groups
|
||||
} else if matches.get_flag(cmd::MAN) {
|
||||
Subcommand::Man
|
||||
} else if let Some(path) = matches.get_many::<String>(cmd::SHOW) {
|
||||
Subcommand::Show {
|
||||
path: Self::parse_module_path(path)?,
|
||||
}
|
||||
} else if matches.get_flag(cmd::EDIT) {
|
||||
Subcommand::Edit
|
||||
} else if matches.get_flag(cmd::EVALUATE) {
|
||||
if positional.arguments.len() > 1 {
|
||||
return Err(ConfigError::SubcommandArguments {
|
||||
@ -722,6 +717,24 @@ impl Config {
|
||||
variable: positional.arguments.into_iter().next(),
|
||||
overrides,
|
||||
}
|
||||
} else if matches.get_flag(cmd::FORMAT) {
|
||||
Subcommand::Format
|
||||
} else if matches.get_flag(cmd::GROUPS) {
|
||||
Subcommand::Groups
|
||||
} else if matches.get_flag(cmd::INIT) {
|
||||
Subcommand::Init
|
||||
} else if let Some(path) = matches.get_many::<String>(cmd::LIST) {
|
||||
Subcommand::List {
|
||||
path: Self::parse_module_path(path)?,
|
||||
}
|
||||
} else if matches.get_flag(cmd::MAN) {
|
||||
Subcommand::Man
|
||||
} else if let Some(path) = matches.get_many::<String>(cmd::SHOW) {
|
||||
Subcommand::Show {
|
||||
path: Self::parse_module_path(path)?,
|
||||
}
|
||||
} else if matches.get_flag(cmd::SUMMARY) {
|
||||
Subcommand::Summary
|
||||
} else if matches.get_flag(cmd::VARIABLES) {
|
||||
Subcommand::Variables
|
||||
} else {
|
||||
@ -731,20 +744,10 @@ impl Config {
|
||||
}
|
||||
};
|
||||
|
||||
let shell_args = if matches.get_flag(arg::CLEAR_SHELL_ARGS) {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
matches
|
||||
.get_many::<String>(arg::SHELL_ARG)
|
||||
.map(|s| s.map(Into::into).collect())
|
||||
};
|
||||
|
||||
let unstable = matches.get_flag(arg::UNSTABLE);
|
||||
|
||||
Ok(Self {
|
||||
check: matches.get_flag(arg::CHECK),
|
||||
color,
|
||||
command_color,
|
||||
color: Self::color_from_matches(matches)?,
|
||||
command_color: Self::command_color_from_matches(matches)?,
|
||||
dotenv_filename: matches
|
||||
.get_one::<String>(arg::DOTENV_FILENAME)
|
||||
.map(Into::into),
|
||||
@ -752,7 +755,7 @@ impl Config {
|
||||
dry_run: matches.get_flag(arg::DRY_RUN),
|
||||
dump_format: Self::dump_format_from_matches(matches)?,
|
||||
highlight: !matches.get_flag(arg::NO_HIGHLIGHT),
|
||||
invocation_directory,
|
||||
invocation_directory: env::current_dir().context(config_error::CurrentDirContext)?,
|
||||
list_heading: matches
|
||||
.get_one::<String>(arg::LIST_HEADING)
|
||||
.map_or_else(|| "Available recipes:\n".into(), Into::into),
|
||||
@ -765,7 +768,13 @@ impl Config {
|
||||
no_dependencies: matches.get_flag(arg::NO_DEPS),
|
||||
search_config,
|
||||
shell: matches.get_one::<String>(arg::SHELL).map(Into::into),
|
||||
shell_args,
|
||||
shell_args: if matches.get_flag(arg::CLEAR_SHELL_ARGS) {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
matches
|
||||
.get_many::<String>(arg::SHELL_ARG)
|
||||
.map(|s| s.map(Into::into).collect())
|
||||
},
|
||||
shell_command: matches.get_flag(arg::SHELL_COMMAND),
|
||||
subcommand,
|
||||
timestamp: matches.get_flag(arg::TIMESTAMP),
|
||||
@ -774,13 +783,17 @@ impl Config {
|
||||
.unwrap()
|
||||
.into(),
|
||||
unsorted: matches.get_flag(arg::UNSORTED),
|
||||
unstable,
|
||||
verbosity,
|
||||
unstable: matches.get_flag(arg::UNSTABLE),
|
||||
verbosity: if matches.get_flag(arg::QUIET) {
|
||||
Verbosity::Quiet
|
||||
} else {
|
||||
Verbosity::from_flag_occurrences(matches.get_count(arg::VERBOSE))
|
||||
},
|
||||
yes: matches.get_flag(arg::YES),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn require_unstable(&self, message: &str) -> Result<(), Error<'static>> {
|
||||
pub(crate) fn require_unstable(&self, message: &str) -> RunResult<'static> {
|
||||
if self.unstable {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -790,7 +803,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run(self, loader: &Loader) -> Result<(), Error> {
|
||||
pub(crate) fn run(self, loader: &Loader) -> RunResult {
|
||||
if let Err(error) = InterruptHandler::install(self.verbosity) {
|
||||
warn!("Failed to set CTRL-C handler: {error}");
|
||||
}
|
||||
|
141
src/function.rs
141
src/function.rs
@ -11,13 +11,13 @@ use {
|
||||
};
|
||||
|
||||
pub(crate) enum Function {
|
||||
Nullary(fn(Context) -> Result<String, String>),
|
||||
Unary(fn(Context, &str) -> Result<String, String>),
|
||||
UnaryOpt(fn(Context, &str, Option<&str>) -> Result<String, String>),
|
||||
UnaryPlus(fn(Context, &str, &[String]) -> Result<String, String>),
|
||||
Binary(fn(Context, &str, &str) -> Result<String, String>),
|
||||
BinaryPlus(fn(Context, &str, &str, &[String]) -> Result<String, String>),
|
||||
Ternary(fn(Context, &str, &str, &str) -> Result<String, String>),
|
||||
Nullary(fn(Context) -> FunctionResult),
|
||||
Unary(fn(Context, &str) -> FunctionResult),
|
||||
UnaryOpt(fn(Context, &str, Option<&str>) -> FunctionResult),
|
||||
UnaryPlus(fn(Context, &str, &[String]) -> FunctionResult),
|
||||
Binary(fn(Context, &str, &str) -> FunctionResult),
|
||||
BinaryPlus(fn(Context, &str, &str, &[String]) -> FunctionResult),
|
||||
Ternary(fn(Context, &str, &str, &str) -> FunctionResult),
|
||||
}
|
||||
|
||||
pub(crate) struct Context<'src: 'run, 'run> {
|
||||
@ -119,7 +119,7 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
fn absolute_path(context: Context, path: &str) -> Result<String, String> {
|
||||
fn absolute_path(context: Context, path: &str) -> FunctionResult {
|
||||
let abs_path_unchecked = context
|
||||
.evaluator
|
||||
.context
|
||||
@ -136,7 +136,7 @@ fn absolute_path(context: Context, path: &str) -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn append(_context: Context, suffix: &str, s: &str) -> Result<String, String> {
|
||||
fn append(_context: Context, suffix: &str, s: &str) -> FunctionResult {
|
||||
Ok(
|
||||
s.split_whitespace()
|
||||
.map(|s| format!("{s}{suffix}"))
|
||||
@ -145,15 +145,15 @@ fn append(_context: Context, suffix: &str, s: &str) -> Result<String, String> {
|
||||
)
|
||||
}
|
||||
|
||||
fn arch(_context: Context) -> Result<String, String> {
|
||||
fn arch(_context: Context) -> FunctionResult {
|
||||
Ok(target::arch().to_owned())
|
||||
}
|
||||
|
||||
fn blake3(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn blake3(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(blake3::hash(s.as_bytes()).to_string())
|
||||
}
|
||||
|
||||
fn blake3_file(context: Context, path: &str) -> Result<String, String> {
|
||||
fn blake3_file(context: Context, path: &str) -> FunctionResult {
|
||||
let path = context
|
||||
.evaluator
|
||||
.context
|
||||
@ -167,7 +167,7 @@ fn blake3_file(context: Context, path: &str) -> Result<String, String> {
|
||||
Ok(hasher.finalize().to_string())
|
||||
}
|
||||
|
||||
fn canonicalize(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn canonicalize(_context: Context, path: &str) -> FunctionResult {
|
||||
let canonical =
|
||||
std::fs::canonicalize(path).map_err(|err| format!("I/O error canonicalizing path: {err}"))?;
|
||||
|
||||
@ -179,7 +179,7 @@ fn canonicalize(_context: Context, path: &str) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn capitalize(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn capitalize(_context: Context, s: &str) -> FunctionResult {
|
||||
let mut capitalized = String::new();
|
||||
for (i, c) in s.chars().enumerate() {
|
||||
if i == 0 {
|
||||
@ -191,7 +191,7 @@ fn capitalize(_context: Context, s: &str) -> Result<String, String> {
|
||||
Ok(capitalized)
|
||||
}
|
||||
|
||||
fn choose(_context: Context, n: &str, alphabet: &str) -> Result<String, String> {
|
||||
fn choose(_context: Context, n: &str, alphabet: &str) -> FunctionResult {
|
||||
if alphabet.is_empty() {
|
||||
return Err("empty alphabet".into());
|
||||
}
|
||||
@ -215,11 +215,11 @@ fn choose(_context: Context, n: &str, alphabet: &str) -> Result<String, String>
|
||||
Ok((0..n).map(|_| alphabet.choose(&mut rng).unwrap()).collect())
|
||||
}
|
||||
|
||||
fn clean(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn clean(_context: Context, path: &str) -> FunctionResult {
|
||||
Ok(Path::new(path).lexiclean().to_str().unwrap().to_owned())
|
||||
}
|
||||
|
||||
fn dir(name: &'static str, f: fn() -> Option<PathBuf>) -> Result<String, String> {
|
||||
fn dir(name: &'static str, f: fn() -> Option<PathBuf>) -> FunctionResult {
|
||||
match f() {
|
||||
Some(path) => path
|
||||
.as_os_str()
|
||||
@ -235,7 +235,7 @@ fn dir(name: &'static str, f: fn() -> Option<PathBuf>) -> Result<String, String>
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_uri_component(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn encode_uri_component(_context: Context, s: &str) -> FunctionResult {
|
||||
static PERCENT_ENCODE: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC
|
||||
.remove(b'-')
|
||||
.remove(b'_')
|
||||
@ -249,7 +249,7 @@ fn encode_uri_component(_context: Context, s: &str) -> Result<String, String> {
|
||||
Ok(percent_encoding::utf8_percent_encode(s, &PERCENT_ENCODE).to_string())
|
||||
}
|
||||
|
||||
fn env_var(context: Context, key: &str) -> Result<String, String> {
|
||||
fn env_var(context: Context, key: &str) -> FunctionResult {
|
||||
use std::env::VarError::*;
|
||||
|
||||
if let Some(value) = context.evaluator.context.dotenv.get(key) {
|
||||
@ -265,7 +265,7 @@ fn env_var(context: Context, key: &str) -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn env_var_or_default(context: Context, key: &str, default: &str) -> Result<String, String> {
|
||||
fn env_var_or_default(context: Context, key: &str, default: &str) -> FunctionResult {
|
||||
use std::env::VarError::*;
|
||||
|
||||
if let Some(value) = context.evaluator.context.dotenv.get(key) {
|
||||
@ -281,39 +281,39 @@ fn env_var_or_default(context: Context, key: &str, default: &str) -> Result<Stri
|
||||
}
|
||||
}
|
||||
|
||||
fn env(context: Context, key: &str, default: Option<&str>) -> Result<String, String> {
|
||||
fn env(context: Context, key: &str, default: Option<&str>) -> FunctionResult {
|
||||
match default {
|
||||
Some(val) => env_var_or_default(context, key, val),
|
||||
None => env_var(context, key),
|
||||
}
|
||||
}
|
||||
|
||||
fn error(_context: Context, message: &str) -> Result<String, String> {
|
||||
fn error(_context: Context, message: &str) -> FunctionResult {
|
||||
Err(message.to_owned())
|
||||
}
|
||||
|
||||
fn extension(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn extension(_context: Context, path: &str) -> FunctionResult {
|
||||
Utf8Path::new(path)
|
||||
.extension()
|
||||
.map(str::to_owned)
|
||||
.ok_or_else(|| format!("Could not extract extension from `{path}`"))
|
||||
}
|
||||
|
||||
fn file_name(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn file_name(_context: Context, path: &str) -> FunctionResult {
|
||||
Utf8Path::new(path)
|
||||
.file_name()
|
||||
.map(str::to_owned)
|
||||
.ok_or_else(|| format!("Could not extract file name from `{path}`"))
|
||||
}
|
||||
|
||||
fn file_stem(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn file_stem(_context: Context, path: &str) -> FunctionResult {
|
||||
Utf8Path::new(path)
|
||||
.file_stem()
|
||||
.map(str::to_owned)
|
||||
.ok_or_else(|| format!("Could not extract file stem from `{path}`"))
|
||||
}
|
||||
|
||||
fn invocation_directory(context: Context) -> Result<String, String> {
|
||||
fn invocation_directory(context: Context) -> FunctionResult {
|
||||
Platform::convert_native_path(
|
||||
&context.evaluator.context.search.working_directory,
|
||||
&context.evaluator.context.config.invocation_directory,
|
||||
@ -321,7 +321,7 @@ fn invocation_directory(context: Context) -> Result<String, String> {
|
||||
.map_err(|e| format!("Error getting shell path: {e}"))
|
||||
}
|
||||
|
||||
fn invocation_directory_native(context: Context) -> Result<String, String> {
|
||||
fn invocation_directory_native(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -342,11 +342,11 @@ fn invocation_directory_native(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn is_dependency(context: Context) -> Result<String, String> {
|
||||
fn is_dependency(context: Context) -> FunctionResult {
|
||||
Ok(context.evaluator.is_dependency.to_string())
|
||||
}
|
||||
|
||||
fn prepend(_context: Context, prefix: &str, s: &str) -> Result<String, String> {
|
||||
fn prepend(_context: Context, prefix: &str, s: &str) -> FunctionResult {
|
||||
Ok(
|
||||
s.split_whitespace()
|
||||
.map(|s| format!("{prefix}{s}"))
|
||||
@ -355,7 +355,7 @@ fn prepend(_context: Context, prefix: &str, s: &str) -> Result<String, String> {
|
||||
)
|
||||
}
|
||||
|
||||
fn join(_context: Context, base: &str, with: &str, and: &[String]) -> Result<String, String> {
|
||||
fn join(_context: Context, base: &str, with: &str, and: &[String]) -> FunctionResult {
|
||||
let mut result = Utf8Path::new(base).join(with);
|
||||
for arg in and {
|
||||
result.push(arg);
|
||||
@ -363,7 +363,7 @@ fn join(_context: Context, base: &str, with: &str, and: &[String]) -> Result<Str
|
||||
Ok(result.to_string())
|
||||
}
|
||||
|
||||
fn just_executable(_context: Context) -> Result<String, String> {
|
||||
fn just_executable(_context: Context) -> FunctionResult {
|
||||
let exe_path =
|
||||
env::current_exe().map_err(|e| format!("Error getting current executable: {e}"))?;
|
||||
|
||||
@ -375,11 +375,11 @@ fn just_executable(_context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn just_pid(_context: Context) -> Result<String, String> {
|
||||
fn just_pid(_context: Context) -> FunctionResult {
|
||||
Ok(std::process::id().to_string())
|
||||
}
|
||||
|
||||
fn justfile(context: Context) -> Result<String, String> {
|
||||
fn justfile(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -395,7 +395,7 @@ fn justfile(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn justfile_directory(context: Context) -> Result<String, String> {
|
||||
fn justfile_directory(context: Context) -> FunctionResult {
|
||||
let justfile_directory = context
|
||||
.evaluator
|
||||
.context
|
||||
@ -420,19 +420,19 @@ fn justfile_directory(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn kebabcase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn kebabcase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_kebab_case())
|
||||
}
|
||||
|
||||
fn lowercamelcase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn lowercamelcase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_lower_camel_case())
|
||||
}
|
||||
|
||||
fn lowercase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn lowercase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_lowercase())
|
||||
}
|
||||
|
||||
fn module_directory(context: Context) -> Result<String, String> {
|
||||
fn module_directory(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -459,7 +459,7 @@ fn module_directory(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn module_file(context: Context) -> Result<String, String> {
|
||||
fn module_file(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -478,27 +478,27 @@ fn module_file(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn num_cpus(_context: Context) -> Result<String, String> {
|
||||
fn num_cpus(_context: Context) -> FunctionResult {
|
||||
let num = num_cpus::get();
|
||||
Ok(num.to_string())
|
||||
}
|
||||
|
||||
fn os(_context: Context) -> Result<String, String> {
|
||||
fn os(_context: Context) -> FunctionResult {
|
||||
Ok(target::os().to_owned())
|
||||
}
|
||||
|
||||
fn os_family(_context: Context) -> Result<String, String> {
|
||||
fn os_family(_context: Context) -> FunctionResult {
|
||||
Ok(target::family().to_owned())
|
||||
}
|
||||
|
||||
fn parent_directory(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn parent_directory(_context: Context, path: &str) -> FunctionResult {
|
||||
Utf8Path::new(path)
|
||||
.parent()
|
||||
.map(Utf8Path::to_string)
|
||||
.ok_or_else(|| format!("Could not extract parent directory from `{path}`"))
|
||||
}
|
||||
|
||||
fn path_exists(context: Context, path: &str) -> Result<String, String> {
|
||||
fn path_exists(context: Context, path: &str) -> FunctionResult {
|
||||
Ok(
|
||||
context
|
||||
.evaluator
|
||||
@ -511,20 +511,15 @@ fn path_exists(context: Context, path: &str) -> Result<String, String> {
|
||||
)
|
||||
}
|
||||
|
||||
fn quote(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn quote(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(format!("'{}'", s.replace('\'', "'\\''")))
|
||||
}
|
||||
|
||||
fn replace(_context: Context, s: &str, from: &str, to: &str) -> Result<String, String> {
|
||||
fn replace(_context: Context, s: &str, from: &str, to: &str) -> FunctionResult {
|
||||
Ok(s.replace(from, to))
|
||||
}
|
||||
|
||||
fn replace_regex(
|
||||
_context: Context,
|
||||
s: &str,
|
||||
regex: &str,
|
||||
replacement: &str,
|
||||
) -> Result<String, String> {
|
||||
fn replace_regex(_context: Context, s: &str, regex: &str, replacement: &str) -> FunctionResult {
|
||||
Ok(
|
||||
Regex::new(regex)
|
||||
.map_err(|err| err.to_string())?
|
||||
@ -533,7 +528,7 @@ fn replace_regex(
|
||||
)
|
||||
}
|
||||
|
||||
fn sha256(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn sha256(_context: Context, s: &str) -> FunctionResult {
|
||||
use sha2::{Digest, Sha256};
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(s);
|
||||
@ -541,7 +536,7 @@ fn sha256(_context: Context, s: &str) -> Result<String, String> {
|
||||
Ok(format!("{hash:x}"))
|
||||
}
|
||||
|
||||
fn sha256_file(context: Context, path: &str) -> Result<String, String> {
|
||||
fn sha256_file(context: Context, path: &str) -> FunctionResult {
|
||||
use sha2::{Digest, Sha256};
|
||||
let path = context
|
||||
.evaluator
|
||||
@ -558,7 +553,7 @@ fn sha256_file(context: Context, path: &str) -> Result<String, String> {
|
||||
Ok(format!("{hash:x}"))
|
||||
}
|
||||
|
||||
fn shell(context: Context, command: &str, args: &[String]) -> Result<String, String> {
|
||||
fn shell(context: Context, command: &str, args: &[String]) -> FunctionResult {
|
||||
let args = iter::once(command)
|
||||
.chain(args.iter().map(String::as_str))
|
||||
.collect::<Vec<&str>>();
|
||||
@ -569,19 +564,19 @@ fn shell(context: Context, command: &str, args: &[String]) -> Result<String, Str
|
||||
.map_err(|output_error| output_error.to_string())
|
||||
}
|
||||
|
||||
fn shoutykebabcase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn shoutykebabcase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_shouty_kebab_case())
|
||||
}
|
||||
|
||||
fn shoutysnakecase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn shoutysnakecase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_shouty_snake_case())
|
||||
}
|
||||
|
||||
fn snakecase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn snakecase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_snake_case())
|
||||
}
|
||||
|
||||
fn source_directory(context: Context) -> Result<String, String> {
|
||||
fn source_directory(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -602,7 +597,7 @@ fn source_directory(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn source_file(context: Context) -> Result<String, String> {
|
||||
fn source_file(context: Context) -> FunctionResult {
|
||||
context
|
||||
.evaluator
|
||||
.context
|
||||
@ -621,51 +616,51 @@ fn source_file(context: Context) -> Result<String, String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn titlecase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn titlecase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_title_case())
|
||||
}
|
||||
|
||||
fn trim(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn trim(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.trim().to_owned())
|
||||
}
|
||||
|
||||
fn trim_end(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn trim_end(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.trim_end().to_owned())
|
||||
}
|
||||
|
||||
fn trim_end_match(_context: Context, s: &str, pat: &str) -> Result<String, String> {
|
||||
fn trim_end_match(_context: Context, s: &str, pat: &str) -> FunctionResult {
|
||||
Ok(s.strip_suffix(pat).unwrap_or(s).to_owned())
|
||||
}
|
||||
|
||||
fn trim_end_matches(_context: Context, s: &str, pat: &str) -> Result<String, String> {
|
||||
fn trim_end_matches(_context: Context, s: &str, pat: &str) -> FunctionResult {
|
||||
Ok(s.trim_end_matches(pat).to_owned())
|
||||
}
|
||||
|
||||
fn trim_start(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn trim_start(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.trim_start().to_owned())
|
||||
}
|
||||
|
||||
fn trim_start_match(_context: Context, s: &str, pat: &str) -> Result<String, String> {
|
||||
fn trim_start_match(_context: Context, s: &str, pat: &str) -> FunctionResult {
|
||||
Ok(s.strip_prefix(pat).unwrap_or(s).to_owned())
|
||||
}
|
||||
|
||||
fn trim_start_matches(_context: Context, s: &str, pat: &str) -> Result<String, String> {
|
||||
fn trim_start_matches(_context: Context, s: &str, pat: &str) -> FunctionResult {
|
||||
Ok(s.trim_start_matches(pat).to_owned())
|
||||
}
|
||||
|
||||
fn uppercamelcase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn uppercamelcase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_upper_camel_case())
|
||||
}
|
||||
|
||||
fn uppercase(_context: Context, s: &str) -> Result<String, String> {
|
||||
fn uppercase(_context: Context, s: &str) -> FunctionResult {
|
||||
Ok(s.to_uppercase())
|
||||
}
|
||||
|
||||
fn uuid(_context: Context) -> Result<String, String> {
|
||||
fn uuid(_context: Context) -> FunctionResult {
|
||||
Ok(uuid::Uuid::new_v4().to_string())
|
||||
}
|
||||
|
||||
fn without_extension(_context: Context, path: &str) -> Result<String, String> {
|
||||
fn without_extension(_context: Context, path: &str) -> FunctionResult {
|
||||
let parent = Utf8Path::new(path)
|
||||
.parent()
|
||||
.ok_or_else(|| format!("Could not extract parent from `{path}`"))?;
|
||||
@ -679,7 +674,7 @@ fn without_extension(_context: Context, path: &str) -> Result<String, String> {
|
||||
|
||||
/// Check whether a string processes properly as semver (e.x. "0.1.0")
|
||||
/// and matches a given semver requirement (e.x. ">=0.1.0")
|
||||
fn semver_matches(_context: Context, version: &str, requirement: &str) -> Result<String, String> {
|
||||
fn semver_matches(_context: Context, version: &str, requirement: &str) -> FunctionResult {
|
||||
Ok(
|
||||
requirement
|
||||
.parse::<VersionReq>()
|
||||
|
@ -86,10 +86,11 @@ pub use crate::run::run;
|
||||
#[doc(hidden)]
|
||||
pub use unindent::unindent;
|
||||
|
||||
pub(crate) type CompileResult<'a, T = ()> = Result<T, CompileError<'a>>;
|
||||
pub(crate) type ConfigResult<T> = Result<T, ConfigError>;
|
||||
pub(crate) type RunResult<'a, T = ()> = Result<T, Error<'a>>;
|
||||
pub(crate) type SearchResult<T> = Result<T, SearchError>;
|
||||
type CompileResult<'a, T = ()> = Result<T, CompileError<'a>>;
|
||||
type ConfigResult<T> = Result<T, ConfigError>;
|
||||
type FunctionResult = Result<String, String>;
|
||||
type RunResult<'a, T = ()> = Result<T, Error<'a>>;
|
||||
type SearchResult<T> = Result<T, SearchError>;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
|
@ -19,7 +19,7 @@ impl PlatformInterface for Platform {
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
fn set_execute_permission(path: &Path) -> Result<(), io::Error> {
|
||||
fn set_execute_permission(path: &Path) -> io::Result<()> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
// get current permissions
|
||||
@ -38,7 +38,7 @@ impl PlatformInterface for Platform {
|
||||
exit_status.signal()
|
||||
}
|
||||
|
||||
fn convert_native_path(_working_directory: &Path, path: &Path) -> Result<String, String> {
|
||||
fn convert_native_path(_working_directory: &Path, path: &Path) -> FunctionResult {
|
||||
path
|
||||
.to_str()
|
||||
.map(str::to_string)
|
||||
@ -85,7 +85,7 @@ impl PlatformInterface for Platform {
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
fn set_execute_permission(_path: &Path) -> Result<(), io::Error> {
|
||||
fn set_execute_permission(_path: &Path) -> io::Result<()> {
|
||||
// it is not necessary to set an execute permission on a script on windows, so
|
||||
// this is a nop
|
||||
Ok(())
|
||||
@ -97,7 +97,7 @@ impl PlatformInterface for Platform {
|
||||
None
|
||||
}
|
||||
|
||||
fn convert_native_path(working_directory: &Path, path: &Path) -> Result<String, String> {
|
||||
fn convert_native_path(working_directory: &Path, path: &Path) -> FunctionResult {
|
||||
// Translate path from windows style to unix style
|
||||
let mut cygpath = Command::new("cygpath");
|
||||
cygpath.current_dir(working_directory);
|
||||
|
@ -10,12 +10,12 @@ pub(crate) trait PlatformInterface {
|
||||
) -> Result<Command, OutputError>;
|
||||
|
||||
/// Set the execute permission on the file pointed to by `path`
|
||||
fn set_execute_permission(path: &Path) -> Result<(), io::Error>;
|
||||
fn set_execute_permission(path: &Path) -> io::Result<()>;
|
||||
|
||||
/// Extract the signal from a process exit status, if it was terminated by a
|
||||
/// signal
|
||||
fn signal_from_exit_status(exit_status: ExitStatus) -> Option<i32>;
|
||||
|
||||
/// Translate a path from a "native" path to a path the interpreter expects
|
||||
fn convert_native_path(working_directory: &Path, path: &Path) -> Result<String, String>;
|
||||
fn convert_native_path(working_directory: &Path, path: &Path) -> FunctionResult;
|
||||
}
|
||||
|
@ -42,11 +42,7 @@ pub(crate) enum Subcommand {
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
pub(crate) fn execute<'src>(
|
||||
&self,
|
||||
config: &Config,
|
||||
loader: &'src Loader,
|
||||
) -> Result<(), Error<'src>> {
|
||||
pub(crate) fn execute<'src>(&self, config: &Config, loader: &'src Loader) -> RunResult<'src> {
|
||||
use Subcommand::*;
|
||||
|
||||
match self {
|
||||
@ -107,7 +103,7 @@ impl Subcommand {
|
||||
loader: &'src Loader,
|
||||
arguments: &[String],
|
||||
overrides: &BTreeMap<String, String>,
|
||||
) -> Result<(), Error<'src>> {
|
||||
) -> RunResult<'src> {
|
||||
if matches!(
|
||||
config.search_config,
|
||||
SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. }
|
||||
@ -192,7 +188,7 @@ impl Subcommand {
|
||||
config: &Config,
|
||||
loader: &'src Loader,
|
||||
search: &Search,
|
||||
) -> Result<Compilation<'src>, Error<'src>> {
|
||||
) -> RunResult<'src, Compilation<'src>> {
|
||||
let compilation = Compiler::compile(config.unstable, loader, &search.justfile)?;
|
||||
|
||||
if config.verbosity.loud() {
|
||||
@ -214,7 +210,7 @@ impl Subcommand {
|
||||
search: &Search,
|
||||
overrides: &BTreeMap<String, String>,
|
||||
chooser: Option<&str>,
|
||||
) -> Result<(), Error<'src>> {
|
||||
) -> RunResult<'src> {
|
||||
let mut recipes = Vec::<&Recipe>::new();
|
||||
let mut stack = vec![justfile];
|
||||
while let Some(module) = stack.pop() {
|
||||
@ -304,7 +300,7 @@ impl Subcommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dump(config: &Config, ast: &Ast, justfile: &Justfile) -> Result<(), Error<'static>> {
|
||||
fn dump(config: &Config, ast: &Ast, justfile: &Justfile) -> RunResult<'static> {
|
||||
match config.dump_format {
|
||||
DumpFormat::Json => {
|
||||
serde_json::to_writer(io::stdout(), justfile)
|
||||
@ -316,7 +312,7 @@ impl Subcommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn edit(search: &Search) -> Result<(), Error<'static>> {
|
||||
fn edit(search: &Search) -> RunResult<'static> {
|
||||
let editor = env::var_os("VISUAL")
|
||||
.or_else(|| env::var_os("EDITOR"))
|
||||
.unwrap_or_else(|| "vim".into());
|
||||
@ -338,7 +334,7 @@ impl Subcommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format(config: &Config, search: &Search, src: &str, ast: &Ast) -> Result<(), Error<'static>> {
|
||||
fn format(config: &Config, search: &Search, src: &str, ast: &Ast) -> RunResult<'static> {
|
||||
config.require_unstable("The `--fmt` command is currently unstable.")?;
|
||||
|
||||
let formatted = ast.to_string();
|
||||
@ -383,7 +379,7 @@ impl Subcommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init(config: &Config) -> Result<(), Error<'static>> {
|
||||
fn init(config: &Config) -> RunResult<'static> {
|
||||
let search = Search::init(&config.search_config, &config.invocation_directory)?;
|
||||
|
||||
if search.justfile.is_file() {
|
||||
@ -403,7 +399,7 @@ impl Subcommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn man() -> Result<(), Error<'static>> {
|
||||
fn man() -> RunResult<'static> {
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
|
||||
Man::new(Config::app())
|
||||
@ -423,7 +419,7 @@ impl Subcommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list(config: &Config, mut module: &Justfile, path: &ModulePath) -> Result<(), Error<'static>> {
|
||||
fn list(config: &Config, mut module: &Justfile, path: &ModulePath) -> RunResult<'static> {
|
||||
for name in &path.path {
|
||||
module = module
|
||||
.modules
|
||||
@ -585,7 +581,7 @@ impl Subcommand {
|
||||
config: &Config,
|
||||
mut module: &Justfile<'src>,
|
||||
path: &ModulePath,
|
||||
) -> Result<(), Error<'src>> {
|
||||
) -> RunResult<'src> {
|
||||
for name in &path.path[0..path.path.len() - 1] {
|
||||
module = module
|
||||
.modules
|
||||
|
@ -25,7 +25,7 @@ mod full {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn summary(path: &Path) -> Result<Result<Summary, String>, io::Error> {
|
||||
pub fn summary(path: &Path) -> io::Result<Result<Summary, String>> {
|
||||
let loader = Loader::new();
|
||||
|
||||
match Compiler::compile(false, &loader, path) {
|
||||
|
14
src/thunk.rs
14
src/thunk.rs
@ -6,42 +6,42 @@ pub(crate) enum Thunk<'src> {
|
||||
Nullary {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context) -> Result<String, String>,
|
||||
function: fn(function::Context) -> FunctionResult,
|
||||
},
|
||||
Unary {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str) -> Result<String, String>,
|
||||
function: fn(function::Context, &str) -> FunctionResult,
|
||||
arg: Box<Expression<'src>>,
|
||||
},
|
||||
UnaryOpt {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str, Option<&str>) -> Result<String, String>,
|
||||
function: fn(function::Context, &str, Option<&str>) -> FunctionResult,
|
||||
args: (Box<Expression<'src>>, Box<Option<Expression<'src>>>),
|
||||
},
|
||||
UnaryPlus {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str, &[String]) -> Result<String, String>,
|
||||
function: fn(function::Context, &str, &[String]) -> FunctionResult,
|
||||
args: (Box<Expression<'src>>, Vec<Expression<'src>>),
|
||||
},
|
||||
Binary {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str, &str) -> Result<String, String>,
|
||||
function: fn(function::Context, &str, &str) -> FunctionResult,
|
||||
args: [Box<Expression<'src>>; 2],
|
||||
},
|
||||
BinaryPlus {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str, &str, &[String]) -> Result<String, String>,
|
||||
function: fn(function::Context, &str, &str, &[String]) -> FunctionResult,
|
||||
args: ([Box<Expression<'src>>; 2], Vec<Expression<'src>>),
|
||||
},
|
||||
Ternary {
|
||||
name: Name<'src>,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
function: fn(function::Context, &str, &str, &str) -> Result<String, String>,
|
||||
function: fn(function::Context, &str, &str, &str) -> FunctionResult,
|
||||
args: [Box<Expression<'src>>; 3],
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user