use clap;
use std;
use std::env;
use std::path::{PathBuf};
use crate::version;
use crate::git;
#[derive(Debug, Clone)]
pub struct Flags {
pub clean: bool,
pub dry_run: bool,
pub continual: bool,
pub git_add: bool,
pub verbosity: u64,
pub show_output: bool,
pub log_output: Option<PathBuf>,
pub run_from_directory: PathBuf,
pub root: PathBuf,
pub jobs: usize,
pub strictness: Strictness,
pub targets: Vec<PathBuf>,
pub parse_only: Option<PathBuf>,
pub blind: bool,
pub makefile: Option<PathBuf>,
pub tupfile: Option<PathBuf>,
pub ninja: Option<PathBuf>,
pub dotfile: Option<PathBuf>,
pub script: Option<PathBuf>,
pub tar: Option<PathBuf>,
pub include_in_tar: Vec<PathBuf>,
}
pub fn args<'a>() -> Flags {
let m = clap::App::new("fac")
.version(version::VERSION)
.about("build things")
.arg(clap::Arg::with_name("jobs")
.short("j")
.long("jobs")
.takes_value(true)
.value_name("JOBS")
.default_value("0")
.hide_default_value(true)
.help("the number of jobs to run simultaneously"))
.arg(clap::Arg::with_name("clean")
.short("c")
.long("clean")
.help("remove all traces of built files"))
.arg(clap::Arg::with_name("dry")
.long("dry")
.help("dry run (don't do any building!)"))
.arg(clap::Arg::with_name("verbose")
.long("verbose")
.short("v")
.multiple(true)
.help("show verbose output"))
.arg(clap::Arg::with_name("show-output")
.long("show-output")
.short("V")
.help("show command output"))
.arg(clap::Arg::with_name("log-output")
.long("log-output")
.short("l")
.takes_value(true)
.value_name("LOG_DIRECTORY")
.help("log command output to directory"))
.group(clap::ArgGroup::with_name("command output")
.arg("log-output")
.arg("show-output")
)
.arg(clap::Arg::with_name("git-add")
.long("git-add")
.help("git add needed files"))
.arg(clap::Arg::with_name("continual")
.long("continual")
.help("keep rebuilding"))
.arg(clap::Arg::with_name("strict")
.long("strict")
.help("require strict dependencies, so first build will succeed"))
.arg(clap::Arg::with_name("exhaustive")
.long("exhaustive")
.help("require exhaustive dependencies (makes --blind \"safe\")"))
.group(clap::ArgGroup::with_name("strictness")
.arg("strict")
.arg("exhaustive")
)
.arg(clap::Arg::with_name("parse-only")
.long("parse-only")
.takes_value(true)
.value_name("FACFILENAME")
.help("just parse this .fac file"))
.arg(clap::Arg::with_name("blind")
.long("blind")
.help("do not track dependencies"))
.arg(clap::Arg::with_name("makefile")
.long("makefile")
.takes_value(true)
.value_name("MAKEFILE")
.help("create a makefile"))
.arg(clap::Arg::with_name("tupfile")
.long("tupfile")
.takes_value(true)
.value_name("TUPFILE")
.help("create a tupfile"))
.arg(clap::Arg::with_name("ninja")
.long("ninja")
.takes_value(true)
.value_name("BUILD.NINJA")
.help("create a build.ninja file"))
.arg(clap::Arg::with_name("dotfile")
.long("dotfile")
.takes_value(true)
.value_name("DOTFILE")
.help("create a graphviz file to visualize dependencies"))
.arg(clap::Arg::with_name("script")
.long("script")
.takes_value(true)
.value_name("SCRIPTFILE")
.help("create a build script"))
.arg(clap::Arg::with_name("tar")
.long("tar")
.takes_value(true)
.value_name("TARNAME.tar[.gz]")
.help("create a tar archive"))
.arg(clap::Arg::with_name("include-in-tar")
.long("include-in-tar")
.short("i")
.takes_value(true)
.value_name("FILENAME")
.multiple(true)
.number_of_values(1)
.help("include in tarball"))
.arg(clap::Arg::with_name("target")
.index(1)
.multiple(true)
.help("names of files to build"))
.get_matches();
let here = env::current_dir().unwrap();
let top = git::go_to_top();
let strictness: Strictness;
if m.is_present("strict") {
strictness = Strictness::Strict;
} else if m.is_present("exhaustive") {
strictness = Strictness::Exhaustive;
} else {
strictness = Strictness::Normal;
}
let mut targets = Vec::new();
if let Some(ts) = m.values_of_os("target") {
for t in ts {
let p = here.join(t);
let p = if let Ok(p) = std::fs::canonicalize(&p) {
p
} else {
p
};
if let Ok(p) = p.strip_prefix(&top) {
targets.push(PathBuf::from(p));
} else {
println!("Invalid path for target: {:?}", t);
std::process::exit(1);
}
}
}
let mut include_in_tar = Vec::new();
if let Some(fs) = m.values_of_os("include-in-tar") {
for f in fs {
let p = here.join(f);
let p = if let Ok(p) = std::fs::canonicalize(&p) {
p
} else {
p
};
if let Ok(p) = p.strip_prefix(&top) {
include_in_tar.push(PathBuf::from(p));
} else {
println!("Invalid path for including in tar: {:?}", f);
std::process::exit(1);
}
}
}
Flags {
clean: m.is_present("clean"),
dry_run: m.is_present("dry"),
verbosity: m.occurrences_of("verbose"),
show_output: m.is_present("show-output"),
log_output: m.value_of("log-output").map(|s| PathBuf::from(s)),
continual: m.is_present("continual"),
git_add: m.is_present("git-add"),
run_from_directory: here,
root: top,
jobs: value_t_or_exit!(m, "jobs", usize),
strictness: strictness,
targets: targets,
parse_only: m.value_of("parse-only").map(|s| PathBuf::from(s)),
blind: m.is_present("blind"),
makefile: m.value_of("makefile").map(|s| PathBuf::from(s)),
tupfile: m.value_of("tupfile").map(|s| PathBuf::from(s)),
ninja: m.value_of("ninja").map(|s| PathBuf::from(s)),
dotfile: m.value_of("dotfile").map(|s| PathBuf::from(s)),
script: m.value_of("script").map(|s| PathBuf::from(s)),
tar: m.value_of("tar").map(|s| PathBuf::from(s)),
include_in_tar: include_in_tar,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Strictness {
Normal,
Strict,
Exhaustive,
}