aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/target.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-03-27 15:50:39 -0600
committerMelody Horn <melody@boringcactus.com>2021-03-27 15:50:39 -0600
commit028e1a631629c7f5959e522dee80188ea7534d8f (patch)
tree65aff918fdcb2999cde604a8959f2c6ec83f6f98 /src/makefile/target.rs
parent4a3bf997b83e3cf3496622ce1554c8641e6031da (diff)
downloadmakers-028e1a631629c7f5959e522dee80188ea7534d8f.tar.gz
makers-028e1a631629c7f5959e522dee80188ea7534d8f.zip
refactor makefile elements into submodules
Diffstat (limited to 'src/makefile/target.rs')
-rw-r--r--src/makefile/target.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/makefile/target.rs b/src/makefile/target.rs
new file mode 100644
index 0000000..1fbc75b
--- /dev/null
+++ b/src/makefile/target.rs
@@ -0,0 +1,77 @@
+use std::cell::Cell;
+use std::fmt;
+use std::fs::metadata;
+use std::time::SystemTime;
+
+use crate::makefile::command_line::CommandLine;
+
+use super::Makefile;
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct Target {
+ pub name: String,
+ pub prerequisites: Vec<String>,
+ pub commands: Vec<CommandLine>,
+ pub already_updated: Cell<bool>,
+}
+
+impl Target {
+ fn modified_time(&self) -> Option<SystemTime> {
+ metadata(&self.name)
+ .and_then(|metadata| metadata.modified())
+ .ok()
+ }
+
+ pub fn newer_than(&self, other: &Target) -> Option<bool> {
+ let self_updated = self.already_updated.get();
+ let other_updated = other.already_updated.get();
+ Some(match (self.modified_time(), other.modified_time()) {
+ (Some(self_mtime), Some(other_mtime)) => self_mtime >= other_mtime,
+ // per POSIX: "If the target does not exist after the target has been
+ // successfully made up-to-date, the target shall be treated as being
+ // newer than any target for which it is a prerequisite."
+ (None, _) if self_updated && other.prerequisites.contains(&self.name) => true,
+ (_, None) if other_updated && self.prerequisites.contains(&other.name) => false,
+ _ => return None,
+ })
+ }
+
+ fn is_up_to_date(&self, file: &Makefile) -> bool {
+ if self.already_updated.get() {
+ return true;
+ }
+ let exists = metadata(&self.name).is_ok();
+ let newer_than_all_dependencies = self.prerequisites.iter().all(|t| {
+ self.newer_than(&file.get_target(t).borrow())
+ .unwrap_or(false)
+ });
+ exists && newer_than_all_dependencies
+ }
+
+ pub fn update(&self, file: &Makefile) {
+ for prereq in &self.prerequisites {
+ file.update_target(prereq);
+ }
+ if !self.is_up_to_date(file) {
+ self.execute_commands(file);
+ }
+ self.already_updated.set(true);
+ }
+
+ fn execute_commands(&self, file: &Makefile) {
+ for command in &self.commands {
+ command.execute(file, self);
+ }
+ }
+}
+
+impl fmt::Display for Target {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let prereqs = self.prerequisites.join(" ");
+ writeln!(f, "{}: {}", &self.name, prereqs)?;
+ for command in &self.commands {
+ writeln!(f, "\t{}", command)?;
+ }
+ Ok(())
+ }
+}