aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/command_line.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/command_line.rs
parent4a3bf997b83e3cf3496622ce1554c8641e6031da (diff)
downloadmakers-028e1a631629c7f5959e522dee80188ea7534d8f.tar.gz
makers-028e1a631629c7f5959e522dee80188ea7534d8f.zip
refactor makefile elements into submodules
Diffstat (limited to 'src/makefile/command_line.rs')
-rw-r--r--src/makefile/command_line.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/makefile/command_line.rs b/src/makefile/command_line.rs
new file mode 100644
index 0000000..0e0e745
--- /dev/null
+++ b/src/makefile/command_line.rs
@@ -0,0 +1,102 @@
+use std::fmt;
+
+use crate::makefile::target::Target;
+use crate::makefile::token::{Token, TokenString};
+use crate::makefile::Makefile;
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct CommandLine {
+ /// If the command prefix contains a <hyphen-minus>, or the -i option is present, or
+ /// the special target .IGNORE has either the current target as a prerequisite or has
+ /// no prerequisites, any error found while executing the command shall be ignored.
+ ignore_errors: bool,
+ /// If the command prefix contains an at-sign and the make utility command line -n
+ /// option is not specified, or the -s option is present, or the special target
+ /// .SILENT has either the current target as a prerequisite or has no prerequisites,
+ /// the command shall not be written to standard output before it is executed.
+ silent: bool,
+ /// If the command prefix contains a <plus-sign>, this indicates a makefile command
+ /// line that shall be executed even if -n, -q, or -t is specified.
+ always_execute: bool,
+ execution_line: TokenString,
+}
+
+impl CommandLine {
+ pub fn from(mut line: TokenString) -> Self {
+ let mut ignore_errors = false;
+ let mut silent = false;
+ let mut always_execute = false;
+
+ if let Token::Text(text) = line.first_token_mut() {
+ let mut text_chars = text.chars().peekable();
+ while let Some(x) = text_chars.next_if(|x| matches!(x, '-' | '@' | '+')) {
+ match x {
+ '-' => ignore_errors = true,
+ '@' => silent = true,
+ '+' => always_execute = true,
+ _ => unreachable!(),
+ }
+ }
+ *text = text_chars.collect();
+ }
+
+ CommandLine {
+ ignore_errors,
+ silent,
+ always_execute,
+ execution_line: line,
+ }
+ }
+
+ pub fn execute(&self, file: &Makefile, target: &Target) {
+ let ignore_error = self.ignore_errors
+ || file.args.ignore_errors
+ || file.special_target_has_prereq(".IGNORE", &target.name);
+ let silent = (self.silent && !file.args.dry_run)
+ || file.args.silent
+ || file.special_target_has_prereq(".SILENT", &target.name);
+
+ let execution_line = file.expand_macros(&self.execution_line, Some(target));
+
+ if !silent {
+ println!("{}", execution_line);
+ }
+
+ let should_execute =
+ self.always_execute || !(file.args.dry_run || file.args.question || file.args.touch);
+ if !should_execute {
+ return;
+ }
+
+ // TODO don't fuck this up
+ let execution_line = ::std::ffi::CString::new(execution_line.as_bytes())
+ .expect("execution line shouldn't have a null in the middle");
+ // TODO pass shell "-e" if errors are not ignored
+ let return_value = unsafe { libc::system(execution_line.as_ptr()) };
+ if return_value != 0 {
+ // apparently there was an error. do we care?
+ if !ignore_error {
+ // TODO handle this error gracefully
+ panic!("error from command execution!");
+ }
+ }
+ }
+}
+
+impl fmt::Display for CommandLine {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.ignore_errors {
+ write!(f, "-")?;
+ }
+ if self.silent {
+ write!(f, "@")?;
+ }
+ if self.always_execute {
+ write!(f, "+")?;
+ }
+ let execution_line = format!("{}", &self.execution_line);
+ let execution_line = execution_line.replace("\n", "↵\n");
+ write!(f, "{}", execution_line)?;
+ Ok(())
+ }
+}