Add support for order-only inputs

Now actions that trigger the archive tool to be rebuilt will not cause
existing downloads/extractions to be redone.
This commit is contained in:
Damien Elmes 2023-06-15 22:08:46 +10:00
parent f70307a753
commit ffac5e0d14
2 changed files with 29 additions and 5 deletions

View file

@ -88,7 +88,7 @@ impl BuildAction for DownloadArchive {
let (_, filename) = self.archive.url.rsplit_once('/').unwrap(); let (_, filename) = self.archive.url.rsplit_once('/').unwrap();
let output_path = Utf8Path::new("download").join(filename); let output_path = Utf8Path::new("download").join(filename);
build.add_inputs("archives_bin", inputs![":build:archives"]); build.add_order_only_inputs("archives_bin", inputs![":build:archives"]);
build.add_variable("url", self.archive.url); build.add_variable("url", self.archive.url);
build.add_variable("checksum", self.archive.sha256); build.add_variable("checksum", self.archive.sha256);
build.add_outputs("out", &[output_path.into_string()]) build.add_outputs("out", &[output_path.into_string()])
@ -135,7 +135,7 @@ where
} }
fn files(&mut self, build: &mut impl crate::build::FilesHandle) { fn files(&mut self, build: &mut impl crate::build::FilesHandle) {
build.add_inputs("archive_tool", inputs![":build:archives"]); build.add_order_only_inputs("archive_tool", inputs![":build:archives"]);
build.add_inputs("in", inputs![self.archive_path.clone()]); build.add_inputs("in", inputs![self.archive_path.clone()]);
let folder = self.extraction_folder(); let folder = self.extraction_folder();

View file

@ -209,6 +209,7 @@ struct BuildStatement<'a> {
implicit_outputs: Vec<String>, implicit_outputs: Vec<String>,
explicit_inputs: Vec<String>, explicit_inputs: Vec<String>,
explicit_outputs: Vec<String>, explicit_outputs: Vec<String>,
order_only_inputs: Vec<String>,
output_subsets: Vec<(String, Vec<String>)>, output_subsets: Vec<(String, Vec<String>)>,
variables: Vec<(String, String)>, variables: Vec<(String, String)>,
rule_variables: Vec<(String, String)>, rule_variables: Vec<(String, String)>,
@ -234,6 +235,7 @@ impl BuildStatement<'_> {
implicit_outputs: Default::default(), implicit_outputs: Default::default(),
explicit_inputs: Default::default(), explicit_inputs: Default::default(),
explicit_outputs: Default::default(), explicit_outputs: Default::default(),
order_only_inputs: Default::default(),
variables: Default::default(), variables: Default::default(),
rule_variables: Default::default(), rule_variables: Default::default(),
output_subsets: Default::default(), output_subsets: Default::default(),
@ -269,8 +271,13 @@ impl BuildStatement<'_> {
let action_name = self.rule_name; let action_name = self.rule_name;
self.implicit_inputs.sort(); self.implicit_inputs.sort();
self.implicit_outputs.sort(); self.implicit_outputs.sort();
let inputs_str = to_ninja_target_string(&self.explicit_inputs, &self.implicit_inputs); let inputs_str = to_ninja_target_string(
let outputs_str = to_ninja_target_string(&self.explicit_outputs, &self.implicit_outputs); &self.explicit_inputs,
&self.implicit_inputs,
&self.order_only_inputs,
);
let outputs_str =
to_ninja_target_string(&self.explicit_outputs, &self.implicit_outputs, &[]);
writeln!(buf, "build {outputs_str}: {action_name} {inputs_str}").unwrap(); writeln!(buf, "build {outputs_str}: {action_name} {inputs_str}").unwrap();
for (key, value) in self.variables.iter().sorted() { for (key, value) in self.variables.iter().sorted() {
@ -329,6 +336,7 @@ pub trait FilesHandle {
/// this is often `in`. /// this is often `in`.
fn add_inputs(&mut self, variable: &'static str, inputs: impl AsRef<BuildInput>); fn add_inputs(&mut self, variable: &'static str, inputs: impl AsRef<BuildInput>);
fn add_inputs_vec(&mut self, variable: &'static str, inputs: Vec<String>); fn add_inputs_vec(&mut self, variable: &'static str, inputs: Vec<String>);
fn add_order_only_inputs(&mut self, variable: &'static str, inputs: impl AsRef<BuildInput>);
/// Add a variable that can be referenced in the command. /// Add a variable that can be referenced in the command.
fn add_variable(&mut self, name: impl Into<String>, value: impl Into<String>); fn add_variable(&mut self, name: impl Into<String>, value: impl Into<String>);
@ -400,6 +408,14 @@ impl FilesHandle for BuildStatement<'_> {
} }
} }
fn add_order_only_inputs(&mut self, variable: &'static str, inputs: impl AsRef<BuildInput>) {
let inputs = FilesHandle::expand_inputs(self, inputs);
if !variable.is_empty() {
self.add_variable(variable, space_separated(&inputs))
}
self.order_only_inputs.extend(inputs);
}
fn add_variable(&mut self, key: impl Into<String>, value: impl Into<String>) { fn add_variable(&mut self, key: impl Into<String>, value: impl Into<String>) {
self.variables.push((key.into(), value.into())); self.variables.push((key.into(), value.into()));
} }
@ -479,12 +495,20 @@ impl FilesHandle for BuildStatement<'_> {
} }
} }
fn to_ninja_target_string(explicit: &[String], implicit: &[String]) -> String { fn to_ninja_target_string(
explicit: &[String],
implicit: &[String],
order_only: &[String],
) -> String {
let mut joined = space_separated(explicit); let mut joined = space_separated(explicit);
if !implicit.is_empty() { if !implicit.is_empty() {
joined.push_str(" | "); joined.push_str(" | ");
joined.push_str(&space_separated(implicit)); joined.push_str(&space_separated(implicit));
} }
if !order_only.is_empty() {
joined.push_str(" || ");
joined.push_str(&space_separated(order_only));
}
joined joined
} }