This commit is contained in:
Yuri Astrakhan 2023-06-12 12:53:55 -04:00 committed by GitHub
parent 6a407813b4
commit a1220c63e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 153 additions and 265 deletions

View File

@ -43,7 +43,7 @@ impl<'src> Analyzer<'src> {
let settings = Settings::from_setting_iter(self.sets.into_iter().map(|(_, set)| set.value));
let mut recipe_table: Table<'src, UnresolvedRecipe<'src>> = Default::default();
let mut recipe_table: Table<'src, UnresolvedRecipe<'src>> = Table::default();
AssignmentResolver::resolve_assignments(&self.assignments)?;

View File

@ -24,37 +24,27 @@ impl Display for CompileError<'_> {
use CompileErrorKind::*;
match &*self.kind {
AliasInvalidAttribute { alias, attr } => {
write!(
f,
"Alias {} has an invalid attribute `{}`",
alias,
attr.to_str()
)?;
}
AliasShadowsRecipe { alias, recipe_line } => {
write!(
f,
"Alias `{}` defined on line {} shadows recipe `{}` defined on line {}",
alias,
self.token.line.ordinal(),
alias,
recipe_line.ordinal(),
)?;
}
BacktickShebang => {
write!(f, "Backticks may not start with `#!`")?;
}
AliasInvalidAttribute { alias, attr } => write!(
f,
"Alias {alias} has an invalid attribute `{}`",
attr.to_str(),
),
AliasShadowsRecipe { alias, recipe_line } => write!(
f,
"Alias `{alias}` defined on line {} shadows recipe `{alias}` defined on line {}",
self.token.line.ordinal(),
recipe_line.ordinal(),
),
BacktickShebang => write!(f, "Backticks may not start with `#!`"),
CircularRecipeDependency { recipe, ref circle } => {
if circle.len() == 2 {
write!(f, "Recipe `{recipe}` depends on itself")?;
write!(f, "Recipe `{recipe}` depends on itself")
} else {
write!(
f,
"Recipe `{}` has circular dependency `{}`",
recipe,
"Recipe `{recipe}` has circular dependency `{}`",
circle.join(" -> ")
)?;
)
}
}
CircularVariableDependency {
@ -62,14 +52,13 @@ impl Display for CompileError<'_> {
ref circle,
} => {
if circle.len() == 2 {
write!(f, "Variable `{variable}` is defined in terms of itself")?;
write!(f, "Variable `{variable}` is defined in terms of itself")
} else {
write!(
f,
"Variable `{}` depends on its own value: `{}`",
variable,
circle.join(" -> ")
)?;
"Variable `{variable}` depends on its own value: `{}`",
circle.join(" -> "),
)
}
}
DependencyArgumentCountMismatch {
@ -80,206 +69,146 @@ impl Display for CompileError<'_> {
} => {
write!(
f,
"Dependency `{}` got {} {} but takes ",
dependency,
found,
"Dependency `{dependency}` got {found} {} but takes ",
Count("argument", *found),
)?;
if min == max {
let expected = min;
write!(f, "{expected} {}", Count("argument", *expected))?;
write!(f, "{expected} {}", Count("argument", *expected))
} else if found < min {
write!(f, "at least {min} {}", Count("argument", *min))?;
write!(f, "at least {min} {}", Count("argument", *min))
} else {
write!(f, "at most {max} {}", Count("argument", *max))?;
write!(f, "at most {max} {}", Count("argument", *max))
}
}
DuplicateAlias { alias, first } => {
write!(
f,
"Alias `{}` first defined on line {} is redefined on line {}",
alias,
first.ordinal(),
self.token.line.ordinal(),
)?;
}
DuplicateAttribute { attribute, first } => {
write!(
f,
"Recipe attribute `{}` first used on line {} is duplicated on line {}",
attribute,
first.ordinal(),
self.token.line.ordinal(),
)?;
}
DuplicateAlias { alias, first } => write!(
f,
"Alias `{alias}` first defined on line {} is redefined on line {}",
first.ordinal(),
self.token.line.ordinal(),
),
DuplicateAttribute { attribute, first } => write!(
f,
"Recipe attribute `{attribute}` first used on line {} is duplicated on line {}",
first.ordinal(),
self.token.line.ordinal(),
),
DuplicateParameter { recipe, parameter } => {
write!(f, "Recipe `{recipe}` has duplicate parameter `{parameter}`")?;
}
DuplicateRecipe { recipe, first } => {
write!(
f,
"Recipe `{}` first defined on line {} is redefined on line {}",
recipe,
first.ordinal(),
self.token.line.ordinal()
)?;
}
DuplicateSet { setting, first } => {
write!(
f,
"Setting `{}` first set on line {} is redefined on line {}",
setting,
first.ordinal(),
self.token.line.ordinal(),
)?;
write!(f, "Recipe `{recipe}` has duplicate parameter `{parameter}`")
}
DuplicateRecipe { recipe, first } => write!(
f,
"Recipe `{recipe}` first defined on line {} is redefined on line {}",
first.ordinal(),
self.token.line.ordinal(),
),
DuplicateSet { setting, first } => write!(
f,
"Setting `{setting}` first set on line {} is redefined on line {}",
first.ordinal(),
self.token.line.ordinal(),
),
DuplicateVariable { variable } => {
write!(f, "Variable `{variable}` has multiple definitions")?;
write!(f, "Variable `{variable}` has multiple definitions")
}
ExpectedKeyword { expected, found } => {
let expected = List::or_ticked(expected);
if found.kind == TokenKind::Identifier {
write!(
f,
"Expected keyword {} but found identifier `{}`",
List::or_ticked(expected),
"Expected keyword {expected} but found identifier `{}`",
found.lexeme()
)?;
)
} else {
write!(
f,
"Expected keyword {} but found `{}`",
List::or_ticked(expected),
found.kind
)?;
write!(f, "Expected keyword {expected} but found `{}`", found.kind)
}
}
ExtraLeadingWhitespace => {
write!(f, "Recipe line has extra leading whitespace")?;
}
ExtraLeadingWhitespace => write!(f, "Recipe line has extra leading whitespace"),
FunctionArgumentCountMismatch {
function,
found,
expected,
} => {
write!(
f,
"Function `{}` called with {} {} but takes {}",
function,
found,
Count("argument", *found),
expected.display(),
)?;
}
InconsistentLeadingWhitespace { expected, found } => {
write!(
f,
"Recipe line has inconsistent leading whitespace. Recipe started with `{}` but found \
} => write!(
f,
"Function `{function}` called with {found} {} but takes {}",
Count("argument", *found),
expected.display(),
),
InconsistentLeadingWhitespace { expected, found } => write!(
f,
"Recipe line has inconsistent leading whitespace. Recipe started with `{}` but found \
line with `{}`",
ShowWhitespace(expected),
ShowWhitespace(found)
)?;
}
Internal { ref message } => {
write!(
f,
"Internal error, this may indicate a bug in just: {message}\n\
ShowWhitespace(expected),
ShowWhitespace(found)
),
Internal { ref message } => write!(
f,
"Internal error, this may indicate a bug in just: {message}\n\
consider filing an issue: https://github.com/casey/just/issues/new"
)?;
}
InvalidEscapeSequence { character } => {
let representation = match character {
),
InvalidEscapeSequence { character } => write!(
f,
"`\\{}` is not a valid escape sequence",
match character {
'`' => r"\`".to_owned(),
'\\' => r"\".to_owned(),
'\'' => r"'".to_owned(),
'"' => r#"""#.to_owned(),
_ => character.escape_default().collect(),
};
write!(f, "`\\{representation}` is not a valid escape sequence")?;
}
}
),
MismatchedClosingDelimiter {
open,
open_line,
close,
} => {
write!(
f,
"Mismatched closing delimiter `{}`. (Did you mean to close the `{}` on line {}?)",
close.close(),
open.open(),
open_line.ordinal(),
)?;
}
MixedLeadingWhitespace { whitespace } => {
write!(
f,
"Found a mix of tabs and spaces in leading whitespace: `{}`\nLeading whitespace may \
} => write!(
f,
"Mismatched closing delimiter `{}`. (Did you mean to close the `{}` on line {}?)",
close.close(),
open.open(),
open_line.ordinal(),
),
MixedLeadingWhitespace { whitespace } => write!(
f,
"Found a mix of tabs and spaces in leading whitespace: `{}`\nLeading whitespace may \
consist of tabs or spaces, but not both",
ShowWhitespace(whitespace)
)?;
}
ShowWhitespace(whitespace)
),
ParameterFollowsVariadicParameter { parameter } => {
write!(f, "Parameter `{parameter}` follows variadic parameter")?;
}
ParsingRecursionDepthExceeded => {
write!(f, "Parsing recursion depth exceeded")?;
}
RequiredParameterFollowsDefaultParameter { parameter } => {
write!(
f,
"Non-default parameter `{parameter}` follows default parameter"
)?;
}
UndefinedVariable { variable } => {
write!(f, "Variable `{variable}` not defined")?;
}
UnexpectedCharacter { expected } => {
write!(f, "Expected character `{expected}`")?;
write!(f, "Parameter `{parameter}` follows variadic parameter")
}
ParsingRecursionDepthExceeded => write!(f, "Parsing recursion depth exceeded"),
RequiredParameterFollowsDefaultParameter { parameter } => write!(
f,
"Non-default parameter `{parameter}` follows default parameter"
),
UndefinedVariable { variable } => write!(f, "Variable `{variable}` not defined"),
UnexpectedCharacter { expected } => write!(f, "Expected character `{expected}`"),
UnexpectedClosingDelimiter { close } => {
write!(f, "Unexpected closing delimiter `{}`", close.close())?;
write!(f, "Unexpected closing delimiter `{}`", close.close())
}
UnexpectedEndOfToken { expected } => {
write!(f, "Expected character `{expected}` but found end-of-file")?;
write!(f, "Expected character `{expected}` but found end-of-file")
}
UnexpectedToken {
ref expected,
found,
} => {
write!(f, "Expected {}, but found {found}", List::or(expected))?;
}
} => write!(f, "Expected {}, but found {found}", List::or(expected)),
UnknownAliasTarget { alias, target } => {
write!(f, "Alias `{alias}` has an unknown target `{target}`")?;
}
UnknownAttribute { attribute } => {
write!(f, "Unknown attribute `{attribute}`")?;
write!(f, "Alias `{alias}` has an unknown target `{target}`")
}
UnknownAttribute { attribute } => write!(f, "Unknown attribute `{attribute}`"),
UnknownDependency { recipe, unknown } => {
write!(f, "Recipe `{recipe}` has unknown dependency `{unknown}`",)?;
}
UnknownFunction { function } => {
write!(f, "Call to unknown function `{function}`")?;
}
UnknownSetting { setting } => {
write!(f, "Unknown setting `{setting}`")?;
}
UnknownStartOfToken => {
write!(f, "Unknown start of token:")?;
}
UnpairedCarriageReturn => {
write!(f, "Unpaired carriage return")?;
}
UnterminatedBacktick => {
write!(f, "Unterminated backtick")?;
}
UnterminatedInterpolation => {
write!(f, "Unterminated interpolation")?;
}
UnterminatedString => {
write!(f, "Unterminated string")?;
write!(f, "Recipe `{recipe}` has unknown dependency `{unknown}`")
}
UnknownFunction { function } => write!(f, "Call to unknown function `{function}`"),
UnknownSetting { setting } => write!(f, "Unknown setting `{setting}`"),
UnknownStartOfToken => write!(f, "Unknown start of token:"),
UnpairedCarriageReturn => write!(f, "Unpaired carriage return"),
UnterminatedBacktick => write!(f, "Unterminated backtick"),
UnterminatedInterpolation => write!(f, "Unterminated interpolation"),
UnterminatedString => write!(f, "Unterminated string"),
}
Ok(())
}
}

View File

@ -11,6 +11,7 @@ pub(crate) const CHOOSE_HELP: &str = "Select one or more recipes to run using a
of $JUST_CHOOSER, falling back to `fzf`";
#[derive(Debug, PartialEq)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct Config {
pub(crate) check: bool,
pub(crate) color: Color,

View File

@ -1,6 +1,3 @@
// `Self` cannot be used where type takes generic arguments
#![allow(clippy::use_self)]
use super::*;
pub struct Enclosure<T: Display> {

View File

@ -238,30 +238,21 @@ impl<'src> ColorDisplay for Error<'src> {
let expected = min;
write!(
f,
"Recipe `{}` got {} {} but {}takes {}",
recipe,
found,
"Recipe `{recipe}` got {found} {} but {}takes {expected}",
Count("argument", *found),
if expected < found { "only " } else { "" },
expected
if expected < found { "only " } else { "" }
)?;
} else if found < min {
write!(
f,
"Recipe `{}` got {} {} but takes at least {}",
recipe,
found,
Count("argument", *found),
min
"Recipe `{recipe}` got {found} {} but takes at least {min}",
Count("argument", *found)
)?;
} else if found > max {
write!(
f,
"Recipe `{}` got {} {} but takes at most {}",
recipe,
found,
Count("argument", *found),
max
"Recipe `{recipe}` got {found} {} but takes at most {max}",
Count("argument", *found)
)?;
}
}
@ -306,35 +297,29 @@ impl<'src> ColorDisplay for Error<'src> {
} => {
write!(
f,
"Chooser `{} {} {}` invocation failed: {}",
shell_binary,
shell_arguments,
"Chooser `{shell_binary} {shell_arguments} {}` invocation failed: {io_error}",
chooser.to_string_lossy(),
io_error,
)?;
}
ChooserRead { chooser, io_error } => {
write!(
f,
"Failed to read output from chooser `{}`: {}",
chooser.to_string_lossy(),
io_error
"Failed to read output from chooser `{}`: {io_error}",
chooser.to_string_lossy()
)?;
}
ChooserStatus { chooser, status } => {
write!(
f,
"Chooser `{}` failed: {}",
chooser.to_string_lossy(),
status
"Chooser `{}` failed: {status}",
chooser.to_string_lossy()
)?;
}
ChooserWrite { chooser, io_error } => {
write!(
f,
"Failed to write to chooser `{}`: {}",
chooser.to_string_lossy(),
io_error
"Failed to write to chooser `{}`: {io_error}",
chooser.to_string_lossy()
)?;
}
CircularInclude { current, include } => {
@ -365,13 +350,12 @@ impl<'src> ColorDisplay for Error<'src> {
} => {
write!(
f,
"Failed to invoke {}: {}",
"Failed to invoke {}: {io_error}",
iter::once(binary)
.chain(arguments)
.map(|value| Enclosure::tick(value.to_string_lossy()).to_string())
.collect::<Vec<String>>()
.join(" "),
io_error,
)?;
}
CommandStatus {
@ -381,13 +365,12 @@ impl<'src> ColorDisplay for Error<'src> {
} => {
write!(
f,
"Command {} failed: {}",
"Command {} failed: {status}",
iter::once(binary)
.chain(arguments)
.map(|value| Enclosure::tick(value.to_string_lossy()).to_string())
.collect::<Vec<String>>()
.join(" "),
status,
)?;
}
Compile { compile_error } => Display::fmt(compile_error, f)?,
@ -446,9 +429,7 @@ impl<'src> ColorDisplay for Error<'src> {
} => {
write!(
f,
"Recipe `{}` cannot be used as default recipe since it requires at least {} {}.",
recipe,
min_arguments,
"Recipe `{recipe}` cannot be used as default recipe since it requires at least {min_arguments} {}.",
Count("argument", *min_arguments),
)?;
}
@ -483,9 +464,8 @@ impl<'src> ColorDisplay for Error<'src> {
FunctionCall { function, message } => {
write!(
f,
"Call to function `{}` failed: {}",
function.lexeme(),
message
"Call to function `{}` failed: {message}",
function.lexeme()
)?;
}
IncludeMissingPath {
@ -532,9 +512,8 @@ impl<'src> ColorDisplay for Error<'src> {
Load { io_error, path } => {
write!(
f,
"Failed to read justfile at `{}`: {}",
path.display(),
io_error
"Failed to read justfile at `{}`: {io_error}",
path.display()
)?;
}
NoChoosableRecipes => {
@ -628,9 +607,8 @@ impl<'src> ColorDisplay for Error<'src> {
WriteJustfile { justfile, io_error } => {
write!(
f,
"Failed to write justfile to `{}`: {}",
justfile.display(),
io_error
"Failed to write justfile to `{}`: {io_error}",
justfile.display()
)?;
}
}
@ -642,12 +620,7 @@ impl<'src> ColorDisplay for Error<'src> {
} = self
{
writeln!(f)?;
write!(
f,
"{}:\n just {}",
color.message().paint("usage"),
recipe
)?;
write!(f, "{}:\n just {recipe}", color.message().paint("usage"))?;
for param in parameters {
write!(f, " {}", param.color_display(color))?;
}

View File

@ -1,6 +1,3 @@
#![allow(unknown_lints)]
#![allow(clippy::unnecessary_wraps)]
use {
super::*,
heck::{
@ -208,7 +205,7 @@ fn join(
fn just_executable(_context: &FunctionContext) -> Result<String, String> {
let exe_path =
std::env::current_exe().map_err(|e| format!("Error getting current executable: {e}"))?;
env::current_exe().map_err(|e| format!("Error getting current executable: {e}"))?;
exe_path.to_str().map(str::to_owned).ok_or_else(|| {
format!(
@ -323,7 +320,7 @@ fn sha256_file(context: &FunctionContext, path: &str) -> Result<String, String>
use sha2::{Digest, Sha256};
let justpath = context.search.working_directory.join(path);
let mut hasher = Sha256::new();
let mut file = std::fs::File::open(&justpath)
let mut file = fs::File::open(&justpath)
.map_err(|err| format!("Failed to open file at `{:?}`: {err}", &justpath.to_str()))?;
std::io::copy(&mut file, &mut hasher)
.map_err(|err| format!("Failed to read file at `{:?}`: {err}", &justpath.to_str()))?;

View File

@ -208,7 +208,7 @@ impl<'src> Lexer<'src> {
};
CompileError::new(
token,
CompileErrorKind::Internal {
Internal {
message: message.into(),
},
)
@ -773,7 +773,7 @@ impl<'src> Lexer<'src> {
/// Lex a backtick, cooked string, or raw string.
///
/// Backtick: `[^`]*`
/// Backtick: ``[^`]*``
/// Cooked string: "[^"]*" # also processes escape sequences
/// Raw string: '[^']*'
fn lex_string(&mut self) -> CompileResult<'src, ()> {

View File

@ -1,16 +1,10 @@
#![deny(clippy::all, clippy::pedantic)]
#![allow(
clippy::default_trait_access,
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::let_underscore_untyped,
clippy::missing_errors_doc,
clippy::needless_pass_by_value,
clippy::non_ascii_literal,
clippy::shadow_unrelated,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::type_repetition_in_bounds,
clippy::unnecessary_wraps,
clippy::wildcard_imports
)]

View File

@ -1,6 +1,3 @@
// `Self` cannot be used where type takes generic arguments
#![allow(clippy::use_self)]
use super::*;
pub struct List<T: Display, I: Iterator<Item = T> + Clone> {

View File

@ -174,15 +174,14 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
if next.kind != Identifier {
Err(self.internal_error(format!(
"Presumed next token would have kind {}, but found {}",
Identifier, next.kind
"Presumed next token would have kind {Identifier}, but found {}",
next.kind
))?)
} else if keyword == next.lexeme() {
Ok(())
} else {
Err(self.internal_error(format!(
"Presumed next token would have lexeme \"{}\", but found \"{}\"",
keyword,
"Presumed next token would have lexeme \"{keyword}\", but found \"{}\"",
next.lexeme(),
))?)
}
@ -196,8 +195,8 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
Ok(next)
} else {
Err(self.internal_error(format!(
"Presumed next token would have kind {:?}, but found {:?}",
kind, next.kind
"Presumed next token would have kind {kind:?}, but found {:?}",
next.kind
))?)
}
}
@ -869,7 +868,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
}
attributes.insert(attribute, name.line);
if !self.accepted(TokenKind::Comma)? {
if !self.accepted(Comma)? {
break;
}
}

View File

@ -1,6 +1,7 @@
use super::*;
/// Main entry point into just binary.
#[allow(clippy::missing_errors_doc)]
pub fn run() -> Result<(), i32> {
#[cfg(windows)]
ansi_term::enable_ansi_support().ok();

View File

@ -6,6 +6,7 @@ pub(crate) const WINDOWS_POWERSHELL_SHELL: &str = "powershell.exe";
pub(crate) const WINDOWS_POWERSHELL_ARGS: &[&str] = &["-NoLogo", "-Command"];
#[derive(Debug, PartialEq, Serialize, Default)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct Settings<'src> {
pub(crate) allow_duplicate_recipes: bool,
pub(crate) dotenv_load: Option<bool>,

View File

@ -116,7 +116,7 @@ fn editor_precedence() {
assert_stdout(&output, JUSTFILE);
let cat = which("cat").unwrap();
let vim = tmp.path().join(format!("vim{}", env::consts::EXE_SUFFIX));
let vim = tmp.path().join(format!("vim{}", EXE_SUFFIX));
#[cfg(unix)]
std::os::unix::fs::symlink(cat, vim).unwrap();
@ -154,7 +154,7 @@ fn editor_working_directory() {
let editor = tmp.path().join("editor");
let permissions = std::os::unix::fs::PermissionsExt::from_mode(0o700);
std::fs::set_permissions(&editor, permissions).unwrap();
fs::set_permissions(&editor, permissions).unwrap();
let output = Command::new(executable_path("just"))
.current_dir(tmp.path().join("child"))
@ -164,8 +164,7 @@ fn editor_working_directory() {
.unwrap();
let want = format!(
"{}{}\n",
JUSTFILE,
"{JUSTFILE}{}\n",
tmp.path().canonicalize().unwrap().display()
);

View File

@ -169,8 +169,8 @@ impl Test {
pub(crate) fn write(self, path: impl AsRef<Path>, content: impl AsRef<[u8]>) -> Self {
let path = self.tempdir.path().join(path);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, content).unwrap();
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, content).unwrap();
self
}
}
@ -224,7 +224,7 @@ impl Test {
fn compare<T: PartialEq + Debug>(name: &str, have: T, want: T) -> bool {
let equal = have == want;
if !equal {
eprintln!("Bad {}: {}", name, Comparison::new(&have, &want));
eprintln!("Bad {name}: {}", Comparison::new(&have, &want));
}
equal
}