1 // Copyright 2015 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.
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.
11 // Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)
14 #![cfg(feature="cargo-fmt")]
17 extern crate rustc_serialize;
19 use std::path::PathBuf;
20 use std::process::Command;
25 use rustc_serialize::json::Json;
28 let mut opts = getopts::Options::new();
29 opts.optflag("h", "help", "show this message");
31 let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
34 print_usage(&opts, &e.to_string());
39 if matches.opt_present("h") {
40 print_usage(&opts, "");
46 fn print_usage(opts: &Options, reason: &str) {
47 let msg = format!("{}\nusage: cargo fmt [options]", reason);
48 println!("{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
49 Arguments after `--` are passes to rustfmt.",
53 fn format_crate(opts: &Options) {
54 let targets = match get_targets() {
57 print_usage(opts, &e.to_string());
62 // Currently only bin and lib files get formatted
63 let files: Vec<_> = targets.into_iter()
64 .filter(|t| t.kind.is_lib() | t.kind.is_bin())
68 format_files(&files, &get_fmt_args()).unwrap_or_else(|e| print_usage(opts, &e.to_string()));
71 fn get_fmt_args() -> Vec<String> {
72 let mut args = vec!["--write-mode=replace".to_string()];
73 // All arguments after -- are passed to rustfmt
74 args.extend(env::args().skip_while(|a| a != "--").skip(1));
81 Lib, // dylib, staticlib, lib
83 Other, // test, plugin,...
87 fn is_lib(&self) -> bool {
89 &TargetKind::Lib => true,
94 fn is_bin(&self) -> bool {
96 &TargetKind::Bin => true,
108 // Returns a vector of all compile targets of a crate
109 fn get_targets() -> Result<Vec<Target>, std::io::Error> {
110 let mut targets: Vec<Target> = vec![];
111 let output = try!(Command::new("cargo").arg("read-manifest").output());
112 if output.status.success() {
113 // None of the unwraps should fail if output of `cargo read-manifest` is correct
114 let data = &String::from_utf8(output.stdout).unwrap();
115 let json = Json::from_str(data).unwrap();
116 let jtargets = json.find("targets").unwrap().as_array().unwrap();
117 for jtarget in jtargets {
118 targets.push(target_from_json(jtarget));
123 // This happens when cargo-fmt is not used inside a crate
124 Err(std::io::Error::new(std::io::ErrorKind::NotFound,
125 str::from_utf8(&output.stderr).unwrap()))
129 fn target_from_json(jtarget: &Json) -> Target {
130 let jtarget = jtarget.as_object().unwrap();
131 let path = PathBuf::from(jtarget.get("src_path").unwrap().as_string().unwrap());
132 let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
133 let kind = match kinds[0].as_string().unwrap() {
134 "bin" => TargetKind::Bin,
135 "lib" | "dylib" | "staticlib" => TargetKind::Lib,
136 _ => TargetKind::Other,
145 fn format_files(files: &Vec<PathBuf>, fmt_args: &Vec<String>) -> Result<(), std::io::Error> {
146 let mut command = try!(Command::new("rustfmt")
150 try!(command.wait());