Skip to content

Commit

Permalink
[fud2] Implement Shell Commands With Dependencies (#2224)
Browse files Browse the repository at this point in the history
Implements shell commands with dependencies. This has been split off
from the origin PR for ease of review.
  • Loading branch information
jku20 authored Aug 6, 2024
1 parent 2a4184b commit 0d578c7
Show file tree
Hide file tree
Showing 17 changed files with 532 additions and 74 deletions.
65 changes: 46 additions & 19 deletions fud2/fud-core/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,36 @@ impl EmitBuild for EmitBuildFn {
pub enum ConfigVar {
/// The key for the config variable.
Required(String),

/// The key for the config variable followed by the value it should be if the key is not found.
Optional(String, String),
}

/// The data required to emit a single, simple op whose body is composed of an ordered set of
/// commands.
/// A shell command tagged with required and generated files.
#[derive(Debug, Clone)]
pub struct Rule {
/// A shell command.
pub cmd: String,

/// Files required by the command.
pub deps: Vec<String>,

/// Files generated by the command.
pub gens: Vec<String>,
}

/// The data required to emit a single op.
pub struct RulesOp {
/// The name of the rule generated.
pub rule_name: String,
/// The name of the op.
pub op_name: String,

/// The shell commands emitted by to the generated rule.
/// Each of these must be run in order in a context where the variables in each cmd are
/// supplied. In particular, this means that variables of the form "$[i|o]<digit>" are in
/// scope.
pub cmds: Vec<String>,
/// The commands run whenever the op run. Each of these must be run in order in a context where
/// the variables in each cmd are supplied. In particular, this means that variables of the
/// form "$[i|o]<digit>" are in scope.
///
/// The second and third element of the tuple is a list of the indices of other commands the
/// command depends on.
pub cmds: Vec<Rule>,

/// Variables to be emitted
pub config_vars: Vec<ConfigVar>,
Expand All @@ -129,9 +144,7 @@ impl EmitBuild for RulesOp {
inputs: &[&str],
outputs: &[&str],
) -> EmitResult {
// Write the Ninja file.
let cmd = self.cmds.join(" && ");
emitter.rule(&self.rule_name, &cmd)?;
// Collect variables into ninja variables.
let in_vars = inputs
.iter()
.enumerate()
Expand All @@ -149,13 +162,27 @@ impl EmitBuild for RulesOp {
}
}

emitter.build_cmd_with_args(
outputs,
&self.rule_name,
inputs,
&[],
&vars,
)?;
// Write a sequence of rules and build statements for each cmd.
for (i, cmd) in self.cmds.iter().enumerate() {
// Don't need to output commands which never generate any outputs as these commands
// would never be run.
if cmd.gens.is_empty() {
continue;
}

let rule_name = format!("{}_rule_{}", self.op_name, i + 1);
emitter.rule(&rule_name, &cmd.cmd)?;
let targets = cmd.gens.iter().map(|s| s.as_str()).collect_vec();
let deps = cmd.deps.iter().map(|s| s.as_str()).collect_vec();
emitter.build_cmd_with_args(
&targets,
&rule_name,
&deps,
&[],
&vars,
)?;
}

Ok(())
}
}
Expand Down
57 changes: 57 additions & 0 deletions fud2/fud-core/src/script/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ pub(super) enum RhaiSystemErrorKind {
StateRef(String),
BeganOp(String, String),
NoOp,
NoDep(String),
DupTarget(String),

/// The string is the type name of non-string value.
ExpectedString(String),
ExpectedShell,
ExpectedShellDeps,
}

impl RhaiSystemError {
Expand Down Expand Up @@ -48,6 +55,41 @@ impl RhaiSystemError {
}
}

pub(super) fn no_dep(dep: &str) -> Self {
Self {
kind: RhaiSystemErrorKind::NoDep(dep.to_string()),
position: rhai::Position::NONE,
}
}

pub(super) fn expected_string(v: &str) -> Self {
Self {
kind: RhaiSystemErrorKind::ExpectedString(v.to_string()),
position: rhai::Position::NONE,
}
}

pub(super) fn dup_target(target: &str) -> Self {
Self {
kind: RhaiSystemErrorKind::DupTarget(target.to_string()),
position: rhai::Position::NONE,
}
}

pub(super) fn expected_shell() -> Self {
Self {
kind: RhaiSystemErrorKind::ExpectedShell,
position: rhai::Position::NONE,
}
}

pub(super) fn expected_shell_deps() -> Self {
Self {
kind: RhaiSystemErrorKind::ExpectedShellDeps,
position: rhai::Position::NONE,
}
}

pub(super) fn with_pos(mut self, p: rhai::Position) -> Self {
self.position = p;
self
Expand All @@ -69,6 +111,21 @@ impl Display for RhaiSystemError {
RhaiSystemErrorKind::NoOp => {
write!(f, "Unable to find current op being built. Consider calling start_op_stmts earlier in the program.")
}
RhaiSystemErrorKind::NoDep(dep) => {
write!(f, "Unable to find dep: `{dep:?}`. A call to `shell` with `{dep:?}` as an output must occur prior to this call.")
}
RhaiSystemErrorKind::ExpectedString(v) => {
write!(f, "Expected string, got: `{v:?}`.")
}
RhaiSystemErrorKind::DupTarget(target) => {
write!(f, "Duplicate target: `{target:?}`. Consider removing a shell command generating `{target:?}`.")
}
RhaiSystemErrorKind::ExpectedShell => {
write!(f, "Expected `shell`, got `shell_deps`. Ops may contain only one of `shell` or `shell_deps` calls, not calls to both")
}
RhaiSystemErrorKind::ExpectedShellDeps => {
write!(f, "Expected `shell_deps`, got shell. Ops may contain only one of `shell` or `shell_deps` calls, not calls to both")
}
}
}
}
Expand Down
Loading

0 comments on commit 0d578c7

Please sign in to comment.