mirror of
https://github.com/casey/just.git
synced 2024-11-26 11:43:43 +03:00
Merge ab3fcc41cf
into 67034cb8b4
This commit is contained in:
commit
0b64afdbd6
@ -3,7 +3,7 @@ use super::*;
|
|||||||
/// An alias, e.g. `name := target`
|
/// An alias, e.g. `name := target`
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||||
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
|
pub(crate) struct Alias<'src, T = Rc<Recipe<'src>>> {
|
||||||
pub(crate) attributes: BTreeSet<Attribute<'src>>,
|
pub(crate) attributes: AttributeSet<'src>,
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
#[serde(
|
#[serde(
|
||||||
bound(serialize = "T: Keyed<'src>"),
|
bound(serialize = "T: Keyed<'src>"),
|
||||||
@ -26,7 +26,7 @@ impl<'src> Alias<'src, Name<'src>> {
|
|||||||
|
|
||||||
impl Alias<'_> {
|
impl Alias<'_> {
|
||||||
pub(crate) fn is_private(&self) -> bool {
|
pub(crate) fn is_private(&self) -> bool {
|
||||||
self.name.lexeme().starts_with('_') || self.attributes.contains(&Attribute::Private)
|
self.name.lexeme().starts_with('_') || self.attributes.contains(AttributeDiscriminant::Private)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,17 +72,21 @@ impl<'run, 'src> Analyzer<'run, 'src> {
|
|||||||
} => {
|
} => {
|
||||||
let mut doc_attr: Option<&str> = None;
|
let mut doc_attr: Option<&str> = None;
|
||||||
let mut groups = Vec::new();
|
let mut groups = Vec::new();
|
||||||
for attribute in attributes {
|
attributes.ensure_valid_attributes(
|
||||||
if let Attribute::Doc(ref doc) = attribute {
|
"Module",
|
||||||
doc_attr = Some(doc.as_ref().map(|s| s.cooked.as_ref()).unwrap_or_default());
|
**name,
|
||||||
} else if let Attribute::Group(ref group) = attribute {
|
&[AttributeDiscriminant::Doc, AttributeDiscriminant::Group],
|
||||||
groups.push(group.cooked.clone());
|
)?;
|
||||||
} else {
|
|
||||||
return Err(name.token.error(InvalidAttribute {
|
for attribute in attributes.iter() {
|
||||||
item_kind: "Module",
|
match attribute {
|
||||||
item_name: name.lexeme(),
|
Attribute::Doc(ref doc) => {
|
||||||
attribute: attribute.clone(),
|
doc_attr = Some(doc.as_ref().map(|s| s.cooked.as_ref()).unwrap_or_default());
|
||||||
}));
|
}
|
||||||
|
Attribute::Group(ref group) => {
|
||||||
|
groups.push(group.cooked.clone());
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,11 +174,9 @@ impl<'run, 'src> Analyzer<'run, 'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for recipe in recipes.values() {
|
for recipe in recipes.values() {
|
||||||
for attribute in &recipe.attributes {
|
if recipe.attributes.contains(AttributeDiscriminant::Script) {
|
||||||
if let Attribute::Script(_) = attribute {
|
unstable_features.insert(UnstableFeature::ScriptAttribute);
|
||||||
unstable_features.insert(UnstableFeature::ScriptAttribute);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,11 +286,7 @@ impl<'run, 'src> Analyzer<'run, 'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !recipe.is_script() {
|
if !recipe.is_script() {
|
||||||
if let Some(attribute) = recipe
|
if let Some(attribute) = recipe.attributes.get(AttributeDiscriminant::Extension) {
|
||||||
.attributes
|
|
||||||
.iter()
|
|
||||||
.find(|attribute| matches!(attribute, Attribute::Extension(_)))
|
|
||||||
{
|
|
||||||
return Err(recipe.name.error(InvalidAttribute {
|
return Err(recipe.name.error(InvalidAttribute {
|
||||||
item_kind: "Recipe",
|
item_kind: "Recipe",
|
||||||
item_name: recipe.name.lexeme(),
|
item_name: recipe.name.lexeme(),
|
||||||
@ -301,16 +299,11 @@ impl<'run, 'src> Analyzer<'run, 'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn analyze_alias(alias: &Alias<'src, Name<'src>>) -> CompileResult<'src> {
|
fn analyze_alias(alias: &Alias<'src, Name<'src>>) -> CompileResult<'src> {
|
||||||
for attribute in &alias.attributes {
|
alias.attributes.ensure_valid_attributes(
|
||||||
if *attribute != Attribute::Private {
|
"Alias",
|
||||||
return Err(alias.name.token.error(InvalidAttribute {
|
*alias.name,
|
||||||
item_kind: "Alias",
|
&[AttributeDiscriminant::Private],
|
||||||
item_name: alias.name.lexeme(),
|
)?;
|
||||||
attribute: attribute.clone(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::{self};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -96,6 +98,10 @@ impl<'src> Attribute<'src> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn discriminant(&self) -> AttributeDiscriminant {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn name(&self) -> &'static str {
|
pub(crate) fn name(&self) -> &'static str {
|
||||||
self.into()
|
self.into()
|
||||||
}
|
}
|
||||||
@ -129,6 +135,63 @@ impl<'src> Display for Attribute<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize)]
|
||||||
|
pub(crate) struct AttributeSet<'src>(BTreeSet<Attribute<'src>>);
|
||||||
|
|
||||||
|
impl<'src, 'a> IntoIterator for &'a AttributeSet<'src> {
|
||||||
|
type Item = &'a Attribute<'src>;
|
||||||
|
|
||||||
|
type IntoIter = collections::btree_set::Iter<'a, Attribute<'src>>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'src> AttributeSet<'src> {
|
||||||
|
pub(crate) fn from_iter(iter: impl IntoIterator<Item = Attribute<'src>>) -> Self {
|
||||||
|
Self(iter.into_iter().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn contains(&self, target: AttributeDiscriminant) -> bool {
|
||||||
|
self.0.iter().any(|attr| attr.discriminant() == target)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get(&self, discriminant: AttributeDiscriminant) -> Option<&Attribute<'src>> {
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.find(|attr| discriminant == attr.discriminant())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iter(&self) -> impl Iterator<Item = &Attribute<'src>> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ensure_valid_attributes(
|
||||||
|
&self,
|
||||||
|
item_kind: &'static str,
|
||||||
|
item_token: Token<'src>,
|
||||||
|
valid: &[AttributeDiscriminant],
|
||||||
|
) -> Result<(), CompileError<'src>> {
|
||||||
|
for attribute in &self.0 {
|
||||||
|
let discriminant = attribute.discriminant();
|
||||||
|
if !valid.contains(&discriminant) {
|
||||||
|
return Err(item_token.error(CompileErrorKind::InvalidAttribute {
|
||||||
|
item_kind,
|
||||||
|
item_name: item_token.lexeme(),
|
||||||
|
attribute: attribute.clone(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) enum Item<'src> {
|
|||||||
relative: StringLiteral<'src>,
|
relative: StringLiteral<'src>,
|
||||||
},
|
},
|
||||||
Module {
|
Module {
|
||||||
attributes: BTreeSet<Attribute<'src>>,
|
attributes: AttributeSet<'src>,
|
||||||
absolute: Option<PathBuf>,
|
absolute: Option<PathBuf>,
|
||||||
doc: Option<&'src str>,
|
doc: Option<&'src str>,
|
||||||
name: Name<'src>,
|
name: Name<'src>,
|
||||||
|
114
src/lib.rs
114
src/lib.rs
@ -6,31 +6,95 @@
|
|||||||
|
|
||||||
pub(crate) use {
|
pub(crate) use {
|
||||||
crate::{
|
crate::{
|
||||||
alias::Alias, analyzer::Analyzer, argument_parser::ArgumentParser, assignment::Assignment,
|
alias::Alias,
|
||||||
assignment_resolver::AssignmentResolver, ast::Ast, attribute::Attribute, binding::Binding,
|
analyzer::Analyzer,
|
||||||
color::Color, color_display::ColorDisplay, command_color::CommandColor,
|
argument_parser::ArgumentParser,
|
||||||
command_ext::CommandExt, compilation::Compilation, compile_error::CompileError,
|
assignment::Assignment,
|
||||||
compile_error_kind::CompileErrorKind, compiler::Compiler, condition::Condition,
|
assignment_resolver::AssignmentResolver,
|
||||||
conditional_operator::ConditionalOperator, config::Config, config_error::ConfigError,
|
ast::Ast,
|
||||||
constants::constants, count::Count, delimiter::Delimiter, dependency::Dependency,
|
attribute::{Attribute, AttributeDiscriminant, AttributeSet},
|
||||||
dump_format::DumpFormat, enclosure::Enclosure, error::Error, evaluator::Evaluator,
|
binding::Binding,
|
||||||
execution_context::ExecutionContext, executor::Executor, expression::Expression,
|
color::Color,
|
||||||
fragment::Fragment, function::Function, interpreter::Interpreter,
|
color_display::ColorDisplay,
|
||||||
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
|
command_color::CommandColor,
|
||||||
justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List,
|
command_ext::CommandExt,
|
||||||
load_dotenv::load_dotenv, loader::Loader, module_path::ModulePath, name::Name,
|
compilation::Compilation,
|
||||||
namepath::Namepath, ordinal::Ordinal, output::output, output_error::OutputError,
|
compile_error::CompileError,
|
||||||
parameter::Parameter, parameter_kind::ParameterKind, parser::Parser, platform::Platform,
|
compile_error_kind::CompileErrorKind,
|
||||||
platform_interface::PlatformInterface, position::Position, positional::Positional, ran::Ran,
|
compiler::Compiler,
|
||||||
range_ext::RangeExt, recipe::Recipe, recipe_resolver::RecipeResolver,
|
condition::Condition,
|
||||||
recipe_signature::RecipeSignature, scope::Scope, search::Search, search_config::SearchConfig,
|
conditional_operator::ConditionalOperator,
|
||||||
search_error::SearchError, set::Set, setting::Setting, settings::Settings, shebang::Shebang,
|
config::Config,
|
||||||
show_whitespace::ShowWhitespace, source::Source, string_delimiter::StringDelimiter,
|
config_error::ConfigError,
|
||||||
string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand,
|
constants::constants,
|
||||||
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind,
|
count::Count,
|
||||||
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe,
|
delimiter::Delimiter,
|
||||||
unstable_feature::UnstableFeature, use_color::UseColor, variables::Variables,
|
dependency::Dependency,
|
||||||
verbosity::Verbosity, warning::Warning,
|
dump_format::DumpFormat,
|
||||||
|
enclosure::Enclosure,
|
||||||
|
error::Error,
|
||||||
|
evaluator::Evaluator,
|
||||||
|
execution_context::ExecutionContext,
|
||||||
|
executor::Executor,
|
||||||
|
expression::Expression,
|
||||||
|
fragment::Fragment,
|
||||||
|
function::Function,
|
||||||
|
interpreter::Interpreter,
|
||||||
|
interrupt_guard::InterruptGuard,
|
||||||
|
interrupt_handler::InterruptHandler,
|
||||||
|
item::Item,
|
||||||
|
justfile::Justfile,
|
||||||
|
keyed::Keyed,
|
||||||
|
keyword::Keyword,
|
||||||
|
lexer::Lexer,
|
||||||
|
line::Line,
|
||||||
|
list::List,
|
||||||
|
load_dotenv::load_dotenv,
|
||||||
|
loader::Loader,
|
||||||
|
module_path::ModulePath,
|
||||||
|
name::Name,
|
||||||
|
namepath::Namepath,
|
||||||
|
ordinal::Ordinal,
|
||||||
|
output::output,
|
||||||
|
output_error::OutputError,
|
||||||
|
parameter::Parameter,
|
||||||
|
parameter_kind::ParameterKind,
|
||||||
|
parser::Parser,
|
||||||
|
platform::Platform,
|
||||||
|
platform_interface::PlatformInterface,
|
||||||
|
position::Position,
|
||||||
|
positional::Positional,
|
||||||
|
ran::Ran,
|
||||||
|
range_ext::RangeExt,
|
||||||
|
recipe::Recipe,
|
||||||
|
recipe_resolver::RecipeResolver,
|
||||||
|
recipe_signature::RecipeSignature,
|
||||||
|
scope::Scope,
|
||||||
|
search::Search,
|
||||||
|
search_config::SearchConfig,
|
||||||
|
search_error::SearchError,
|
||||||
|
set::Set,
|
||||||
|
setting::Setting,
|
||||||
|
settings::Settings,
|
||||||
|
shebang::Shebang,
|
||||||
|
show_whitespace::ShowWhitespace,
|
||||||
|
source::Source,
|
||||||
|
string_delimiter::StringDelimiter,
|
||||||
|
string_kind::StringKind,
|
||||||
|
string_literal::StringLiteral,
|
||||||
|
subcommand::Subcommand,
|
||||||
|
suggestion::Suggestion,
|
||||||
|
table::Table,
|
||||||
|
thunk::Thunk,
|
||||||
|
token::Token,
|
||||||
|
token_kind::TokenKind,
|
||||||
|
unresolved_dependency::UnresolvedDependency,
|
||||||
|
unresolved_recipe::UnresolvedRecipe,
|
||||||
|
unstable_feature::UnstableFeature,
|
||||||
|
use_color::UseColor,
|
||||||
|
variables::Variables,
|
||||||
|
verbosity::Verbosity,
|
||||||
|
warning::Warning,
|
||||||
},
|
},
|
||||||
camino::Utf8Path,
|
camino::Utf8Path,
|
||||||
clap::ValueEnum,
|
clap::ValueEnum,
|
||||||
|
@ -462,7 +462,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
/// Parse an alias, e.g `alias name := target`
|
/// Parse an alias, e.g `alias name := target`
|
||||||
fn parse_alias(
|
fn parse_alias(
|
||||||
&mut self,
|
&mut self,
|
||||||
attributes: BTreeSet<Attribute<'src>>,
|
attributes: AttributeSet<'src>,
|
||||||
) -> CompileResult<'src, Alias<'src, Name<'src>>> {
|
) -> CompileResult<'src, Alias<'src, Name<'src>>> {
|
||||||
self.presume_keyword(Keyword::Alias)?;
|
self.presume_keyword(Keyword::Alias)?;
|
||||||
let name = self.parse_name()?;
|
let name = self.parse_name()?;
|
||||||
@ -480,24 +480,15 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
fn parse_assignment(
|
fn parse_assignment(
|
||||||
&mut self,
|
&mut self,
|
||||||
export: bool,
|
export: bool,
|
||||||
attributes: BTreeSet<Attribute<'src>>,
|
attributes: AttributeSet<'src>,
|
||||||
) -> CompileResult<'src, Assignment<'src>> {
|
) -> CompileResult<'src, Assignment<'src>> {
|
||||||
let name = self.parse_name()?;
|
let name = self.parse_name()?;
|
||||||
self.presume(ColonEquals)?;
|
self.presume(ColonEquals)?;
|
||||||
let value = self.parse_expression()?;
|
let value = self.parse_expression()?;
|
||||||
self.expect_eol()?;
|
self.expect_eol()?;
|
||||||
|
|
||||||
let private = attributes.contains(&Attribute::Private);
|
let private = attributes.contains(AttributeDiscriminant::Private);
|
||||||
|
attributes.ensure_valid_attributes("Assignment", *name, &[AttributeDiscriminant::Private])?;
|
||||||
for attribute in attributes {
|
|
||||||
if attribute != Attribute::Private {
|
|
||||||
return Err(name.error(CompileErrorKind::InvalidAttribute {
|
|
||||||
item_kind: "Assignment",
|
|
||||||
item_name: name.lexeme(),
|
|
||||||
attribute,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
constant: false,
|
constant: false,
|
||||||
@ -863,7 +854,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
doc: Option<&'src str>,
|
doc: Option<&'src str>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
attributes: BTreeSet<Attribute<'src>>,
|
attributes: AttributeSet<'src>,
|
||||||
) -> CompileResult<'src, UnresolvedRecipe<'src>> {
|
) -> CompileResult<'src, UnresolvedRecipe<'src>> {
|
||||||
let name = self.parse_name()?;
|
let name = self.parse_name()?;
|
||||||
|
|
||||||
@ -924,9 +915,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
let body = self.parse_body()?;
|
let body = self.parse_body()?;
|
||||||
|
|
||||||
let shebang = body.first().map_or(false, Line::is_shebang);
|
let shebang = body.first().map_or(false, Line::is_shebang);
|
||||||
let script = attributes
|
let script = attributes.contains(AttributeDiscriminant::Script);
|
||||||
.iter()
|
|
||||||
.any(|attribute| matches!(attribute, Attribute::Script(_)));
|
|
||||||
|
|
||||||
if shebang && script {
|
if shebang && script {
|
||||||
return Err(name.error(CompileErrorKind::ShebangAndScriptAttribute {
|
return Err(name.error(CompileErrorKind::ShebangAndScriptAttribute {
|
||||||
@ -934,7 +923,8 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let private = name.lexeme().starts_with('_') || attributes.contains(&Attribute::Private);
|
let private =
|
||||||
|
name.lexeme().starts_with('_') || attributes.contains(AttributeDiscriminant::Private);
|
||||||
|
|
||||||
Ok(Recipe {
|
Ok(Recipe {
|
||||||
shebang: shebang || script,
|
shebang: shebang || script,
|
||||||
@ -1114,9 +1104,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Item attributes, i.e., `[macos]` or `[confirm: "warning!"]`
|
/// Item attributes, i.e., `[macos]` or `[confirm: "warning!"]`
|
||||||
fn parse_attributes(
|
fn parse_attributes(&mut self) -> CompileResult<'src, Option<(Token<'src>, AttributeSet<'src>)>> {
|
||||||
&mut self,
|
|
||||||
) -> CompileResult<'src, Option<(Token<'src>, BTreeSet<Attribute<'src>>)>> {
|
|
||||||
let mut attributes = BTreeMap::new();
|
let mut attributes = BTreeMap::new();
|
||||||
|
|
||||||
let mut token = None;
|
let mut token = None;
|
||||||
@ -1164,7 +1152,8 @@ impl<'run, 'src> Parser<'run, 'src> {
|
|||||||
if attributes.is_empty() {
|
if attributes.is_empty() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some((token.unwrap(), attributes.into_keys().collect())))
|
let attribute_set = AttributeSet::from_iter(attributes.into_keys());
|
||||||
|
Ok(Some((token.unwrap(), attribute_set)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ fn error_from_signal(recipe: &str, line_number: Option<usize>, exit_status: Exit
|
|||||||
/// A recipe, e.g. `foo: bar baz`
|
/// A recipe, e.g. `foo: bar baz`
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize)]
|
#[derive(PartialEq, Debug, Clone, Serialize)]
|
||||||
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
pub(crate) struct Recipe<'src, D = Dependency<'src>> {
|
||||||
pub(crate) attributes: BTreeSet<Attribute<'src>>,
|
pub(crate) attributes: AttributeSet<'src>,
|
||||||
pub(crate) body: Vec<Line<'src>>,
|
pub(crate) body: Vec<Line<'src>>,
|
||||||
pub(crate) dependencies: Vec<D>,
|
pub(crate) dependencies: Vec<D>,
|
||||||
pub(crate) doc: Option<&'src str>,
|
pub(crate) doc: Option<&'src str>,
|
||||||
@ -66,20 +66,20 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn confirm(&self) -> RunResult<'src, bool> {
|
pub(crate) fn confirm(&self) -> RunResult<'src, bool> {
|
||||||
for attribute in &self.attributes {
|
if let Some(Attribute::Confirm(ref prompt)) =
|
||||||
if let Attribute::Confirm(prompt) = attribute {
|
self.attributes.get(AttributeDiscriminant::Confirm)
|
||||||
if let Some(prompt) = prompt {
|
{
|
||||||
eprint!("{} ", prompt.cooked);
|
if let Some(prompt) = prompt {
|
||||||
} else {
|
eprint!("{} ", prompt.cooked);
|
||||||
eprint!("Run recipe `{}`? ", self.name);
|
} else {
|
||||||
}
|
eprint!("Run recipe `{}`? ", self.name);
|
||||||
let mut line = String::new();
|
|
||||||
std::io::stdin()
|
|
||||||
.read_line(&mut line)
|
|
||||||
.map_err(|io_error| Error::GetConfirmation { io_error })?;
|
|
||||||
let line = line.trim().to_lowercase();
|
|
||||||
return Ok(line == "y" || line == "yes");
|
|
||||||
}
|
}
|
||||||
|
let mut line = String::new();
|
||||||
|
std::io::stdin()
|
||||||
|
.read_line(&mut line)
|
||||||
|
.map_err(|io_error| Error::GetConfirmation { io_error })?;
|
||||||
|
let line = line.trim().to_lowercase();
|
||||||
|
return Ok(line == "y" || line == "yes");
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_public(&self) -> bool {
|
pub(crate) fn is_public(&self) -> bool {
|
||||||
!self.private && !self.attributes.contains(&Attribute::Private)
|
!self.private && !self.attributes.contains(AttributeDiscriminant::Private)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_script(&self) -> bool {
|
pub(crate) fn is_script(&self) -> bool {
|
||||||
@ -105,18 +105,21 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn takes_positional_arguments(&self, settings: &Settings) -> bool {
|
pub(crate) fn takes_positional_arguments(&self, settings: &Settings) -> bool {
|
||||||
settings.positional_arguments || self.attributes.contains(&Attribute::PositionalArguments)
|
settings.positional_arguments
|
||||||
|
|| self
|
||||||
|
.attributes
|
||||||
|
.contains(AttributeDiscriminant::PositionalArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn change_directory(&self) -> bool {
|
pub(crate) fn change_directory(&self) -> bool {
|
||||||
!self.attributes.contains(&Attribute::NoCd)
|
!self.attributes.contains(AttributeDiscriminant::NoCd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enabled(&self) -> bool {
|
pub(crate) fn enabled(&self) -> bool {
|
||||||
let windows = self.attributes.contains(&Attribute::Windows);
|
let windows = self.attributes.contains(AttributeDiscriminant::Windows);
|
||||||
let linux = self.attributes.contains(&Attribute::Linux);
|
let linux = self.attributes.contains(AttributeDiscriminant::Linux);
|
||||||
let macos = self.attributes.contains(&Attribute::Macos);
|
let macos = self.attributes.contains(AttributeDiscriminant::Macos);
|
||||||
let unix = self.attributes.contains(&Attribute::Unix);
|
let unix = self.attributes.contains(AttributeDiscriminant::Unix);
|
||||||
|
|
||||||
(!windows && !linux && !macos && !unix)
|
(!windows && !linux && !macos && !unix)
|
||||||
|| (cfg!(target_os = "windows") && windows)
|
|| (cfg!(target_os = "windows") && windows)
|
||||||
@ -127,7 +130,9 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_exit_message(&self) -> bool {
|
fn print_exit_message(&self) -> bool {
|
||||||
!self.attributes.contains(&Attribute::NoExitMessage)
|
!self
|
||||||
|
.attributes
|
||||||
|
.contains(AttributeDiscriminant::NoExitMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn working_directory<'a>(&'a self, context: &'a ExecutionContext) -> Option<PathBuf> {
|
fn working_directory<'a>(&'a self, context: &'a ExecutionContext) -> Option<PathBuf> {
|
||||||
@ -139,7 +144,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn no_quiet(&self) -> bool {
|
fn no_quiet(&self) -> bool {
|
||||||
self.attributes.contains(&Attribute::NoQuiet)
|
self.attributes.contains(AttributeDiscriminant::NoQuiet)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run<'run>(
|
pub(crate) fn run<'run>(
|
||||||
@ -341,10 +346,8 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let executor = if let Some(Attribute::Script(interpreter)) = self
|
let executor = if let Some(Attribute::Script(interpreter)) =
|
||||||
.attributes
|
self.attributes.get(AttributeDiscriminant::Script)
|
||||||
.iter()
|
|
||||||
.find(|attribute| matches!(attribute, Attribute::Script(_)))
|
|
||||||
{
|
{
|
||||||
Executor::Command(
|
Executor::Command(
|
||||||
interpreter
|
interpreter
|
||||||
|
Loading…
Reference in New Issue
Block a user