From aa50ebd03ed1d1f698d0d275f9570ef53e720831 Mon Sep 17 00:00:00 2001 From: Niels langager Ellegaard Date: Sun, 5 Jan 2014 11:23:39 +0100 Subject: [PATCH] Move command line parsing to parse_args.rs --- src/librustpkg/lib.rs | 189 ++++++---------------------------- src/librustpkg/parse_args.rs | 190 +++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 160 deletions(-) create mode 100644 src/librustpkg/parse_args.rs diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs index 39bc4c7570e52..e9c41d6b897bb 100644 --- a/src/librustpkg/lib.rs +++ b/src/librustpkg/lib.rs @@ -20,9 +20,8 @@ extern mod extra; extern mod rustc; extern mod syntax; -use std::{os, result, run, str, task}; +use std::{os, run, str, task}; use std::io::process; -use std::hashmap::HashSet; use std::io; use std::io::fs; pub use std::path::Path; @@ -32,9 +31,9 @@ use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use rustc::metadata::filesearch::rust_path; use rustc::util::sha2; -use extra::{getopts}; use syntax::{ast, diagnostic}; use messages::{error, warn, note}; +use parse_args::{ParseResult, parse_args}; use path_util::{build_pkg_id_in_workspace, built_test_in_workspace}; use path_util::in_rust_path; use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace}; @@ -42,9 +41,8 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, dir use source_control::{CheckedOutSources, is_git_dir, make_read_only}; use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace}; use workspace::determine_destination; -use context::{Context, BuildContext, - RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble, - LLVMAssemble, LLVMCompileBitcode}; +use context::{BuildContext, Trans, Nothing, Pretty, Analysis, + LLVMAssemble, LLVMCompileBitcode}; use context::{Command, BuildCmd, CleanCmd, DoCmd, InfoCmd, InstallCmd, ListCmd, PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd}; use crate_id::CrateId; @@ -52,7 +50,7 @@ use package_source::PkgSrc; use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench}; use target::{Main, Tests, MaybeCustom, Inferred, JustOne}; use workcache_support::digest_only_date; -use exit_codes::{COPY_FAILED_CODE, BAD_FLAG_CODE}; +use exit_codes::{COPY_FAILED_CODE}; pub mod api; mod conditions; @@ -63,6 +61,7 @@ mod installed_packages; mod messages; pub mod crate_id; pub mod package_source; +mod parse_args; mod path_util; mod source_control; mod target; @@ -751,173 +750,43 @@ pub fn main() { } pub fn main_args(args: &[~str]) -> int { - let opts = ~[getopts::optflag("h"), getopts::optflag("help"), - getopts::optflag("no-link"), - getopts::optflag("no-trans"), - // n.b. Ignores different --pretty options for now - getopts::optflag("pretty"), - getopts::optflag("parse-only"), - getopts::optflag("S"), getopts::optflag("assembly"), - getopts::optmulti("c"), getopts::optmulti("cfg"), - getopts::optflag("v"), getopts::optflag("version"), - getopts::optflag("r"), getopts::optflag("rust-path-hack"), - getopts::optopt("sysroot"), - getopts::optflag("emit-llvm"), - getopts::optopt("linker"), - getopts::optopt("link-args"), - getopts::optopt("opt-level"), - getopts::optflag("O"), - getopts::optflag("save-temps"), - getopts::optopt("target"), - getopts::optopt("target-cpu"), - getopts::optmulti("Z") ]; - let matches = &match getopts::getopts(args, opts) { - result::Ok(m) => m, - result::Err(f) => { - error(format!("{}", f.to_err_msg())); - - return 1; - } - }; - let help = matches.opt_present("h") || - matches.opt_present("help"); - let no_link = matches.opt_present("no-link"); - let no_trans = matches.opt_present("no-trans"); - let supplied_sysroot = matches.opt_str("sysroot"); - let generate_asm = matches.opt_present("S") || - matches.opt_present("assembly"); - let parse_only = matches.opt_present("parse-only"); - let pretty = matches.opt_present("pretty"); - let emit_llvm = matches.opt_present("emit-llvm"); - - if matches.opt_present("v") || - matches.opt_present("version") { - rustc::version(args[0]); - return 0; - } - - let use_rust_path_hack = matches.opt_present("r") || - matches.opt_present("rust-path-hack"); - - let linker = matches.opt_str("linker"); - let link_args = matches.opt_str("link-args"); - let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c"); - let mut user_supplied_opt_level = true; - let opt_level = match matches.opt_str("opt-level") { - Some(~"0") => session::No, - Some(~"1") => session::Less, - Some(~"2") => session::Default, - Some(~"3") => session::Aggressive, - _ if matches.opt_present("O") => session::Default, - _ => { - user_supplied_opt_level = false; - session::No - } - }; - let save_temps = matches.opt_present("save-temps"); - let target = matches.opt_str("target"); - let target_cpu = matches.opt_str("target-cpu"); - let experimental_features = { - let strs = matches.opt_strs("Z"); - if matches.opt_present("Z") { - Some(strs) - } - else { - None + let (command, args, context, supplied_sysroot) = match parse_args(args) { + Ok(ParseResult { + command: cmd, + args: args, + context: ctx, + sysroot: sroot}) => (cmd, args, ctx, sroot), + Err(error_code) => { + debug!("Parsing failed. Returning error code {}", error_code); + return error_code } }; - - let mut args = matches.free.clone(); - args.shift(); - - if (args.len() < 1) { - usage::general(); - return 1; - } - - let rustc_flags = RustcFlags { - linker: linker, - link_args: link_args, - optimization_level: opt_level, - compile_upto: if no_trans { - Trans - } else if no_link { - Link - } else if pretty { - Pretty - } else if parse_only { - Analysis - } else if emit_llvm && generate_asm { - LLVMAssemble - } else if generate_asm { - Assemble - } else if emit_llvm { - LLVMCompileBitcode - } else { - Nothing - }, - save_temps: save_temps, - target: target, - target_cpu: target_cpu, - additional_library_paths: - HashSet::new(), // No way to set this from the rustpkg command line - experimental_features: experimental_features - }; - - let cmd_opt = args.iter().filter_map( |s| from_str(s.clone())).next(); - let command = match(cmd_opt) { - None => { - usage::general(); - return 0; - } - Some(cmd) => { - let bad_option = context::flags_forbidden_for_cmd(&rustc_flags, - cfgs, - cmd, - user_supplied_opt_level); - if help || bad_option { - usage::usage_for_command(cmd); - if bad_option { - return BAD_FLAG_CODE; - } - else { - return 0; - } - } else { - cmd - } - } - }; - - // Pop off all flags, plus the command - let mut remaining_args: ~[~str] = args.iter().skip_while(|&s| { - let maybe_command: Option = from_str(*s); - maybe_command.is_none() - }).map(|s| s.clone()).collect(); - remaining_args.shift(); - let sroot = match supplied_sysroot { + debug!("Finished parsing commandline args {:?}", args); + debug!(" Using command: {:?}", command); + debug!(" Using args {:?}", args); + debug!(" Using cflags: {:?}", context.rustc_flags); + debug!(" Using rust_path_hack {:b}", context.use_rust_path_hack); + debug!(" Using cfgs: {:?}", context.cfgs); + debug!(" Using supplied_sysroot: {:?}", supplied_sysroot); + + let sysroot = match supplied_sysroot { Some(s) => Path::new(s), _ => filesearch::get_or_default_sysroot() }; - debug!("Using sysroot: {}", sroot.display()); + debug!("Using sysroot: {}", sysroot.display()); let ws = default_workspace(); debug!("Will store workcache in {}", ws.display()); - let rm_args = remaining_args.clone(); // Wrap the rest in task::try in case of a condition failure in a task let result = do task::try { BuildContext { - context: Context { - cfgs: cfgs.clone(), - rustc_flags: rustc_flags.clone(), - use_rust_path_hack: use_rust_path_hack, - }, - sysroot: sroot.clone(), // Currently, only tests override this - workcache_context: api::default_context(sroot.clone(), + context: context, + sysroot: sysroot.clone(), // Currently, only tests override this + workcache_context: api::default_context(sysroot.clone(), default_workspace()).workcache_context - }.run(command, rm_args.clone()) + }.run(command, args.clone()) }; // FIXME #9262: This is using the same error code for all errors, // and at least one test case succeeds if rustpkg returns COPY_FAILED_CODE, diff --git a/src/librustpkg/parse_args.rs b/src/librustpkg/parse_args.rs new file mode 100644 index 0000000000000..8f21c6d3bfa68 --- /dev/null +++ b/src/librustpkg/parse_args.rs @@ -0,0 +1,190 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use context::{Context, RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble, + LLVMAssemble, LLVMCompileBitcode}; +use context::{Command, flags_forbidden_for_cmd}; +use rustc::version; +use exit_codes::{BAD_FLAG_CODE}; +use rustc::driver::{session}; + +use usage; + +use extra::{getopts}; +use std::{result}; +use std::hashmap::HashSet; + +/// Result of parsing command line arguments +pub struct ParseResult { + // Command + command: Command, + // Args + args: ~[~str], + // Parsed command line flags + context: Context, + // Path to system root + sysroot: Option<~str> +} + +/// Parses command line arguments of rustpkg. +/// Returns a triplet (command, remaining_args, context) +pub fn parse_args(args: &[~str]) -> Result { + let opts = ~[ getopts::optflag("no-link"), + getopts::optflag("no-trans"), + // n.b. Ignores different --pretty options for now + getopts::optflag("pretty"), + getopts::optflag("parse-only"), + getopts::optflag("S"), getopts::optflag("assembly"), + getopts::optmulti("c"), getopts::optmulti("cfg"), + getopts::optflag("v"), getopts::optflag("version"), + getopts::optflag("r"), getopts::optflag("rust-path-hack"), + getopts::optopt("sysroot"), + getopts::optflag("emit-llvm"), + getopts::optopt("linker"), + getopts::optopt("link-args"), + getopts::optopt("opt-level"), + getopts::optflag("O"), + getopts::optflag("save-temps"), + getopts::optopt("target"), + getopts::optopt("target-cpu"), + getopts::optmulti("Z") ]; + let matches = &match getopts::getopts(args, opts) { + result::Ok(m) => m, + result::Err(f) => { + error!("{}", f.to_err_msg()); + return Err(1); + } + }; + let no_link = matches.opt_present("no-link"); + let no_trans = matches.opt_present("no-trans"); + let supplied_sysroot = matches.opt_str("sysroot"); + let generate_asm = matches.opt_present("S") || + matches.opt_present("assembly"); + let parse_only = matches.opt_present("parse-only"); + let pretty = matches.opt_present("pretty"); + let emit_llvm = matches.opt_present("emit-llvm"); + + if matches.opt_present("v") || + matches.opt_present("version") { + version(args[0]); + return Err(0); + } + + let use_rust_path_hack = matches.opt_present("r") || + matches.opt_present("rust-path-hack"); + + let linker = matches.opt_str("linker"); + let link_args = matches.opt_str("link-args"); + let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c"); + let mut user_supplied_opt_level = true; + let opt_level = match matches.opt_str("opt-level") { + Some(~"0") => session::No, + Some(~"1") => session::Less, + Some(~"2") => session::Default, + Some(~"3") => session::Aggressive, + _ if matches.opt_present("O") => session::Default, + _ => { + user_supplied_opt_level = false; + session::No + } + }; + + let save_temps = matches.opt_present("save-temps"); + let target = matches.opt_str("target"); + let target_cpu = matches.opt_str("target-cpu"); + let experimental_features = { + let strs = matches.opt_strs("Z"); + if matches.opt_present("Z") { + Some(strs) + } + else { + None + } + }; + + let mut args = matches.free.clone(); + args.shift(); + + if (args.len() < 1) { + usage::general(); + return Err(1); + } + + let rustc_flags = RustcFlags { + linker: linker, + link_args: link_args, + optimization_level: opt_level, + compile_upto: if no_trans { + Trans + } else if no_link { + Link + } else if pretty { + Pretty + } else if parse_only { + Analysis + } else if emit_llvm && generate_asm { + LLVMAssemble + } else if generate_asm { + Assemble + } else if emit_llvm { + LLVMCompileBitcode + } else { + Nothing + }, + save_temps: save_temps, + target: target, + target_cpu: target_cpu, + additional_library_paths: + HashSet::new(), // No way to set this from the rustpkg command line + experimental_features: experimental_features + }; + + let cmd_opt = args.iter().filter_map( |s| from_str(s.clone())).next(); + let command = match(cmd_opt){ + None => { + debug!("No legal command. Returning 0"); + usage::general(); + return Err(0); + } + Some(cmd) => { + let bad_option = flags_forbidden_for_cmd(&rustc_flags, + cfgs, + cmd, + user_supplied_opt_level); + if bad_option { + usage::usage_for_command(cmd); + debug!("Bad option, returning BAD_FLAG_CODE"); + return Err(BAD_FLAG_CODE); + } else { + cmd + } + } + }; + + // Pop off all flags, plus the command + let mut remaining_args: ~[~str] = args.iter().skip_while(|&s| { + let maybe_command: Option = from_str(*s); + maybe_command.is_none() + }).map(|s| s.clone()).collect(); + remaining_args.shift(); + + let context = Context{ + rustc_flags: rustc_flags, + cfgs: cfgs, + use_rust_path_hack: use_rust_path_hack, + }; + Ok(ParseResult { + command: command, + args: remaining_args, + context: context, + sysroot: supplied_sysroot + }) +} +