diff options
| -rw-r--r-- | Cargo.lock | 218 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/args.rs | 189 | ||||
| -rw-r--r-- | src/main.rs | 8 | 
4 files changed, 416 insertions, 2 deletions
@@ -1,5 +1,223 @@  # This file is automatically @generated by Cargo.  # It is not intended for manual editing.  [[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" + +[[package]]  name = "makers"  version = "0.1.0" +dependencies = [ + "structopt", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" @@ -1,7 +1,7 @@  [package]  name = "makers"  version = "0.1.0" -authors = ["Melody Horn <melody@boringcactus.com>"] +authors = ["boringcactus / Melody Horn <melody@boringcactus.com>"]  edition = "2018"  description = "a POSIX-compatible make implemented in Rust"  readme = "README.md" @@ -10,3 +10,4 @@ keywords = ["build", "make"]  categories = ["development-tools"]  [dependencies] +structopt = "0.3.21" diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..1fe6731 --- /dev/null +++ b/src/args.rs @@ -0,0 +1,189 @@ +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; + +use structopt::StructOpt; + +#[derive(StructOpt, Debug, PartialEq, Eq)] +#[structopt(author, about)] +pub struct Args { +    /// Cause environment variables, including those with null values, to override macro +    /// assignments within makefiles. +    #[structopt(short, long)] +    environment_overrides: bool, + +    /// Specify a different makefile (or '-' for standard input). +    /// +    /// The argument makefile is a pathname of a description file, which is also referred +    /// to as the makefile. A pathname of '-' shall denote the standard input. There can +    /// be multiple instances of this option, and they shall be processed in the order +    /// specified. The effect of specifying the same option-argument more than once is +    /// unspecified. +    #[structopt(short = "f", long = "file", visible_alias = "makefile", number_of_values = 1, parse(from_os_str))] +    makefile: Vec<PathBuf>, + +    /// Ignore error codes returned by invoked commands. +    /// +    /// This mode is the same as if the special target .IGNORE were specified without +    /// prerequisites. +    #[structopt(short, long)] +    ignore_errors: bool, + +    /// Continue to update other targets that do not depend on the current target if a +    /// non-ignored error occurs while executing the commands to bring a target +    /// up-to-date. +    #[structopt(short, long)] +    keep_going: bool, + +    /// Write commands that would be executed on standard output, but do not execute them +    /// (but execute lines starting with '+'). +    /// +    /// However, lines with a <plus-sign> ( '+' ) prefix shall be executed. In this mode, +    /// lines with an at-sign ( '@' ) character prefix shall be written to standard +    /// output. +    #[structopt(short = "n", long, visible_alias = "just-print", visible_alias = "recon")] +    dry_run: bool, + +    /// Write to standard output the complete set of macro definitions and target +    /// descriptions. +    /// +    /// The output format is unspecified. +    #[structopt(short, long, visible_alias = "print-data-base")] +    print_everything: bool, + +    /// Return a zero exit value if the target file is up-to-date; otherwise, return an +    /// exit value of 1. +    /// +    /// Targets shall not be updated if this option is specified. However, a makefile +    /// command line (associated with the targets) with a <plus-sign> ( '+' ) prefix +    /// shall be executed. +    #[structopt(short, long)] +    question: bool, + +    /// Clear the suffix list and do not use the built-in rules. +    #[structopt(short = "r", long)] +    no_builtin_rules: bool, + +    /// Terminate make if an error occurs while executing the commands to bring a target +    /// up-to-date (default behavior, required by POSIX to be also a flag for some +    /// reason). +    /// +    /// This shall be the default and the opposite of -k. +    #[structopt(short = "S", long, visible_alias = "stop", hidden = true, overrides_with="keep-going")] +    no_keep_going: bool, + +    /// Do not write makefile command lines or touch messages to standard output before +    /// executing. +    /// +    /// This mode shall be the same as if the special target .SILENT were specified +    /// without prerequisites. +    #[structopt(short, long, visible_alias = "quiet")] +    silent: bool, + +    /// Update the modification time of each target as though a touch target had been +    /// executed. +    /// +    /// Targets that have prerequisites but no commands, or that are already up-to-date, +    /// shall not be touched in this manner. Write messages to standard output for each +    /// target file indicating the name of the file and that it was touched. Normally, +    /// the makefile command lines associated with each target are not executed. However, +    /// a command line with a <plus-sign> ( '+' ) prefix shall be executed. +    #[structopt(short, long)] +    touch: bool, + +    /// Target names or macro definitions. +    /// +    /// If no target is specified, while make is processing the makefiles, the first +    /// target that make encounters that is not a special target or an inference rule +    /// shall be used. +    targets_or_macros: Vec<String>, +} + +impl Args { +    pub fn from_env_and_args() -> Args { +        // POSIX spec says "Any options specified in the MAKEFLAGS environment variable +        // shall be evaluated before any options specified on the make utility command +        // line." +        // TODO make sure only flags show up in MAKEFLAGS (i.e. not -f or other stuff) +        // TODO accept "option letters without the leading <hyphen-minus> characters" +        let env_makeflags = env::var("MAKEFLAGS").unwrap_or_default(); +        let env_makeflags = env_makeflags.split_whitespace() +            .map(|x| OsString::from(x)); +        let mut args = env::args_os(); +        // per the structopt docs, the first argument will be used as the binary name, +        // so we need to make sure it goes in before MAKEFLAGS +        let arg0 = args.next().unwrap_or_else(|| env!("CARGO_PKG_NAME").into()); + +        let args = ::std::iter::once(arg0) +            .chain(env_makeflags.into_iter()) +            .chain(args); +        Args::from_iter(args) +    } +} + +#[cfg(test)] +mod test { +    use super::*; + +    #[test] +    fn no_args() { +        let args: Vec<OsString> = vec!["makers".into()]; +        let args = Args::from_iter(args.into_iter()); +        assert_eq!(args, Args { +            environment_overrides: false, +            makefile: vec![], +            ignore_errors: false, +            keep_going: false, +            dry_run: false, +            print_everything: false, +            question: false, +            no_builtin_rules: false, +            no_keep_going: false, +            silent: false, +            touch: false, +            targets_or_macros: vec![], +        }); +    } + +    #[test] +    fn kitchen_sink_args() { +        let args = "makers -eiknpqrstf foo -f bruh bar baz=yeet"; +        let args = Args::from_iter(args.split_whitespace()); +        assert_eq!(args, Args { +            environment_overrides: true, +            makefile: vec!["foo".into(), "bruh".into()], +            ignore_errors: true, +            keep_going: true, +            dry_run: true, +            print_everything: true, +            question: true, +            no_builtin_rules: true, +            no_keep_going: false, +            silent: true, +            touch: true, +            targets_or_macros: vec!["bar".into(), "baz=yeet".into()], +        }); +    } + +    #[test] +    fn keep_going_wrestling() { +        let args = "makers -kSkSkSSSkSkkSk -k -S -k -k -S -S -k"; +        let args = Args::from_iter(args.split_whitespace()); +        assert_eq!(args, Args { +            environment_overrides: false, +            makefile: vec![], +            ignore_errors: false, +            keep_going: true, +            dry_run: false, +            print_everything: false, +            question: false, +            no_builtin_rules: false, +            no_keep_going: false, +            silent: false, +            touch: false, +            targets_or_macros: vec![], +        }); +    } + +    // TODO test MAKEFLAGS +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..2316546 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ + +mod args; + +use args::Args; +  fn main() { -    println!("Hello, world!"); +    let args = Args::from_env_and_args(); +    dbg!(args);  }  |