Add justfile summaries (#399)
Exposes an interface for producing a summary that captures the important details of the parsed justfile.
This commit is contained in:
parent
e118051a5c
commit
12f9428695
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -127,7 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.5.13"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -182,7 +182,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.7.11"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -200,9 +200,9 @@ dependencies = [
|
||||
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"executable-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -504,14 +504,14 @@ dependencies = [
|
||||
"checksum dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d0a1279c96732bc6800ce6337b6a614697b0e74ae058dc03c62ebeb78b4d86"
|
||||
"checksum edit-distance 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
|
||||
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
|
||||
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
|
||||
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
||||
"checksum executable-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebc5a6d89e3c90b84e8f33c8737933dda8f1c106b5415900b38b9d433841478"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
||||
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
|
@ -9,15 +9,15 @@ readme = "crates-io-readme.md"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.11"
|
||||
ansi_term = "0.11.0"
|
||||
assert_matches = "1.1.0"
|
||||
atty = "0.2.1"
|
||||
brev = "0.1.6"
|
||||
clap = "2.0.0"
|
||||
dotenv = "0.13.0"
|
||||
edit-distance = "2.0.0"
|
||||
env_logger = "0.5.12"
|
||||
itertools = "0.7"
|
||||
env_logger = "0.6.1"
|
||||
itertools = "0.8.0"
|
||||
lazy_static = "1.0.0"
|
||||
libc = "0.2.21"
|
||||
log = "0.4.4"
|
||||
|
@ -42,3 +42,5 @@ mod token;
|
||||
mod verbosity;
|
||||
|
||||
pub use crate::run::run;
|
||||
|
||||
pub mod summary;
|
||||
|
194
src/summary.rs
Normal file
194
src/summary.rs
Normal file
@ -0,0 +1,194 @@
|
||||
//! Justfile summary creation, for testing purposes only.
|
||||
//!
|
||||
//! The contents of this module are not bound by any stability guarantees.
|
||||
//! Breaking changes may be introduced at any time.
|
||||
//!
|
||||
//! The main entry point into this module is the `summary` function, which
|
||||
//! parses a justfile at a given path and produces a `Summary` object,
|
||||
//! which broadly captures the functionality of the parsed justfile, or
|
||||
//! an error message.
|
||||
//!
|
||||
//! This functionality is intended to be used with `janus`, a tool for
|
||||
//! ensuring that changes to just do not inadvertently break or
|
||||
//! change the interpretation of existing justfiles.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fs, io,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use crate::{expression, fragment, justfile::Justfile, parser::Parser, recipe};
|
||||
|
||||
pub fn summary(path: impl AsRef<Path>) -> Result<Result<Summary, String>, io::Error> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let text = fs::read_to_string(path)?;
|
||||
|
||||
match Parser::parse(&text) {
|
||||
Ok(justfile) => Ok(Ok(Summary::new(justfile))),
|
||||
Err(compilation_error) => Ok(Err(compilation_error.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub struct Summary {
|
||||
pub assignments: BTreeMap<String, Assignment>,
|
||||
pub recipes: BTreeMap<String, Recipe>,
|
||||
}
|
||||
|
||||
impl Summary {
|
||||
fn new(justfile: Justfile) -> Summary {
|
||||
let exports = justfile.exports;
|
||||
|
||||
let mut aliases = BTreeMap::new();
|
||||
|
||||
for alias in justfile.aliases.values() {
|
||||
aliases
|
||||
.entry(alias.target)
|
||||
.or_insert(Vec::new())
|
||||
.push(alias.name.to_string());
|
||||
}
|
||||
|
||||
Summary {
|
||||
recipes: justfile
|
||||
.recipes
|
||||
.into_iter()
|
||||
.map(|(name, recipe)| {
|
||||
(
|
||||
name.to_string(),
|
||||
Recipe::new(recipe, aliases.remove(name).unwrap_or(Vec::new())),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
assignments: justfile
|
||||
.assignments
|
||||
.into_iter()
|
||||
.map(|(name, expression)| {
|
||||
(
|
||||
name.to_string(),
|
||||
Assignment::new(name, expression, &exports),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub struct Recipe {
|
||||
pub aliases: Vec<String>,
|
||||
pub dependencies: BTreeSet<String>,
|
||||
pub lines: Vec<Line>,
|
||||
pub private: bool,
|
||||
pub quiet: bool,
|
||||
pub shebang: bool,
|
||||
}
|
||||
|
||||
impl Recipe {
|
||||
fn new(recipe: recipe::Recipe, aliases: Vec<String>) -> Recipe {
|
||||
Recipe {
|
||||
private: recipe.private,
|
||||
shebang: recipe.shebang,
|
||||
quiet: recipe.quiet,
|
||||
dependencies: recipe.dependencies.into_iter().map(str::to_owned).collect(),
|
||||
lines: recipe.lines.into_iter().map(Line::new).collect(),
|
||||
aliases,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub struct Line {
|
||||
pub fragments: Vec<Fragment>,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
fn new(fragments: Vec<fragment::Fragment>) -> Line {
|
||||
Line {
|
||||
fragments: fragments.into_iter().map(Fragment::new).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub enum Fragment {
|
||||
Text { text: String },
|
||||
Expression { expression: Expression },
|
||||
}
|
||||
|
||||
impl Fragment {
|
||||
fn new(fragment: fragment::Fragment) -> Fragment {
|
||||
match fragment {
|
||||
fragment::Fragment::Text { text } => Fragment::Text {
|
||||
text: text.lexeme.to_owned(),
|
||||
},
|
||||
fragment::Fragment::Expression { expression } => Fragment::Expression {
|
||||
expression: Expression::new(expression),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub struct Assignment {
|
||||
pub exported: bool,
|
||||
pub expression: Expression,
|
||||
}
|
||||
|
||||
impl Assignment {
|
||||
fn new(name: &str, expression: expression::Expression, exports: &BTreeSet<&str>) -> Assignment {
|
||||
Assignment {
|
||||
exported: exports.contains(name),
|
||||
expression: Expression::new(expression),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug, Clone)]
|
||||
pub enum Expression {
|
||||
Backtick {
|
||||
command: String,
|
||||
},
|
||||
Call {
|
||||
name: String,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
Concatination {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
},
|
||||
String {
|
||||
text: String,
|
||||
},
|
||||
Variable {
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
fn new(expression: expression::Expression) -> Expression {
|
||||
use expression::Expression::*;
|
||||
match expression {
|
||||
Backtick { raw, .. } => Expression::Backtick {
|
||||
command: raw.to_owned(),
|
||||
},
|
||||
Call {
|
||||
name, arguments, ..
|
||||
} => Expression::Call {
|
||||
name: name.to_owned(),
|
||||
arguments: arguments.into_iter().map(Expression::new).collect(),
|
||||
},
|
||||
Concatination { lhs, rhs } => Expression::Concatination {
|
||||
lhs: Box::new(Expression::new(*lhs)),
|
||||
rhs: Box::new(Expression::new(*rhs)),
|
||||
},
|
||||
String { cooked_string } => Expression::String {
|
||||
text: cooked_string.cooked,
|
||||
},
|
||||
Variable { name, .. } => Expression::Variable {
|
||||
name: name.to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user