diff options
author | Melody Horn <melody@boringcactus.com> | 2021-03-27 15:50:39 -0600 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2021-03-27 15:50:39 -0600 |
commit | 028e1a631629c7f5959e522dee80188ea7534d8f (patch) | |
tree | 65aff918fdcb2999cde604a8959f2c6ec83f6f98 /src/makefile/target.rs | |
parent | 4a3bf997b83e3cf3496622ce1554c8641e6031da (diff) | |
download | makers-028e1a631629c7f5959e522dee80188ea7534d8f.tar.gz makers-028e1a631629c7f5959e522dee80188ea7534d8f.zip |
refactor makefile elements into submodules
Diffstat (limited to 'src/makefile/target.rs')
-rw-r--r-- | src/makefile/target.rs | 77 |
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(()) + } +} |