From 028e1a631629c7f5959e522dee80188ea7534d8f Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sat, 27 Mar 2021 15:50:39 -0600 Subject: refactor makefile elements into submodules --- src/makefile/target.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/makefile/target.rs (limited to 'src/makefile/target.rs') 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, + pub commands: Vec, + pub already_updated: Cell, +} + +impl Target { + fn modified_time(&self) -> Option { + metadata(&self.name) + .and_then(|metadata| metadata.modified()) + .ok() + } + + pub fn newer_than(&self, other: &Target) -> Option { + 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(()) + } +} -- cgit v1.2.3