/* * Copyright (c) 2016-2017 Jean Guyomarc'h * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #[macro_use] extern crate log; extern crate getopts; extern crate crypto; mod logger; mod utils; mod common; mod config; mod cmd; mod hook; #[macro_use] mod compiler; mod fetcher; mod unpacker; mod subprocess; use cmd::Errno; const PROLOG: &'static str = "Usage: subcomponent [options] subcomponent [options] Commands: fetch Fetch locally the requested components status Tell the status of the components template Create a subcomponent template "; fn usage(opts: &getopts::Options, exit: i32) -> ! { println!("{}", opts.usage(PROLOG)); std::process::exit(exit); } fn main() { let args: Vec = std::env::args().collect(); let mut opts = getopts::Options::new(); let mut loglevel = log::LogLevelFilter::Info; /* When we hit a positional argument, we will stop interpreting what * follows as options. These will be options to the command that is * identified by the hit positional argument */ opts.parsing_style(getopts::ParsingStyle::StopAtFirstFree); /* Description of the expected options */ opts.optflag("h", "help", "Display this message"); opts.optflag("", "debug", "Increase log verbosity for debug"); opts.optopt("C", "", "Execute subcomponent at path PATH", "PATH"); opts.optopt("f", "file", "Use FILE instead of the default one", "FILE"); /* Getopt */ let matches = match opts.parse(&args[1..]) { Ok(m) => { m }, Err(err) => { logger::init(log::LogLevelFilter::Error); error!("Options parsing failed: {}", err); usage(&opts, 1); } }; /* Always start with the --debug option, as it will set the logger */ if matches.opt_present("debug") { loglevel = log::LogLevelFilter::Trace; } logger::init(loglevel); /* --help: print usage and exit */ if matches.opt_present("help") { usage(&opts, 0); } /* If no command are provided, this is an error */ if matches.free.is_empty() { error!("A command name is required"); std::process::exit(1); } /* * If the '-C' option is present, change directory to the specified * path. If we do not succeed, we will stop right here. */ if let Some(path_opt) = matches.opt_str("C") { let path = std::path::Path::new(&path_opt); if let Err(err) = std::env::set_current_dir(&path) { error!("Failed to change directory to \"{}\". {}", path.display(), err); let errcode = match err.raw_os_error() { Some(code) => code, None => 127 }; std::process::exit(errcode); } else { debug!("Working directory is now {:?}", path); } } /* Option -f: use a different file than the default one */ let mut entry = std::path::PathBuf::new(); match matches.opt_str("f") { None => { entry.push(common::sub_dir_get()); entry.push(common::sub_file_get()); }, Some(file_opt) => { entry.push(file_opt); } } /* * Compile the subcomponent's description file. * If no file is available, the parser's result will be None. Otherwise, * it will be a valid Some(). */ let parser_opt = if entry.exists() { match compiler::compile(&entry) { Ok(parser) => Some(parser), Err(err) => { error!("Compilation of {} failed: {}", entry.display(), err); std::process::exit(127); } } } else { None }; /* Run sub-getopts for the command */ let cmds_opt = match cmd::getopts(&matches.free, &parser_opt) { Ok(c) => c, Err(err) => { error!("Command failed: {}", err); std::process::exit(127); } }; /* Run the command(s) */ let mut return_code = -1; if let Some(cmds) = cmds_opt { for cmd in cmds { if let Err(ret) = cmd.run(&parser_opt) { error!("Command failed: {}", ret); if let Some(os_err) = ret.errno() { return_code = os_err; } std::process::exit(return_code); } } } /* * At this point, we have not encountered errors. */ std::process::exit(0); }