123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- use std::env;
- use std::process;
- use std::os::unix::process::CommandExt;
- const USAGE_HINT: &'static str =
- "NOTICE ABOUT CAB:
- Cabal was invoked using cab, a wrapper script around
- Cabal. For cab-specific help, use --cab-help.\n";
- const USAGE: &'static str =
- "Command line Cabal wrapper for new-style builds
- Usage: cab [GLOBAL_FLAGS] [COMMAND [FLAGS]]
- cab for the most part has the exact same usage as Cabal, but it
- deliberately rewrites certain commands so that they are understood as
- the 'new-style project' commands.
- Certain old-style commands cannot be invoked through cab (as running
- `cab test' will always be treated as `cabal new-test` and not `cabal
- test') but any command which does not have a new-style equivalent
- (such as `check') will be run identically.
- Commands which differ from Cabal:
- cab build => cabal new-build
- cab configure => cabal new-configure
- cab conf => cabal new-configure
- cab repl => cabal new-repl
- cab run => cabal new-run
- cab test => cabal new-test
- cab bench => cabal new-bench
- cab freeze => cabal new-freeze
- cab haddock => cabal new-haddock
- cab update => cabal new-update
- cab install => cabal new-install
- cab exec => cabal new-exec
- ";
- /// A function which knows all the replaceable arguments. This will
- /// return None if it's not one of the new-style commands it knows
- /// about.
- fn replace(s: &str) -> Option<String> {
- Some(match s {
- "build" => "new-build".to_owned(),
- "configure" => "new-configure".to_owned(),
- "repl" => "new-repl".to_owned(),
- "run" => "new-run".to_owned(),
- "test" => "new-test".to_owned(),
- "bench" => "new-bench".to_owned(),
- "freeze" => "new-freeze".to_owned(),
- "haddock" => "new-haddock".to_owned(),
- s if s.starts_with("old-") =>
- s.trim_left_matches("old-").to_owned(),
- _ => None?,
- })
- }
- /// This is a tiny stateful iterator that has some logic around
- /// whether to rewrite arguments. (Not enough logic yet, I think, but
- /// this is fine for a first pass.)
- struct CabalArgs {
- seen_cmd: bool,
- args: env::Args,
- }
- impl CabalArgs {
- fn new() -> CabalArgs {
- let mut args = env::args();
- let _ = args.next();
- CabalArgs {
- seen_cmd: false,
- args: args,
- }
- }
- }
- impl Iterator for CabalArgs {
- type Item = String;
- fn next(&mut self) -> Option<String> {
- // Once we've seen a proper command, then we don't want to do
- // any kind of rewriting of the rest of it, so we just pass
- // the arguments on
- if self.seen_cmd {
- self.args.next()
- } else {
- // if we haven't seen a proper command yet, then we can
- // keep intercepting arguments
- self.args.next().and_then( |arg| {
- if &arg == "--help" {
- // if it's asking for help, then we should also
- // add a short note about how the usage for `cab`
- // is a bit different, but otherwise let `cabal`
- // print whatever it wants
- println!("{}", USAGE_HINT);
- Some(arg)
- } else if &arg == "--cab-help" {
- // We totally intercept --cab-help to display our
- // own full help string and leave it at that.
- println!("{}", USAGE);
- process::exit(0);
- } else if let Some(r) = replace(&arg) {
- // If there is a replacement for this fragment,
- // then we've now seen a command (and shouldn't do
- // anything else) but we should return the
- // replacement string (i.e. new-build for build)
- self.seen_cmd = true;
- Some(r)
- } else {
- // otherwise, keep going!
- Some(arg)
- }
- })
- }
- }
- }
- fn main() {
- process::Command::new("cabal")
- .args(CabalArgs::new())
- .exec();
- }
|