Add additional continuous integration checks (#574)
Add GitHub Actions checks: - Clippy is placated - Rustfmt doesn't produce any changes - Shell completion scripts are current
This commit is contained in:
parent
85e8015702
commit
ed991cb509
32
.github/workflows/rust.yaml
vendored
Normal file
32
.github/workflows/rust.yaml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: Rust
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
profile: minimal
|
||||||
|
components: clippy, rustfmt
|
||||||
|
override: true
|
||||||
|
- name: Version
|
||||||
|
run: |
|
||||||
|
rustup --version
|
||||||
|
cargo --version
|
||||||
|
cargo clippy --version
|
||||||
|
- name: Lint
|
||||||
|
run: cargo clippy
|
||||||
|
- name: Format
|
||||||
|
run: cargo fmt -- --check
|
||||||
|
- name: Completion Scripts
|
||||||
|
run: |
|
||||||
|
for script in completions/*; do
|
||||||
|
shell=${script##*.}
|
||||||
|
cargo run -- --completions $shell > $script
|
||||||
|
done
|
||||||
|
git diff --no-ext-diff --quiet --exit-code
|
@ -1,5 +1,5 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.11.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.11.
|
||||||
.TH JUST "1" "December 2019" "just 0.5.4" "JUST MANUAL"
|
.TH JUST "1" "January 2020" "just 0.5.4" "JUST MANUAL"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
just \- save and run commands
|
just \- save and run commands
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
@ -57,6 +57,10 @@ Print version information
|
|||||||
.TP
|
.TP
|
||||||
Print colorful output [default: auto]
|
Print colorful output [default: auto]
|
||||||
[possible values: auto, always, never]
|
[possible values: auto, always, never]
|
||||||
|
.HP
|
||||||
|
\fB\-\-completions\fR <SHELL>
|
||||||
|
.IP
|
||||||
|
Print shell completion script for <SHELL> [possible values: zsh, bash, fish, powershell, elvish]
|
||||||
.TP
|
.TP
|
||||||
\fB\-f\fR, \fB\-\-justfile\fR <JUSTFILE>
|
\fB\-f\fR, \fB\-\-justfile\fR <JUSTFILE>
|
||||||
Use <JUSTFILE> as justfile.
|
Use <JUSTFILE> as justfile.
|
||||||
|
@ -73,7 +73,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
|
|
||||||
let mut settings = Settings::new();
|
let mut settings = Settings::new();
|
||||||
|
|
||||||
for (_, set) in self.sets.into_iter() {
|
for (_, set) in self.sets {
|
||||||
match set.value {
|
match set.value {
|
||||||
Setting::Shell(shell) => {
|
Setting::Shell(shell) => {
|
||||||
assert!(settings.shell.is_none());
|
assert!(settings.shell.is_none());
|
||||||
@ -191,7 +191,7 @@ impl<'src> Analyzer<'src> {
|
|||||||
|
|
||||||
// Make sure the target recipe exists
|
// Make sure the target recipe exists
|
||||||
match recipes.get(alias.target.lexeme()) {
|
match recipes.get(alias.target.lexeme()) {
|
||||||
Some(target) => Ok(alias.resolve(target.clone())),
|
Some(target) => Ok(alias.resolve(Rc::clone(target))),
|
||||||
None => Err(token.error(UnknownAliasTarget {
|
None => Err(token.error(UnknownAliasTarget {
|
||||||
alias: alias.name.lexeme(),
|
alias: alias.name.lexeme(),
|
||||||
target: alias.target.lexeme(),
|
target: alias.target.lexeme(),
|
||||||
|
52
src/color.rs
52
src/color.rs
@ -12,12 +12,12 @@ pub(crate) struct Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
fn restyle(self, style: Style) -> Color {
|
fn restyle(self, style: Style) -> Self {
|
||||||
Color { style, ..self }
|
Self { style, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redirect(self, stream: Stream) -> Color {
|
fn redirect(self, stream: Stream) -> Self {
|
||||||
Color {
|
Self {
|
||||||
atty: atty::is(stream),
|
atty: atty::is(stream),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
@ -31,76 +31,76 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fmt(fmt: &Formatter) -> Color {
|
pub(crate) fn fmt(fmt: &Formatter) -> Self {
|
||||||
if fmt.alternate() {
|
if fmt.alternate() {
|
||||||
Color::always()
|
Self::always()
|
||||||
} else {
|
} else {
|
||||||
Color::never()
|
Self::never()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn auto() -> Color {
|
pub(crate) fn auto() -> Self {
|
||||||
Color {
|
Self {
|
||||||
use_color: UseColor::Auto,
|
use_color: UseColor::Auto,
|
||||||
..default()
|
..default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn always() -> Color {
|
pub(crate) fn always() -> Self {
|
||||||
Color {
|
Self {
|
||||||
use_color: UseColor::Always,
|
use_color: UseColor::Always,
|
||||||
..default()
|
..default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn never() -> Color {
|
pub(crate) fn never() -> Self {
|
||||||
Color {
|
Self {
|
||||||
use_color: UseColor::Never,
|
use_color: UseColor::Never,
|
||||||
..default()
|
..default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn stderr(self) -> Color {
|
pub(crate) fn stderr(self) -> Self {
|
||||||
self.redirect(Stream::Stderr)
|
self.redirect(Stream::Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn stdout(self) -> Color {
|
pub(crate) fn stdout(self) -> Self {
|
||||||
self.redirect(Stream::Stdout)
|
self.redirect(Stream::Stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn doc(self) -> Color {
|
pub(crate) fn doc(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Blue))
|
self.restyle(Style::new().fg(Blue))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn error(self) -> Color {
|
pub(crate) fn error(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Red).bold())
|
self.restyle(Style::new().fg(Red).bold())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn warning(self) -> Color {
|
pub(crate) fn warning(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Yellow).bold())
|
self.restyle(Style::new().fg(Yellow).bold())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn banner(self) -> Color {
|
pub(crate) fn banner(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Cyan).bold())
|
self.restyle(Style::new().fg(Cyan).bold())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn command(self) -> Color {
|
pub(crate) fn command(self) -> Self {
|
||||||
self.restyle(Style::new().bold())
|
self.restyle(Style::new().bold())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parameter(self) -> Color {
|
pub(crate) fn parameter(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Cyan))
|
self.restyle(Style::new().fg(Cyan))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn message(self) -> Color {
|
pub(crate) fn message(self) -> Self {
|
||||||
self.restyle(Style::new().bold())
|
self.restyle(Style::new().bold())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn annotation(self) -> Color {
|
pub(crate) fn annotation(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Purple))
|
self.restyle(Style::new().fg(Purple))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn string(self) -> Color {
|
pub(crate) fn string(self) -> Self {
|
||||||
self.restyle(Style::new().fg(Green))
|
self.restyle(Style::new().fg(Green))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +126,8 @@ impl Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Color {
|
impl Default for Color {
|
||||||
fn default() -> Color {
|
fn default() -> Self {
|
||||||
Color {
|
Self {
|
||||||
use_color: UseColor::Auto,
|
use_color: UseColor::Auto,
|
||||||
atty: false,
|
atty: false,
|
||||||
style: Style::new(),
|
style: Style::new(),
|
||||||
|
@ -237,7 +237,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_matches(matches: &ArgMatches) -> ConfigResult<Config> {
|
pub(crate) fn from_matches(matches: &ArgMatches) -> ConfigResult<Self> {
|
||||||
let invocation_directory = env::current_dir().context(config_error::CurrentDir)?;
|
let invocation_directory = env::current_dir().context(config_error::CurrentDir)?;
|
||||||
|
|
||||||
let verbosity = Verbosity::from_flag_occurrences(matches.occurrences_of(arg::VERBOSE));
|
let verbosity = Verbosity::from_flag_occurrences(matches.occurrences_of(arg::VERBOSE));
|
||||||
@ -368,7 +368,7 @@ impl Config {
|
|||||||
|| matches.occurrences_of(arg::SHELL) > 0
|
|| matches.occurrences_of(arg::SHELL) > 0
|
||||||
|| matches.occurrences_of(arg::SHELL_ARG) > 0;
|
|| matches.occurrences_of(arg::SHELL_ARG) > 0;
|
||||||
|
|
||||||
Ok(Config {
|
Ok(Self {
|
||||||
dry_run: matches.is_present(arg::DRY_RUN),
|
dry_run: matches.is_present(arg::DRY_RUN),
|
||||||
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
|
||||||
quiet: matches.is_present(arg::QUIET),
|
quiet: matches.is_present(arg::QUIET),
|
||||||
@ -394,7 +394,7 @@ impl Config {
|
|||||||
Search::find(&self.search_config, &self.invocation_directory).eprint(self.color)?;
|
Search::find(&self.search_config, &self.invocation_directory).eprint(self.color)?;
|
||||||
|
|
||||||
if self.subcommand == Edit {
|
if self.subcommand == Edit {
|
||||||
return self.edit(&search);
|
return Self::edit(&search);
|
||||||
}
|
}
|
||||||
|
|
||||||
let src = fs::read_to_string(&search.justfile)
|
let src = fs::read_to_string(&search.justfile)
|
||||||
@ -415,7 +415,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match &self.subcommand {
|
match &self.subcommand {
|
||||||
Dump => self.dump(justfile),
|
Dump => Self::dump(justfile),
|
||||||
Completions { shell } => Self::completions(&shell),
|
Completions { shell } => Self::completions(&shell),
|
||||||
Evaluate { overrides } => self.run(justfile, &search, overrides, &Vec::new()),
|
Evaluate { overrides } => self.run(justfile, &search, overrides, &Vec::new()),
|
||||||
Run {
|
Run {
|
||||||
@ -423,8 +423,8 @@ impl Config {
|
|||||||
overrides,
|
overrides,
|
||||||
} => self.run(justfile, &search, overrides, arguments),
|
} => self.run(justfile, &search, overrides, arguments),
|
||||||
List => self.list(justfile),
|
List => self.list(justfile),
|
||||||
Show { ref name } => self.show(&name, justfile),
|
Show { ref name } => Self::show(&name, justfile),
|
||||||
Summary => self.summary(justfile),
|
Summary => Self::summary(justfile),
|
||||||
Edit | Init => unreachable!(),
|
Edit | Init => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,12 +439,12 @@ impl Config {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump(&self, justfile: Justfile) -> Result<(), i32> {
|
fn dump(justfile: Justfile) -> Result<(), i32> {
|
||||||
println!("{}", justfile);
|
println!("{}", justfile);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn edit(&self, search: &Search) -> Result<(), i32> {
|
pub(crate) fn edit(search: &Search) -> Result<(), i32> {
|
||||||
let editor = env::var_os("VISUAL")
|
let editor = env::var_os("VISUAL")
|
||||||
.or_else(|| env::var_os("EDITOR"))
|
.or_else(|| env::var_os("EDITOR"))
|
||||||
.unwrap_or_else(|| "vim".into());
|
.unwrap_or_else(|| "vim".into());
|
||||||
@ -601,7 +601,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&self, name: &str, justfile: Justfile) -> Result<(), i32> {
|
fn show(name: &str, justfile: Justfile) -> Result<(), i32> {
|
||||||
if let Some(alias) = justfile.get_alias(name) {
|
if let Some(alias) = justfile.get_alias(name) {
|
||||||
let recipe = justfile.get_recipe(alias.target.name.lexeme()).unwrap();
|
let recipe = justfile.get_recipe(alias.target.name.lexeme()).unwrap();
|
||||||
println!("{}", alias);
|
println!("{}", alias);
|
||||||
@ -619,7 +619,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn summary(&self, justfile: Justfile) -> Result<(), i32> {
|
fn summary(justfile: Justfile) -> Result<(), i32> {
|
||||||
if justfile.count() == 0 {
|
if justfile.count() == 0 {
|
||||||
eprintln!("Justfile contains no recipes.");
|
eprintln!("Justfile contains no recipes.");
|
||||||
} else {
|
} else {
|
||||||
|
@ -48,8 +48,8 @@ pub(crate) enum ConfigError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigError {
|
impl ConfigError {
|
||||||
pub(crate) fn internal(message: impl Into<String>) -> ConfigError {
|
pub(crate) fn internal(message: impl Into<String>) -> Self {
|
||||||
ConfigError::Internal {
|
Self::Internal {
|
||||||
message: message.into(),
|
message: message.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// `Self` cannot be used where type takes generic arguments
|
||||||
|
#![allow(clippy::use_self)]
|
||||||
|
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub struct Enclosure<T: Display> {
|
pub struct Enclosure<T: Display> {
|
||||||
@ -7,7 +10,7 @@ pub struct Enclosure<T: Display> {
|
|||||||
|
|
||||||
impl<T: Display> Enclosure<T> {
|
impl<T: Display> Enclosure<T> {
|
||||||
pub fn tick(value: T) -> Enclosure<T> {
|
pub fn tick(value: T) -> Enclosure<T> {
|
||||||
Enclosure {
|
Self {
|
||||||
enclosure: "`",
|
enclosure: "`",
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
|
@ -66,13 +66,14 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Call { thunk } => {
|
Expression::Call { thunk } => {
|
||||||
|
use Thunk::*;
|
||||||
|
|
||||||
let context = FunctionContext {
|
let context = FunctionContext {
|
||||||
dotenv: self.dotenv,
|
dotenv: self.dotenv,
|
||||||
invocation_directory: &self.config.invocation_directory,
|
invocation_directory: &self.config.invocation_directory,
|
||||||
search: self.search,
|
search: self.search,
|
||||||
};
|
};
|
||||||
|
|
||||||
use Thunk::*;
|
|
||||||
match thunk {
|
match thunk {
|
||||||
Nullary { name, function, .. } => {
|
Nullary { name, function, .. } => {
|
||||||
function(&context).map_err(|message| RuntimeError::FunctionCall {
|
function(&context).map_err(|message| RuntimeError::FunctionCall {
|
||||||
@ -183,14 +184,13 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
let mut rest = arguments;
|
let mut rest = arguments;
|
||||||
for parameter in parameters {
|
for parameter in parameters {
|
||||||
let value = if rest.is_empty() {
|
let value = if rest.is_empty() {
|
||||||
match parameter.default {
|
if let Some(ref default) = parameter.default {
|
||||||
Some(ref default) => evaluator.evaluate_expression(default)?,
|
evaluator.evaluate_expression(default)?
|
||||||
None => {
|
} else {
|
||||||
return Err(RuntimeError::Internal {
|
return Err(RuntimeError::Internal {
|
||||||
message: "missing parameter without default".to_string(),
|
message: "missing parameter without default".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if parameter.variadic {
|
} else if parameter.variadic {
|
||||||
let value = rest.to_vec().join(" ");
|
let value = rest.to_vec().join(" ");
|
||||||
rest = &[];
|
rest = &[];
|
||||||
|
@ -109,11 +109,12 @@ fn env_var_or_default(
|
|||||||
key: &str,
|
key: &str,
|
||||||
default: &str,
|
default: &str,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
|
use std::env::VarError::*;
|
||||||
|
|
||||||
if let Some(value) = context.dotenv.get(key) {
|
if let Some(value) = context.dotenv.get(key) {
|
||||||
return Ok(value.clone());
|
return Ok(value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::env::VarError::*;
|
|
||||||
match env::var(key) {
|
match env::var(key) {
|
||||||
Err(NotPresent) => Ok(default.to_string()),
|
Err(NotPresent) => Ok(default.to_string()),
|
||||||
Err(NotUnicode(os_string)) => Err(format!(
|
Err(NotUnicode(os_string)) => Err(format!(
|
||||||
|
@ -3,9 +3,9 @@ use crate::common::*;
|
|||||||
pub(crate) struct InterruptGuard;
|
pub(crate) struct InterruptGuard;
|
||||||
|
|
||||||
impl InterruptGuard {
|
impl InterruptGuard {
|
||||||
pub(crate) fn new() -> InterruptGuard {
|
pub(crate) fn new() -> Self {
|
||||||
InterruptHandler::instance().block();
|
InterruptHandler::instance().block();
|
||||||
InterruptGuard
|
Self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ pub(crate) struct InterruptHandler {
|
|||||||
|
|
||||||
impl InterruptHandler {
|
impl InterruptHandler {
|
||||||
pub(crate) fn install() -> Result<(), ctrlc::Error> {
|
pub(crate) fn install() -> Result<(), ctrlc::Error> {
|
||||||
ctrlc::set_handler(|| InterruptHandler::instance().interrupt())
|
ctrlc::set_handler(|| Self::instance().interrupt())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn instance() -> MutexGuard<'static, InterruptHandler> {
|
pub(crate) fn instance() -> MutexGuard<'static, Self> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref INSTANCE: Mutex<InterruptHandler> = Mutex::new(InterruptHandler::new());
|
static ref INSTANCE: Mutex<InterruptHandler> = Mutex::new(InterruptHandler::new());
|
||||||
}
|
}
|
||||||
@ -29,8 +29,8 @@ impl InterruptHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> InterruptHandler {
|
fn new() -> Self {
|
||||||
InterruptHandler {
|
Self {
|
||||||
blocks: 0,
|
blocks: 0,
|
||||||
interrupted: false,
|
interrupted: false,
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ impl<'src> Justfile<'src> {
|
|||||||
arguments: &'run [String],
|
arguments: &'run [String],
|
||||||
) -> RunResult<'run, ()> {
|
) -> RunResult<'run, ()> {
|
||||||
let argvec: Vec<&str> = if !arguments.is_empty() {
|
let argvec: Vec<&str> = if !arguments.is_empty() {
|
||||||
arguments.iter().map(|argument| argument.as_str()).collect()
|
arguments.iter().map(String::as_str).collect()
|
||||||
} else if let Some(recipe) = self.first() {
|
} else if let Some(recipe) = self.first() {
|
||||||
let min_arguments = recipe.min_arguments();
|
let min_arguments = recipe.min_arguments();
|
||||||
if min_arguments > 0 {
|
if min_arguments > 0 {
|
||||||
@ -70,7 +70,7 @@ impl<'src> Justfile<'src> {
|
|||||||
let unknown_overrides = overrides
|
let unknown_overrides = overrides
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|name| !self.assignments.contains_key(name.as_str()))
|
.filter(|name| !self.assignments.contains_key(name.as_str()))
|
||||||
.map(|name| name.as_str())
|
.map(String::as_str)
|
||||||
.collect::<Vec<&str>>();
|
.collect::<Vec<&str>>();
|
||||||
|
|
||||||
if !unknown_overrides.is_empty() {
|
if !unknown_overrides.is_empty() {
|
||||||
|
17
src/lexer.rs
17
src/lexer.rs
@ -73,16 +73,12 @@ impl<'src> Lexer<'src> {
|
|||||||
let len_utf8 = c.len_utf8();
|
let len_utf8 = c.len_utf8();
|
||||||
|
|
||||||
self.token_end.offset += len_utf8;
|
self.token_end.offset += len_utf8;
|
||||||
|
self.token_end.column += len_utf8;
|
||||||
|
|
||||||
match c {
|
if c == '\n' {
|
||||||
'\n' => {
|
|
||||||
self.token_end.column = 0;
|
self.token_end.column = 0;
|
||||||
self.token_end.line += 1;
|
self.token_end.line += 1;
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
self.token_end.column += len_utf8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.next = self.chars.next();
|
self.next = self.chars.next();
|
||||||
|
|
||||||
@ -203,10 +199,7 @@ impl<'src> Lexer<'src> {
|
|||||||
CompilationError { token, kind }
|
CompilationError { token, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unterminated_interpolation_error(
|
fn unterminated_interpolation_error(interpolation_start: Token<'src>) -> CompilationError<'src> {
|
||||||
&self,
|
|
||||||
interpolation_start: Token<'src>,
|
|
||||||
) -> CompilationError<'src> {
|
|
||||||
CompilationError {
|
CompilationError {
|
||||||
token: interpolation_start,
|
token: interpolation_start,
|
||||||
kind: UnterminatedInterpolation,
|
kind: UnterminatedInterpolation,
|
||||||
@ -275,7 +268,7 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(interpolation_start) = self.interpolation_start {
|
if let Some(interpolation_start) = self.interpolation_start {
|
||||||
return Err(self.unterminated_interpolation_error(interpolation_start));
|
return Err(Self::unterminated_interpolation_error(interpolation_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
while self.indented() {
|
while self.indented() {
|
||||||
@ -486,7 +479,7 @@ impl<'src> Lexer<'src> {
|
|||||||
self.lex_double(InterpolationEnd)
|
self.lex_double(InterpolationEnd)
|
||||||
} else if self.at_eol_or_eof() {
|
} else if self.at_eol_or_eof() {
|
||||||
// Return unterminated interpolation error that highlights the opening {{
|
// Return unterminated interpolation error that highlights the opening {{
|
||||||
Err(self.unterminated_interpolation_error(interpolation_start))
|
Err(Self::unterminated_interpolation_error(interpolation_start))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise lex as per normal
|
// Otherwise lex as per normal
|
||||||
self.lex_normal(start)
|
self.lex_normal(start)
|
||||||
|
34
src/lib.rs
34
src/lib.rs
@ -1,3 +1,37 @@
|
|||||||
|
#![deny(clippy::all, clippy::pedantic, clippy::restriction)]
|
||||||
|
#![allow(
|
||||||
|
clippy::print_stdout,
|
||||||
|
clippy::else_if_without_else,
|
||||||
|
clippy::use_debug,
|
||||||
|
clippy::implicit_return,
|
||||||
|
clippy::if_not_else,
|
||||||
|
clippy::missing_docs_in_private_items,
|
||||||
|
clippy::enum_glob_use,
|
||||||
|
clippy::integer_arithmetic,
|
||||||
|
clippy::option_unwrap_used,
|
||||||
|
clippy::indexing_slicing,
|
||||||
|
clippy::non_ascii_literal,
|
||||||
|
clippy::missing_inline_in_public_items,
|
||||||
|
clippy::option_expect_used,
|
||||||
|
clippy::comparison_chain,
|
||||||
|
clippy::wildcard_enum_match_arm,
|
||||||
|
clippy::too_many_lines,
|
||||||
|
clippy::shadow_unrelated,
|
||||||
|
clippy::needless_pass_by_value,
|
||||||
|
clippy::option_map_unwrap_or,
|
||||||
|
clippy::filter_map,
|
||||||
|
clippy::result_expect_used,
|
||||||
|
clippy::unreachable,
|
||||||
|
clippy::string_add,
|
||||||
|
clippy::panic,
|
||||||
|
clippy::match_same_arms
|
||||||
|
)]
|
||||||
|
// clippy::option_map_unwrap_or_else,
|
||||||
|
// clippy::result_expect_used,
|
||||||
|
// clippy::result_unwrap_used,
|
||||||
|
// clippy::unreachable
|
||||||
|
// )]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// `Self` cannot be used where type takes generic arguments
|
||||||
|
#![allow(clippy::use_self)]
|
||||||
|
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
|
pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
|
||||||
@ -70,7 +73,7 @@ impl<T: Display, I: Iterator<Item = T> + Clone> Display for List<T, I> {
|
|||||||
write!(f, ", {} {}", self.conjunction, c)?;
|
write!(f, ", {} {}", self.conjunction, c)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => panic!("Iterator was fused, but returned Some after None"),
|
_ => unreachable!("Iterator was fused, but returned Some after None"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,11 @@ pub(crate) enum OutputError {
|
|||||||
impl Display for OutputError {
|
impl Display for OutputError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
match *self {
|
match *self {
|
||||||
OutputError::Code(code) => write!(f, "Process exited with status code {}", code),
|
Self::Code(code) => write!(f, "Process exited with status code {}", code),
|
||||||
OutputError::Io(ref io_error) => write!(f, "Error executing process: {}", io_error),
|
Self::Io(ref io_error) => write!(f, "Error executing process: {}", io_error),
|
||||||
OutputError::Signal(signal) => write!(f, "Process terminated by signal {}", signal),
|
Self::Signal(signal) => write!(f, "Process terminated by signal {}", signal),
|
||||||
OutputError::Unknown => write!(f, "Process experienced an unknown failure"),
|
Self::Unknown => write!(f, "Process experienced an unknown failure"),
|
||||||
OutputError::Utf8(ref err) => write!(f, "Could not convert process stdout to UTF-8: {}", err),
|
Self::Utf8(ref err) => write!(f, "Could not convert process stdout to UTF-8: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use crate::common::*;
|
|||||||
///
|
///
|
||||||
/// - Overrides are of the form `NAME=.*`
|
/// - Overrides are of the form `NAME=.*`
|
||||||
///
|
///
|
||||||
/// - After overrides comes a single optional search_directory argument.
|
/// - After overrides comes a single optional search directory argument.
|
||||||
/// This is either '.', '..', or an argument that contains a `/`.
|
/// This is either '.', '..', or an argument that contains a `/`.
|
||||||
///
|
///
|
||||||
/// If the argument contains a `/`, everything before and including
|
/// If the argument contains a `/`, everything before and including
|
||||||
@ -40,9 +40,7 @@ pub struct Positional {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Positional {
|
impl Positional {
|
||||||
pub fn from_values<'values>(
|
pub fn from_values<'values>(values: Option<impl IntoIterator<Item = &'values str>>) -> Self {
|
||||||
values: Option<impl IntoIterator<Item = &'values str>>,
|
|
||||||
) -> Positional {
|
|
||||||
let mut overrides = Vec::new();
|
let mut overrides = Vec::new();
|
||||||
let mut search_directory = None;
|
let mut search_directory = None;
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
@ -71,7 +69,7 @@ impl Positional {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Positional {
|
Self {
|
||||||
overrides,
|
overrides,
|
||||||
search_directory,
|
search_directory,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -50,7 +50,7 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
|
|
||||||
pub(crate) fn max_arguments(&self) -> usize {
|
pub(crate) fn max_arguments(&self) -> usize {
|
||||||
if self.parameters.iter().any(|p| p.variadic) {
|
if self.parameters.iter().any(|p| p.variadic) {
|
||||||
usize::MAX - 1
|
usize::max_value() - 1
|
||||||
} else {
|
} else {
|
||||||
self.parameters.len()
|
self.parameters.len()
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
|||||||
recipe: UnresolvedRecipe<'src>,
|
recipe: UnresolvedRecipe<'src>,
|
||||||
) -> CompilationResult<'src, Rc<Recipe<'src>>> {
|
) -> CompilationResult<'src, Rc<Recipe<'src>>> {
|
||||||
if let Some(resolved) = self.resolved_recipes.get(recipe.name()) {
|
if let Some(resolved) = self.resolved_recipes.get(recipe.name()) {
|
||||||
return Ok(resolved.clone());
|
return Ok(Rc::clone(resolved));
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push(recipe.name());
|
stack.push(recipe.name());
|
||||||
@ -87,7 +87,7 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
|||||||
|
|
||||||
if let Some(resolved) = self.resolved_recipes.get(name) {
|
if let Some(resolved) = self.resolved_recipes.get(name) {
|
||||||
// dependency already resolved
|
// dependency already resolved
|
||||||
dependencies.push(resolved.clone());
|
dependencies.push(Rc::clone(&resolved));
|
||||||
} else if stack.contains(&name) {
|
} else if stack.contains(&name) {
|
||||||
let first = stack[0];
|
let first = stack[0];
|
||||||
stack.push(first);
|
stack.push(first);
|
||||||
@ -114,7 +114,7 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resolved = Rc::new(recipe.resolve(dependencies)?);
|
let resolved = Rc::new(recipe.resolve(dependencies)?);
|
||||||
self.resolved_recipes.insert(resolved.clone());
|
self.resolved_recipes.insert(Rc::clone(&resolved));
|
||||||
stack.pop();
|
stack.pop();
|
||||||
Ok(resolved)
|
Ok(resolved)
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,8 @@ pub(crate) enum RuntimeError<'src> {
|
|||||||
impl<'src> Error for RuntimeError<'src> {
|
impl<'src> Error for RuntimeError<'src> {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match *self {
|
match *self {
|
||||||
Self::Code { code, .. } => code,
|
Self::Code { code, .. }
|
||||||
Self::Backtick {
|
| Self::Backtick {
|
||||||
output_error: OutputError::Code(code),
|
output_error: OutputError::Code(code),
|
||||||
..
|
..
|
||||||
} => code,
|
} => code,
|
||||||
|
@ -14,14 +14,14 @@ impl Search {
|
|||||||
pub(crate) fn find(
|
pub(crate) fn find(
|
||||||
search_config: &SearchConfig,
|
search_config: &SearchConfig,
|
||||||
invocation_directory: &Path,
|
invocation_directory: &Path,
|
||||||
) -> SearchResult<Search> {
|
) -> SearchResult<Self> {
|
||||||
match search_config {
|
match search_config {
|
||||||
SearchConfig::FromInvocationDirectory => {
|
SearchConfig::FromInvocationDirectory => {
|
||||||
let justfile = Self::justfile(&invocation_directory)?;
|
let justfile = Self::justfile(&invocation_directory)?;
|
||||||
|
|
||||||
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -34,7 +34,7 @@ impl Search {
|
|||||||
|
|
||||||
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -45,7 +45,7 @@ impl Search {
|
|||||||
|
|
||||||
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -54,7 +54,7 @@ impl Search {
|
|||||||
SearchConfig::WithJustfileAndWorkingDirectory {
|
SearchConfig::WithJustfileAndWorkingDirectory {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
} => Ok(Search {
|
} => Ok(Self {
|
||||||
justfile: Self::clean(invocation_directory, justfile),
|
justfile: Self::clean(invocation_directory, justfile),
|
||||||
working_directory: Self::clean(invocation_directory, working_directory),
|
working_directory: Self::clean(invocation_directory, working_directory),
|
||||||
}),
|
}),
|
||||||
@ -64,14 +64,14 @@ impl Search {
|
|||||||
pub(crate) fn init(
|
pub(crate) fn init(
|
||||||
search_config: &SearchConfig,
|
search_config: &SearchConfig,
|
||||||
invocation_directory: &Path,
|
invocation_directory: &Path,
|
||||||
) -> SearchResult<Search> {
|
) -> SearchResult<Self> {
|
||||||
match search_config {
|
match search_config {
|
||||||
SearchConfig::FromInvocationDirectory => {
|
SearchConfig::FromInvocationDirectory => {
|
||||||
let working_directory = Self::project_root(&invocation_directory)?;
|
let working_directory = Self::project_root(&invocation_directory)?;
|
||||||
|
|
||||||
let justfile = working_directory.join(FILENAME);
|
let justfile = working_directory.join(FILENAME);
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -84,7 +84,7 @@ impl Search {
|
|||||||
|
|
||||||
let justfile = working_directory.join(FILENAME);
|
let justfile = working_directory.join(FILENAME);
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -95,7 +95,7 @@ impl Search {
|
|||||||
|
|
||||||
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
let working_directory = Self::working_directory_from_justfile(&justfile)?;
|
||||||
|
|
||||||
Ok(Search {
|
Ok(Self {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
})
|
})
|
||||||
@ -104,7 +104,7 @@ impl Search {
|
|||||||
SearchConfig::WithJustfileAndWorkingDirectory {
|
SearchConfig::WithJustfileAndWorkingDirectory {
|
||||||
justfile,
|
justfile,
|
||||||
working_directory,
|
working_directory,
|
||||||
} => Ok(Search {
|
} => Ok(Self {
|
||||||
justfile: Self::clean(invocation_directory, justfile),
|
justfile: Self::clean(invocation_directory, justfile),
|
||||||
working_directory: Self::clean(invocation_directory, working_directory),
|
working_directory: Self::clean(invocation_directory, working_directory),
|
||||||
}),
|
}),
|
||||||
|
@ -85,6 +85,7 @@ impl<'table, V: Keyed<'table> + 'table> IntoIterator for &'table Table<'table, V
|
|||||||
type Item = (&'table &'table str, &'table V);
|
type Item = (&'table &'table str, &'table V);
|
||||||
type IntoIter = btree_map::Iter<'table, &'table str, V>;
|
type IntoIter = btree_map::Iter<'table, &'table str, V>;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn into_iter(self) -> btree_map::Iter<'table, &'table str, V> {
|
fn into_iter(self) -> btree_map::Iter<'table, &'table str, V> {
|
||||||
self.map.iter()
|
self.map.iter()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ pub(crate) enum Verbosity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Verbosity {
|
impl Verbosity {
|
||||||
pub(crate) fn from_flag_occurrences(flag_occurences: u64) -> Verbosity {
|
pub(crate) fn from_flag_occurrences(flag_occurences: u64) -> Self {
|
||||||
match flag_occurences {
|
match flag_occurences {
|
||||||
0 => Taciturn,
|
0 => Taciturn,
|
||||||
1 => Loquacious,
|
1 => Loquacious,
|
||||||
@ -19,15 +19,13 @@ impl Verbosity {
|
|||||||
pub(crate) fn loquacious(self) -> bool {
|
pub(crate) fn loquacious(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Taciturn => false,
|
Taciturn => false,
|
||||||
Loquacious => true,
|
Loquacious | Grandiloquent => true,
|
||||||
Grandiloquent => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn grandiloquent(self) -> bool {
|
pub(crate) fn grandiloquent(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Taciturn => false,
|
Taciturn | Loquacious => false,
|
||||||
Loquacious => false,
|
|
||||||
Grandiloquent => true,
|
Grandiloquent => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user