aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-14 23:50:30 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-14 23:50:30 -0600
commitb162ce1d581d2f3352a2d878e037bd9949e9dace (patch)
treead2ee39942f5635729ac63e0b595eca2aed9518a
parent5a72fb28fb69a476437141a4eb898d6d001dd281 (diff)
downloadmakers-b162ce1d581d2f3352a2d878e037bd9949e9dace.tar.gz
makers-b162ce1d581d2f3352a2d878e037bd9949e9dace.zip
rebuild out-of-date makefiles, kinda
-rw-r--r--src/main.rs29
-rw-r--r--src/makefile/input.rs112
-rw-r--r--src/makefile/mod.rs4
-rw-r--r--src/makefile/target.rs2
4 files changed, 127 insertions, 20 deletions
diff --git a/src/main.rs b/src/main.rs
index c5bc049..8fa4efd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,6 +24,7 @@ use std::env;
use std::fs::metadata;
use std::io::stdin;
use std::path::PathBuf;
+use std::rc::Rc;
use eyre::{bail, Result};
@@ -63,18 +64,42 @@ fn main() -> Result<()> {
// TODO dump command-line macros into environment
// TODO add SHELL macro
let mut makefile = Makefile::new(&args);
+ let paths = Default::default();
for filename in &args.makefile {
if filename == &PathBuf::from("-") {
let macros = makefile.macros.with_overlay();
- let file = MakefileReader::read(&args, macros, stdin().lock(), "-")?.finish();
+ let file = MakefileReader::read(&args, macros, stdin().lock(), "-", Rc::clone(&paths))?
+ .finish();
makefile.extend(file)?;
} else {
let macros = makefile.macros.with_overlay();
- let file = MakefileReader::read_file(&args, macros, filename)?.finish();
+ let file =
+ MakefileReader::read_file(&args, macros, filename, Rc::clone(&paths))?.finish();
makefile.extend(file)?;
};
}
+ let makefiles_outdated = paths
+ .borrow()
+ .iter()
+ .filter(|path| {
+ makefile
+ .get_target(path)
+ .map_or(false, |target| !target.borrow().is_up_to_date(&makefile))
+ })
+ .cloned()
+ .collect::<Vec<_>>();
+ for outdated in makefiles_outdated {
+ eprintln!("makefile {} out of date, rebuilding", outdated);
+ makefile.update_target(&outdated)?;
+ let macros = makefile.macros.with_overlay();
+ let file =
+ MakefileReader::read_file(&args, macros, &outdated, Default::default())?.finish();
+ // TODO forget the stale data
+ // TODO reread all the things, not just this one
+ makefile.extend(file)?;
+ }
+
if args.print_everything {
println!("{}", &makefile);
} else {
diff --git a/src/makefile/input.rs b/src/makefile/input.rs
index 4a0f086..64b12d7 100644
--- a/src/makefile/input.rs
+++ b/src/makefile/input.rs
@@ -1,10 +1,11 @@
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::error::Error as StdError;
use std::fs::File;
use std::io::{BufRead, BufReader, Cursor, Error as IoError, ErrorKind as IoErrorKind, Lines};
use std::iter::Peekable;
use std::path::Path;
+use std::rc::Rc;
use eyre::{bail, eyre, Context, Result};
use lazy_static::lazy_static;
@@ -192,6 +193,7 @@ pub struct MakefileReader<'a, 'parent, R: BufRead> {
pending_line: Option<(usize, Vec<String>)>,
#[cfg(feature = "full")]
conditional_stack: Vec<ConditionalState>,
+ file_names: Rc<RefCell<Vec<String>>>,
}
impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> {
@@ -199,6 +201,7 @@ impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> {
args: &'a Args,
mut macros: MacroSet<'parent, 'static>,
path: impl AsRef<Path>,
+ file_names: Rc<RefCell<Vec<String>>>,
) -> Result<Self> {
#[cfg(feature = "full")]
if let Some(mut old_makefile_list) = macros.pop("MAKEFILE_LIST") {
@@ -218,11 +221,13 @@ impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> {
},
);
}
+ let file_name = path.as_ref().to_string_lossy();
+ file_names.borrow_mut().push(file_name.to_string());
let file = File::open(path.as_ref());
// TODO handle errors
let file = file.context("couldn't open makefile!")?;
let file_reader = BufReader::new(file);
- Self::read(args, macros, file_reader, path.as_ref().to_string_lossy())
+ Self::read(args, macros, file_reader, file_name, file_names)
}
}
@@ -232,6 +237,7 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
macros: MacroSet<'parent, 'static>,
source: R,
name: impl Into<String>,
+ file_names: Rc<RefCell<Vec<String>>>,
) -> Result<Self> {
let name = name.into();
let mut reader = Self {
@@ -247,6 +253,7 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
pending_line: None,
#[cfg(feature = "full")]
conditional_stack: Vec::new(),
+ file_names,
};
// TODO be smart about this instead, please
if !args.no_builtin_rules {
@@ -310,6 +317,7 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
child_macros,
Cursor::new(eval),
"<eval>",
+ Rc::clone(&self.file_names),
)
.context("while evaling")?
.finish();
@@ -536,9 +544,15 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
// POSIX says we only have to handle a single filename, but GNU make
// handles arbitrarily many filenames, and it's not like that's more work
for field in fields {
+ log::trace!("{}:{}: including {}", &self.file_name, line_number, field);
let child_macros = self.macros.with_overlay();
- let child = MakefileReader::read_file(self.args, child_macros, field)
- .with_context(|| format!("while including {}", field));
+ let child = MakefileReader::read_file(
+ self.args,
+ child_macros,
+ field,
+ Rc::clone(&self.file_names),
+ )
+ .with_context(|| format!("while including {}", field));
match child {
Ok(child) => {
let child = child.finish();
@@ -957,8 +971,14 @@ a: $(x) b \\
\t\td
\tfoo";
let args = Args::empty();
- let makefile =
- MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?.finish();
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?
+ .finish();
assert_eq!(
makefile.targets["a"].prerequisites,
vec!["3", "4", "5", "b", "c", "d"]
@@ -979,7 +999,13 @@ worked = perhaps
endif
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
assert_eq!(
makefile.expand_macros(&TokenString::r#macro("worked"))?,
"yes"
@@ -997,7 +1023,13 @@ ifeq (1,1)
endif
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert_eq!(makefile.targets["a"].commands.len(), 1);
Ok(())
@@ -1013,7 +1045,13 @@ baz
endef
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
assert_eq!(
makefile.expand_macros(&TokenString::r#macro("foo"))?,
"bar\nbaz"
@@ -1035,7 +1073,13 @@ endif
FOO = bar
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
assert_eq!(makefile.expand_macros(&TokenString::r#macro("FOO"))?, "bar",);
Ok(())
}
@@ -1077,7 +1121,13 @@ clean:
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert!(makefile.targets.contains_key("server"));
Ok(())
@@ -1092,7 +1142,13 @@ info:
\thello # there
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert_eq!(
makefile.targets["foo"],
@@ -1136,7 +1192,13 @@ cursed:
\techo yeah its value is $$# and it's really cool
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let _makefile = makefile.finish();
Ok(())
}
@@ -1154,7 +1216,13 @@ cursed:
\techo hiiii
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert_eq!(makefile.inference_rules.len(), 2);
Ok(())
@@ -1169,7 +1237,13 @@ test: a
test: c
";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert_eq!(
makefile.targets["test"].prerequisites,
@@ -1183,7 +1257,13 @@ test: c
fn export_assign() -> R {
let file = "export x = 3";
let args = Args::empty();
- let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file), "")?;
+ let makefile = MakefileReader::read(
+ &args,
+ MacroSet::new(),
+ Cursor::new(file),
+ "",
+ Default::default(),
+ )?;
let makefile = makefile.finish();
assert_eq!(
makefile.macros.get("x").map(|x| &x.text),
diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs
index 7cc16c5..981636b 100644
--- a/src/makefile/mod.rs
+++ b/src/makefile/mod.rs
@@ -148,7 +148,9 @@ impl<'a> Makefile<'a> {
format!("while building missing included file {}", &failed_include)
})?;
let macros = self.macros.with_overlay();
- let file = MakefileReader::read_file(self.args, macros, failed_include)?.finish();
+ let file =
+ MakefileReader::read_file(self.args, macros, failed_include, Default::default())?
+ .finish();
self.extend(file)?;
}
Ok(())
diff --git a/src/makefile/target.rs b/src/makefile/target.rs
index c12f666..c3431e4 100644
--- a/src/makefile/target.rs
+++ b/src/makefile/target.rs
@@ -67,7 +67,7 @@ impl Target {
})
}
- fn is_up_to_date(&self, file: &Makefile) -> bool {
+ pub fn is_up_to_date(&self, file: &Makefile) -> bool {
if self.already_updated.get() {
return true;
}