]> git.lizzy.rs Git - rust.git/blob - src/librust/rust.rs
auto merge of #7442 : graydon/rust/clean-llvm-trigger, r=brson
[rust.git] / src / librust / rust.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // rust - central access to other rust tools
12 // FIXME #2238 Make commands run and test emit proper file endings on windows
13 // FIXME #2238 Make run only accept source that emits an executable
14
15 #[link(name = "rust",
16        vers = "0.7-pre",
17        uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
18        url = "https://github.com/mozilla/rust/tree/master/src/rust")];
19
20 #[license = "MIT/ASL2"];
21 #[crate_type = "lib"];
22
23 #[no_std];
24
25 extern mod core(name = "std");
26
27 extern mod rustpkg;
28 extern mod rustdoc;
29 extern mod rusti;
30 extern mod rustc;
31
32 use core::prelude::*;
33
34 use core::io;
35 use core::os;
36 use core::run;
37 use core::libc::exit;
38
39 // For bootstrapping.
40 mod std {
41     pub use core::os;
42     pub use core::str;
43     pub use core::unstable;
44 }
45
46 enum ValidUsage {
47     Valid(int), Invalid
48 }
49
50 impl ValidUsage {
51     fn is_valid(&self) -> bool {
52         match *self {
53             Valid(_)   => true,
54             Invalid    => false
55         }
56     }
57 }
58
59 enum Action<'self> {
60     Call(&'self fn:Copy(args: &[~str]) -> ValidUsage),
61     CallMain(&'static str, &'self fn:Copy()),
62 }
63
64 enum UsageSource<'self> {
65     UsgStr(&'self str),
66     UsgCall(&'self fn:Copy()),
67 }
68
69 struct Command<'self> {
70     cmd: &'self str,
71     action: Action<'self>,
72     usage_line: &'self str,
73     usage_full: UsageSource<'self>,
74 }
75
76 static commands: &'static [Command<'static>] = &[
77     Command{
78         cmd: "build",
79         action: CallMain("rustc", rustc::main),
80         usage_line: "compile rust source files",
81         usage_full: UsgCall(rustc_help),
82     },
83     Command{
84         cmd: "run",
85         action: Call(cmd_run),
86         usage_line: "build an executable, and run it",
87         usage_full: UsgStr(
88             "The run command is an shortcut for the command line \n\
89              \"rustc <filename> -o <filestem>~ && ./<filestem>~ [<arguments>...]\".\
90             \n\nUsage:\trust run <filename> [<arguments>...]"
91         )
92     },
93     Command{
94         cmd: "test",
95         action: Call(cmd_test),
96         usage_line: "build a test executable, and run it",
97         usage_full: UsgStr(
98             "The test command is an shortcut for the command line \n\
99             \"rustc --test <filename> -o <filestem>test~ && \
100             ./<filestem>test~\"\n\nUsage:\trust test <filename>"
101         )
102     },
103     Command{
104         cmd: "doc",
105         action: CallMain("rustdoc", rustdoc::main),
106         usage_line: "generate documentation from doc comments",
107         usage_full: UsgCall(rustdoc::config::usage),
108     },
109     Command{
110         cmd: "pkg",
111         action: CallMain("rustpkg", rustpkg::main),
112         usage_line: "download, build, install rust packages",
113         usage_full: UsgCall(rustpkg::usage::general),
114     },
115     Command{
116         cmd: "sketch",
117         action: CallMain("rusti", rusti::main),
118         usage_line: "run a rust interpreter",
119         usage_full: UsgStr("\nUsage:\trusti"),
120     },
121     Command{
122         cmd: "help",
123         action: Call(cmd_help),
124         usage_line: "show detailed usage of a command",
125         usage_full: UsgStr(
126             "The help command displays the usage text of another command.\n\
127             The text is either build in, or provided by the corresponding \
128             program.\n\nUsage:\trust help <command>"
129         )
130     }
131 ];
132
133 fn rustc_help() {
134     rustc::usage(copy os::args()[0])
135 }
136
137 fn find_cmd(command_string: &str) -> Option<Command> {
138     do commands.iter().find_ |command| {
139         command.cmd == command_string
140     }.map_consume(|x| copy *x)
141 }
142
143 fn cmd_help(args: &[~str]) -> ValidUsage {
144     fn print_usage(command_string: ~str) -> ValidUsage {
145         match find_cmd(command_string) {
146             Some(command) => {
147                 match command.action {
148                     CallMain(prog, _) => io::println(fmt!(
149                         "The %s command is an alias for the %s program.",
150                         command.cmd, prog)),
151                     _       => ()
152                 }
153                 match command.usage_full {
154                     UsgStr(msg) => io::println(fmt!("%s\n", msg)),
155                     UsgCall(f)  => f(),
156                 }
157                 Valid(0)
158             },
159             None => Invalid
160         }
161     }
162
163     match args {
164         [ref command_string] => print_usage(copy *command_string),
165         _                    => Invalid
166     }
167 }
168
169 fn cmd_test(args: &[~str]) -> ValidUsage {
170     match args {
171         [ref filename] => {
172             let test_exec = Path(*filename).filestem().unwrap() + "test~";
173             invoke("rustc", &[~"--test", filename.to_owned(),
174                               ~"-o", test_exec.to_owned()], rustc::main);
175             let exit_code = run::process_status(~"./" + test_exec, []);
176             Valid(exit_code)
177         }
178         _ => Invalid
179     }
180 }
181
182 fn cmd_run(args: &[~str]) -> ValidUsage {
183     match args {
184         [ref filename, ..prog_args] => {
185             let exec = Path(*filename).filestem().unwrap() + "~";
186             invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()],
187                    rustc::main);
188             let exit_code = run::process_status(~"./"+exec, prog_args);
189             Valid(exit_code)
190         }
191         _ => Invalid
192     }
193 }
194
195 fn invoke(prog: &str, args: &[~str], f: &fn()) {
196     let mut osargs = ~[prog.to_owned()];
197     osargs.push_all_move(args.to_owned());
198     os::set_args(osargs);
199     f();
200 }
201
202 fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
203     match command.action {
204         Call(f) => f(args),
205         CallMain(prog, f) => {
206             invoke(prog, args, f);
207             Valid(0)
208         }
209     }
210 }
211
212 fn usage() {
213     static indent: uint = 8;
214
215     io::print(
216         "The rust tool is a convenience for managing rust source code.\n\
217         It acts as a shortcut for programs of the rust tool chain.\n\
218         \n\
219         Usage:\trust <command> [arguments]\n\
220         \n\
221         The commands are:\n\
222         \n"
223     );
224
225     for commands.iter().advance |command| {
226         let padding = " ".repeat(indent - command.cmd.len());
227         io::println(fmt!("    %s%s%s",
228                          command.cmd, padding, command.usage_line));
229     }
230
231     io::print(
232         "\n\
233         Use \"rust help <command>\" for more information about a command.\n\
234         \n"
235     );
236
237 }
238
239 pub fn main() {
240     let os_args = os::args();
241     let args = os_args.tail();
242
243     if !args.is_empty() {
244         let r = find_cmd(*args.head());
245         for r.iter().advance |command| {
246             let result = do_command(command, args.tail());
247             match result {
248                 Valid(exit_code) => unsafe { exit(exit_code.to_i32()) },
249                 _                => loop
250             }
251         }
252     }
253
254     usage();
255 }