Skip to content

Commit

Permalink
feat(cli): allow tasks to require modules to be selected (#580)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaspar030 authored Dec 12, 2024
2 parents 6bcb4d5 + 5417c28 commit 54512a8
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 26 deletions.
27 changes: 24 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ tinytemplate = "1.2.1"
serde_json = { version = "1.0.133", features = ["indexmap"] }
git-cache = "0.2.3"
shellexpand = "3.1.0"
thiserror = "2.0.6"

[profile.release]
lto = "fat"
Expand Down
2 changes: 2 additions & 0 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ pub struct YamlTask {
pub cmd: Vec<String>,
pub help: Option<String>,
pub required_vars: Option<Vec<String>>,
pub required_modules: Option<Vec<String>>,
pub export: Option<Vec<StringOrMapString>>,
#[serde(default = "default_as_true")]
pub build: bool,
Expand All @@ -243,6 +244,7 @@ impl From<YamlTask> for Task {
cmd: yaml_task.cmd,
help: yaml_task.help,
required_vars: yaml_task.required_vars,
required_modules: yaml_task.required_modules,
export: yaml_task
.export
.map(|s| s.iter().map(|s| s.clone().into()).collect_vec()),
Expand Down
6 changes: 3 additions & 3 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ use super::{
nested_env,
nested_env::{Env, EnvKey, IfMissing},
ninja::{NinjaBuildBuilder, NinjaRule, NinjaRuleBuilder},
utils, Context, ContextBag, Dependency, Module, Task,
utils, Context, ContextBag, Dependency, Module, Task, TaskError,
};

#[derive(Deserialize, Serialize, Debug)]
pub struct BuildInfo {
pub binary: String,
pub builder: String,
pub tasks: IndexMap<String, Task>,
pub tasks: IndexMap<String, Result<Task, TaskError>>,
pub out: Utf8PathBuf,

#[serde(skip)]
Expand Down Expand Up @@ -972,7 +972,7 @@ fn configure_build(
global_env_flattened.insert(&out_str, outfile.to_string());
let tasks = build
.build_context
.collect_tasks(contexts, &global_env_flattened)?;
.collect_tasks(contexts, &global_env_flattened, &modules)?;

Ok(ConfigureBuildResult::Build(
BuildInfo {
Expand Down
37 changes: 31 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ mod serde_bool_helpers;
mod task_runner;
mod utils;

use model::{Context, ContextBag, Dependency, Module, Rule, Task};
use model::{Context, ContextBag, Dependency, Module, Rule, Task, TaskError};

use generate::{get_ninja_build_file, BuildInfo, GenerateMode, GeneratorBuilder, Selector};
use nested_env::{Env, MergeOption};
Expand Down Expand Up @@ -358,7 +358,30 @@ fn try_main() -> Result<i32> {
})
.collect();

if builds.is_empty() {
if !builds
.iter()
.any(|build_info| build_info.tasks.iter().any(|t| t.1.is_ok() && t.0 == task))
{
let mut not_available = 0;
for b in builds {
for t in &b.tasks {
if t.1.is_err() && t.0 == task {
not_available += 1;
if verbose > 0 {
eprintln!(
"laze: warn: task \"{task}\" for binary \"{}\" on builder \"{}\": {}",
b.binary,
b.builder,
t.1.as_ref().err().unwrap()
);
}
}
}
}

if not_available > 0 && verbose == 0 {
println!("laze hint: {not_available} target(s) not available, try `--verbose` to list why");
}
return Err(anyhow!("no matching target for task \"{}\" found.", task));
}

Expand All @@ -382,11 +405,13 @@ fn try_main() -> Result<i32> {

for build in builds {
let task = build.tasks.get(task).unwrap();
if task.build_app() {
let build_target = build.out.clone();
ninja_targets.push(build_target);
if let Ok(task) = task {
if task.build_app() {
let build_target = build.out.clone();
ninja_targets.push(build_target);
}
targets.push((build, task));
}
targets.push((build, task));
}

if !ninja_targets.is_empty() && !build_matches.get_flag("generate-only") {
Expand Down
35 changes: 28 additions & 7 deletions src/model/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use camino::Utf8PathBuf;

use crate::Env;
use crate::MergeOption;
use crate::{ContextBag, Module, Rule, Task};
use crate::{ContextBag, Module, Rule, Task, TaskError};

#[derive(Eq)]
pub struct Context {
Expand Down Expand Up @@ -149,22 +149,43 @@ impl Context {
&self,
contexts: &ContextBag,
env: &im::HashMap<&String, String>,
) -> Result<IndexMap<String, Task>, Error> {
modules: &IndexMap<&String, (&Module, Env, std::option::Option<IndexSet<&Module>>)>,
) -> Result<IndexMap<String, Result<Task, TaskError>>, Error> {
let mut result = IndexMap::new();
let mut parents = Vec::new();
self.get_parents(contexts, &mut parents);
for parent in parents {
if let Some(tasks) = &parent.tasks {
for (name, task) in tasks {
'tasks: for (name, task) in tasks {
if let Some(required_vars) = &task.required_vars {
if required_vars.iter().any(|x| !env.contains_key(x)) {
continue;
for var in required_vars {
if !env.contains_key(var) {
result.insert(
name.clone(),
Err(TaskError::RequiredVarMissing { var: var.clone() }),
);
continue 'tasks;
}
}
}
if let Some(required_modules) = &task.required_modules {
for module in required_modules {
if !modules.contains_key(module) {
result.insert(
name.clone(),
Err(TaskError::RequiredModuleMissing {
module: module.clone(),
}),
);
continue 'tasks;
}
}
}
result.insert(
name.clone(),
task.with_env_eval(env)
.with_context(|| format!("task \"{}\"", name))?,
Ok(task
.with_env_eval(env)
.with_context(|| format!("task \"{}\"", name))?),
);
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ pub use context_bag::{ContextBag, IsAncestor};
pub use dependency::Dependency;
pub use module::{CustomBuild, Module};
pub use rule::Rule;
pub use task::Task;
pub use task::VarExportSpec;
pub use task::{Task, TaskError, VarExportSpec};
17 changes: 12 additions & 5 deletions src/model/task.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
use std::path::Path;

use anyhow::{Error, Result};
use thiserror::Error;

use crate::nested_env;
use crate::serde_bool_helpers::{default_as_false, default_as_true};
use crate::IGNORE_SIGINT;

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
#[serde(deny_unknown_fields)]
pub struct Task {
pub cmd: Vec<String>,
pub help: Option<String>,
pub required_vars: Option<Vec<String>>,
pub required_modules: Option<Vec<String>>,
pub export: Option<Vec<VarExportSpec>>,
#[serde(default = "default_as_true")]
pub build: bool,
#[serde(default = "default_as_false")]
pub ignore_ctrl_c: bool,
}

#[derive(Error, Debug, Serialize, Deserialize)]
pub enum TaskError {
#[error("required variable `{var}` not set")]
RequiredVarMissing { var: String },
#[error("required module `{module}` not selected")]
RequiredModuleMissing { module: String },
}

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct VarExportSpec {
pub variable: String,
Expand Down Expand Up @@ -101,8 +111,6 @@ impl Task {

fn _with_env(&self, env: &im::HashMap<&String, String>, do_eval: bool) -> Result<Task, Error> {
Ok(Task {
help: self.help.clone(),
build: self.build,
cmd: self
.cmd
.iter()
Expand All @@ -114,13 +122,12 @@ impl Task {
}
})
.collect::<Result<Vec<String>, _>>()?,
ignore_ctrl_c: self.ignore_ctrl_c,
required_vars: self.required_vars.clone(),
export: if do_eval {
self.expand_export(env)
} else {
self.export.clone()
},
..(*self).clone()
})
}

Expand Down

0 comments on commit 54512a8

Please sign in to comment.