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]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.5.13"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -182,7 +182,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.7.11"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"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 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 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 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 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 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 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 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 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 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 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 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"
|
"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"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.11"
|
ansi_term = "0.11.0"
|
||||||
assert_matches = "1.1.0"
|
assert_matches = "1.1.0"
|
||||||
atty = "0.2.1"
|
atty = "0.2.1"
|
||||||
brev = "0.1.6"
|
brev = "0.1.6"
|
||||||
clap = "2.0.0"
|
clap = "2.0.0"
|
||||||
dotenv = "0.13.0"
|
dotenv = "0.13.0"
|
||||||
edit-distance = "2.0.0"
|
edit-distance = "2.0.0"
|
||||||
env_logger = "0.5.12"
|
env_logger = "0.6.1"
|
||||||
itertools = "0.7"
|
itertools = "0.8.0"
|
||||||
lazy_static = "1.0.0"
|
lazy_static = "1.0.0"
|
||||||
libc = "0.2.21"
|
libc = "0.2.21"
|
||||||
log = "0.4.4"
|
log = "0.4.4"
|
||||||
|
@ -42,3 +42,5 @@ mod token;
|
|||||||
mod verbosity;
|
mod verbosity;
|
||||||
|
|
||||||
pub use crate::run::run;
|
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