1
0
mirror of https://github.com/casey/just synced 2024-06-29 06:24:38 +00:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Marcin Drzymala
fac177559a
Merge 95d51ab933 into 570d3058cf 2024-06-25 23:36:56 +00:00
Marcin Drzymala
95d51ab933 WIP: Add JustfileKind to Search: Path or Stdin 2024-06-26 01:36:11 +02:00
Marcin Drzymala
2964a62542 Add WithStdin variants to SearchConfig 2024-06-26 01:36:11 +02:00
Casey Rodarmor
570d3058cf
Link to modules when first introduced in readme (#2193) 2024-06-25 21:59:42 +00:00
dependabot[bot]
c900b6f478
Update softprops/action-gh-release (#2183) 2024-06-24 12:42:39 -07:00
Casey Rodarmor
af86a471e2
Don't analyze comments when ignore-comments is set (#2180) 2024-06-21 20:39:34 +00:00
9 changed files with 239 additions and 35 deletions

View File

@ -95,7 +95,7 @@ jobs:
shell: bash
- name: Publish Archive
uses: softprops/action-gh-release@v2.0.5
uses: softprops/action-gh-release@v2.0.6
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
draft: false
@ -105,7 +105,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Changelog
uses: softprops/action-gh-release@v2.0.5
uses: softprops/action-gh-release@v2.0.6
if: >-
${{
startsWith(github.ref, 'refs/tags/')

View File

@ -656,8 +656,8 @@ Available recipes:
lint
```
Recipes in submodules can be listed with `just --list PATH`, where `PATH` is a
space- or `::`-separated module path:
Recipes in [submodules](#modules1190) can be listed with `just --list PATH`,
where `PATH` is a space- or `::`-separated module path:
```
$ cat justfile
@ -3145,7 +3145,7 @@ import? 'foo/bar.just'
Missing source files for optional imports do not produce an error.
### Modules <sup>1.19.0</sup>
### Modules<sup>1.19.0</sup>
A `justfile` can declare modules using `mod` statements. `mod` statements are
currently unstable, so you'll need to use the `--unstable` flag, or set the

View File

@ -149,7 +149,7 @@ impl<'src> Analyzer<'src> {
}
}
let recipes = RecipeResolver::resolve_recipes(recipe_table, &self.assignments)?;
let recipes = RecipeResolver::resolve_recipes(&self.assignments, &settings, recipe_table)?;
let mut aliases = Table::new();
while let Some(alias) = self.aliases.pop() {

View File

@ -1482,6 +1482,22 @@ mod tests {
},
}
test! {
name: search_config_from_working_directory_and_justfile_long_stdin,
args: ["--working-directory", "foo", "--justfile", "-"],
search_config: SearchConfig::WithStdinAndWorkingDirectory {
working_directory: PathBuf::from("foo"),
},
}
test! {
name: search_config_from_working_directory_and_justfile_short_stdin,
args: ["--working-directory", "foo", "-f", "-"],
search_config: SearchConfig::WithStdinAndWorkingDirectory {
working_directory: PathBuf::from("foo"),
},
}
test! {
name: search_config_justfile_long,
args: ["--justfile", "foo"],
@ -1490,6 +1506,12 @@ mod tests {
},
}
test! {
name: search_config_justfile_long_stdin,
args: ["--justfile", "-"],
search_config: SearchConfig::WithStdin,
}
test! {
name: search_config_justfile_short,
args: ["-f", "foo"],
@ -1498,6 +1520,12 @@ mod tests {
},
}
test! {
name: search_config_justfile_short_stdin,
args: ["-f", "-"],
search_config: SearchConfig::WithStdin,
}
test! {
name: search_directory_parent,
args: ["../"],

View File

@ -8,8 +8,9 @@ pub(crate) struct RecipeResolver<'src: 'run, 'run> {
impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
pub(crate) fn resolve_recipes(
unresolved_recipes: Table<'src, UnresolvedRecipe<'src>>,
assignments: &'run Table<'src, Assignment<'src>>,
settings: &Settings,
unresolved_recipes: Table<'src, UnresolvedRecipe<'src>>,
) -> CompileResult<'src, Table<'src, Rc<Recipe<'src>>>> {
let mut resolver = Self {
resolved_recipes: Table::new(),
@ -39,6 +40,10 @@ impl<'src: 'run, 'run> RecipeResolver<'src, 'run> {
}
for line in &recipe.body {
if line.is_comment() && settings.ignore_comments {
continue;
}
for fragment in &line.fragments {
if let Fragment::Interpolation { expression, .. } = fragment {
for variable in expression.variables() {

View File

@ -1,14 +1,58 @@
use {super::*, std::path::Component};
use {
super::*,
std::{
io::{stdin, Read},
path::{Component, Display},
},
};
const DEFAULT_JUSTFILE_NAME: &str = JUSTFILE_NAMES[0];
pub(crate) const JUSTFILE_NAMES: [&str; 2] = ["justfile", ".justfile"];
const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"];
pub(crate) struct Search {
pub(crate) justfile: PathBuf,
pub(crate) justfile: JustfileKind,
pub(crate) working_directory: PathBuf,
}
#[derive(Debug, Clone)]
pub enum JustfileKind {
Path { path: PathBuf },
Stdin { data: String },
}
impl JustfileKind {
pub fn to_str(&self) -> Option<&str> {
match self {
JustfileKind::Path { path } => path.to_str(),
JustfileKind::Stdin { .. } => None,
}
}
pub fn display(&self) -> Display<'_> {
match self {
JustfileKind::Path { path } => path.display(),
JustfileKind::Stdin { .. } => Path::new("<STDIN>").display(),
}
}
pub fn parent(&self) -> Option<&Path> {
match self {
JustfileKind::Path { path } => path.parent(),
JustfileKind::Stdin { .. } => None,
}
}
}
impl PartialEq<PathBuf> for JustfileKind {
fn eq(&self, other: &PathBuf) -> bool {
match self {
JustfileKind::Path { path } => path == other,
JustfileKind::Stdin { .. } => false,
}
}
}
impl Search {
fn global_justfile_paths() -> Vec<PathBuf> {
let mut paths = Vec::new();
@ -33,6 +77,7 @@ impl Search {
paths
}
/// Search for a Justfile
pub(crate) fn find(
search_config: &SearchConfig,
invocation_directory: &Path,
@ -41,24 +86,29 @@ impl Search {
SearchConfig::FromInvocationDirectory => Self::find_next(invocation_directory),
SearchConfig::FromSearchDirectory { search_directory } => {
let search_directory = Self::clean(invocation_directory, search_directory);
let justfile = Self::justfile(&search_directory)?;
let working_directory = Self::working_directory_from_justfile(&justfile)?;
let path = Self::justfile(&search_directory)?;
let working_directory = Self::working_directory_from_justfile(&path)?;
let justfile = JustfileKind::Path { path: path.clone() };
Ok(Self {
justfile,
working_directory,
})
}
SearchConfig::GlobalJustfile => Ok(Self {
justfile: Self::global_justfile_paths()
SearchConfig::GlobalJustfile => {
let path = Self::global_justfile_paths()
.iter()
.find(|path| path.exists())
.cloned()
.ok_or(SearchError::GlobalJustfileNotFound)?,
working_directory: Self::project_root(invocation_directory)?,
}),
.ok_or(SearchError::GlobalJustfileNotFound)?;
Ok(Self {
justfile: JustfileKind::Path { path },
working_directory: Self::project_root(invocation_directory)?,
})
}
SearchConfig::WithJustfile { justfile } => {
let justfile = Self::clean(invocation_directory, justfile);
let working_directory = Self::working_directory_from_justfile(&justfile)?;
let path = Self::clean(invocation_directory, justfile);
let justfile = JustfileKind::Path { path: path.clone() };
let working_directory = Self::working_directory_from_justfile(&path)?;
Ok(Self {
justfile,
working_directory,
@ -67,22 +117,58 @@ impl Search {
SearchConfig::WithJustfileAndWorkingDirectory {
justfile,
working_directory,
} => Ok(Self {
justfile: Self::clean(invocation_directory, justfile),
working_directory: Self::clean(invocation_directory, working_directory),
}),
} => {
let path = Self::clean(invocation_directory, justfile);
let justfile = JustfileKind::Path { path };
Ok(Self {
justfile,
working_directory: Self::clean(invocation_directory, working_directory),
})
}
SearchConfig::WithStdin => {
let working_directory = PathBuf::from(invocation_directory);
let mut data = String::new();
if let Err(err) = stdin().read_to_string(&mut data) {
return Err(SearchError::Io {
directory: working_directory,
io_error: err,
});
}
let justfile = JustfileKind::Stdin { data };
Ok(Self {
justfile,
working_directory,
})
}
SearchConfig::WithStdinAndWorkingDirectory { working_directory } => {
let working_directory = working_directory.to_owned();
let mut data = String::new();
if let Err(err) = stdin().read_to_string(&mut data) {
return Err(SearchError::Io {
directory: working_directory,
io_error: err,
});
}
let justfile = JustfileKind::Stdin { data };
Ok(Self {
justfile,
working_directory,
})
}
}
}
pub(crate) fn find_next(starting_dir: &Path) -> SearchResult<Self> {
let justfile = Self::justfile(starting_dir)?;
let working_directory = Self::working_directory_from_justfile(&justfile)?;
let path = Self::justfile(starting_dir)?;
let justfile = JustfileKind::Path { path: path.clone() };
let working_directory = Self::working_directory_from_justfile(&path)?;
Ok(Self {
justfile,
working_directory,
})
}
/// Search for a Justfile when running "init" subcommand
pub(crate) fn init(
search_config: &SearchConfig,
invocation_directory: &Path,
@ -90,7 +176,8 @@ impl Search {
match search_config {
SearchConfig::FromInvocationDirectory => {
let working_directory = Self::project_root(invocation_directory)?;
let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME);
let path = working_directory.join(DEFAULT_JUSTFILE_NAME);
let justfile = JustfileKind::Path { path };
Ok(Self {
justfile,
working_directory,
@ -99,7 +186,8 @@ impl Search {
SearchConfig::FromSearchDirectory { search_directory } => {
let search_directory = Self::clean(invocation_directory, search_directory);
let working_directory = Self::project_root(&search_directory)?;
let justfile = working_directory.join(DEFAULT_JUSTFILE_NAME);
let path = working_directory.join(DEFAULT_JUSTFILE_NAME);
let justfile = JustfileKind::Path { path };
Ok(Self {
justfile,
working_directory,
@ -107,8 +195,9 @@ impl Search {
}
SearchConfig::GlobalJustfile => Err(SearchError::GlobalJustfileInit),
SearchConfig::WithJustfile { justfile } => {
let justfile = Self::clean(invocation_directory, justfile);
let working_directory = Self::working_directory_from_justfile(&justfile)?;
let path = Self::clean(invocation_directory, justfile);
let working_directory = Self::working_directory_from_justfile(&path)?;
let justfile = JustfileKind::Path { path };
Ok(Self {
justfile,
working_directory,
@ -117,14 +206,51 @@ impl Search {
SearchConfig::WithJustfileAndWorkingDirectory {
justfile,
working_directory,
} => Ok(Self {
justfile: Self::clean(invocation_directory, justfile),
working_directory: Self::clean(invocation_directory, working_directory),
}),
} => {
let path = Self::clean(invocation_directory, justfile);
let justfile = JustfileKind::Path { path };
let working_directory = Self::clean(invocation_directory, working_directory);
Ok(Self {
justfile,
working_directory,
})
}
SearchConfig::WithStdin => {
let working_directory = Self::project_root(invocation_directory)?;
let mut data = String::new();
if let Err(err) = io::stdin().read_to_string(&mut data) {
return Err(SearchError::Io {
directory: working_directory,
io_error: err,
});
}
let justfile = JustfileKind::Stdin { data };
Ok(Self {
justfile,
working_directory,
})
}
SearchConfig::WithStdinAndWorkingDirectory { working_directory } => {
let working_directory = working_directory.to_owned();
let mut data = String::new();
if let Err(err) = io::stdin().read_to_string(&mut data) {
return Err(SearchError::Io {
directory: working_directory,
io_error: err,
});
}
let justfile = JustfileKind::Stdin { data };
Ok(Self {
justfile,
working_directory,
})
}
}
}
pub(crate) fn justfile(directory: &Path) -> SearchResult<PathBuf> {
fn justfile(directory: &Path) -> SearchResult<PathBuf> {
for directory in directory.ancestors() {
let mut candidates = BTreeSet::new();

View File

@ -19,4 +19,10 @@ pub(crate) enum SearchConfig {
justfile: PathBuf,
working_directory: PathBuf,
},
/// Use justfile loaded from stdin by using "-" as justfile name.
WithStdin,
/// Use justfile loaded from stdin and working directory.
WithStdinAndWorkingDirectory {
working_directory: PathBuf,
},
}

View File

@ -1,4 +1,4 @@
use {super::*, pretty_assertions::assert_eq};
use {self::search::JustfileKind, super::*, pretty_assertions::assert_eq};
pub(crate) fn compile(src: &str) -> Justfile {
Compiler::test_compile(src).expect("expected successful compilation")
@ -17,7 +17,8 @@ pub(crate) fn config(args: &[&str]) -> Config {
pub(crate) fn search(config: &Config) -> Search {
let working_directory = config.invocation_directory.clone();
let justfile = working_directory.join("justfile");
let path = working_directory.join("justfile");
let justfile = JustfileKind::Path { path };
Search {
justfile,

View File

@ -97,3 +97,41 @@ fn dont_evaluate_comments() {
)
.run();
}
#[test]
fn dont_analyze_comments() {
Test::new()
.justfile(
"
set ignore-comments
some_recipe:
# {{ bar }}
",
)
.run();
}
#[test]
fn comments_still_must_be_parsable_when_ignored() {
Test::new()
.justfile(
"
set ignore-comments
some_recipe:
# {{ foo bar }}
",
)
.stderr(
"
error: Expected '}}', '(', '+', or '/', but found identifier
justfile:4:12
4 # {{ foo bar }}
^^^
",
)
.status(EXIT_FAILURE)
.run();
}