]> git.lizzy.rs Git - rust.git/commitdiff
Create cargo-fmt crate
authortopecongiro <seuchida@gmail.com>
Wed, 7 Feb 2018 13:49:10 +0000 (22:49 +0900)
committertopecongiro <seuchida@gmail.com>
Wed, 7 Feb 2018 13:49:10 +0000 (22:49 +0900)
cargo-fmt/Cargo.toml [new file with mode: 0644]
cargo-fmt/src/main.rs [new file with mode: 0644]
src/bin/cargo-fmt.rs [deleted file]

diff --git a/cargo-fmt/Cargo.toml b/cargo-fmt/Cargo.toml
new file mode 100644 (file)
index 0000000..8714265
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+name = "cargo-fmt"
+version = "0.4.0"
+authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
+description = "Cargo frontend for rustfmt"
+repository = "https://github.com/rust-lang-nursery/rustfmt"
+readme = "README.md"
+license = "Apache-2.0/MIT"
+categories = ["development-tools"]
+
+[[bin]]
+name = "cargo-fmt"
+
+[dependencies]
+cargo_metadata = "0.4"
+getopts = "0.2"
+serde_json = "1.0"
diff --git a/cargo-fmt/src/main.rs b/cargo-fmt/src/main.rs
new file mode 100644 (file)
index 0000000..1acad99
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2015-2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)
+
+#![cfg(not(test))]
+#![deny(warnings)]
+
+extern crate cargo_metadata;
+extern crate getopts;
+extern crate serde_json as json;
+
+use std::collections::HashSet;
+use std::env;
+use std::fs;
+use std::hash::{Hash, Hasher};
+use std::io::{self, Write};
+use std::iter::FromIterator;
+use std::path::{Path, PathBuf};
+use std::process::{Command, ExitStatus};
+use std::str;
+
+use getopts::{Matches, Options};
+
+fn main() {
+    let exit_status = execute();
+    std::io::stdout().flush().unwrap();
+    std::process::exit(exit_status);
+}
+
+const SUCCESS: i32 = 0;
+const FAILURE: i32 = 1;
+
+fn execute() -> i32 {
+    let mut opts = getopts::Options::new();
+    opts.optflag("h", "help", "show this message");
+    opts.optflag("q", "quiet", "no output printed to stdout");
+    opts.optflag("v", "verbose", "use verbose output");
+    opts.optmulti(
+        "p",
+        "package",
+        "specify package to format (only usable in workspaces)",
+        "<package>",
+    );
+    opts.optflag("", "version", "print rustfmt version and exit");
+    opts.optflag("", "all", "format all packages (only usable in workspaces)");
+
+    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
+    let mut is_package_arg = false;
+    for arg in env::args().skip(2).take_while(|a| a != "--") {
+        if arg.starts_with('-') {
+            is_package_arg = arg.starts_with("--package");
+        } else if !is_package_arg {
+            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
+            return FAILURE;
+        } else {
+            is_package_arg = false;
+        }
+    }
+
+    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
+        Ok(m) => m,
+        Err(e) => {
+            print_usage_to_stderr(&opts, &e.to_string());
+            return FAILURE;
+        }
+    };
+
+    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
+        (false, false) => Verbosity::Normal,
+        (false, true) => Verbosity::Quiet,
+        (true, false) => Verbosity::Verbose,
+        (true, true) => {
+            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
+            return FAILURE;
+        }
+    };
+
+    if matches.opt_present("h") {
+        print_usage_to_stdout(&opts, "");
+        return SUCCESS;
+    }
+
+    if matches.opt_present("version") {
+        return handle_command_status(get_version(verbosity), &opts);
+    }
+
+    let strategy = CargoFmtStrategy::from_matches(&matches);
+    handle_command_status(format_crate(verbosity, &strategy), &opts)
+}
+
+macro_rules! print_usage {
+    ($print: ident, $opts: ident, $reason: expr) => {{
+        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
+        $print!(
+            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
+             Arguments after `--` are passed to rustfmt.",
+            $opts.usage(&msg)
+        );
+    }};
+}
+
+fn print_usage_to_stdout(opts: &Options, reason: &str) {
+    print_usage!(println, opts, reason);
+}
+
+fn print_usage_to_stderr(opts: &Options, reason: &str) {
+    print_usage!(eprintln, opts, reason);
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Verbosity {
+    Verbose,
+    Normal,
+    Quiet,
+}
+
+fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
+    match status {
+        Err(e) => {
+            print_usage_to_stderr(opts, &e.to_string());
+            FAILURE
+        }
+        Ok(status) => {
+            if status.success() {
+                SUCCESS
+            } else {
+                status.code().unwrap_or(FAILURE)
+            }
+        }
+    }
+}
+
+fn get_version(verbosity: Verbosity) -> Result<ExitStatus, io::Error> {
+    run_rustfmt(&[], &[String::from("--version")], verbosity)
+}
+
+fn format_crate(
+    verbosity: Verbosity,
+    strategy: &CargoFmtStrategy,
+) -> Result<ExitStatus, io::Error> {
+    let rustfmt_args = get_fmt_args();
+    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
+        HashSet::new()
+    } else {
+        get_targets(strategy)?
+    };
+
+    // Currently only bin and lib files get formatted
+    let files: Vec<_> = targets
+        .into_iter()
+        .inspect(|t| {
+            if verbosity == Verbosity::Verbose {
+                println!("[{}] {:?}", t.kind, t.path)
+            }
+        })
+        .map(|t| t.path)
+        .collect();
+
+    run_rustfmt(&files, &rustfmt_args, verbosity)
+}
+
+fn get_fmt_args() -> Vec<String> {
+    // All arguments after -- are passed to rustfmt
+    env::args().skip_while(|a| a != "--").skip(1).collect()
+}
+
+/// Target uses a `path` field for equality and hashing.
+#[derive(Debug)]
+pub struct Target {
+    /// A path to the main source file of the target.
+    path: PathBuf,
+    /// A kind of target (e.g. lib, bin, example, ...).
+    kind: String,
+}
+
+impl Target {
+    pub fn from_target(target: &cargo_metadata::Target) -> Self {
+        let path = PathBuf::from(&target.src_path);
+        let canonicalized = fs::canonicalize(&path).unwrap_or(path);
+
+        Target {
+            path: canonicalized,
+            kind: target.kind[0].clone(),
+        }
+    }
+}
+
+impl PartialEq for Target {
+    fn eq(&self, other: &Target) -> bool {
+        self.path == other.path
+    }
+}
+
+impl Eq for Target {}
+
+impl Hash for Target {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.path.hash(state);
+    }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum CargoFmtStrategy {
+    /// Format every packages and dependencies.
+    All,
+    /// Format pacakges that are specified by the command line argument.
+    Some(Vec<String>),
+    /// Format the root packages only.
+    Root,
+}
+
+impl CargoFmtStrategy {
+    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
+        match (matches.opt_present("all"), matches.opt_present("p")) {
+            (false, false) => CargoFmtStrategy::Root,
+            (true, _) => CargoFmtStrategy::All,
+            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
+        }
+    }
+}
+
+/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
+fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
+    let mut targets = HashSet::new();
+
+    match *strategy {
+        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
+        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
+        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
+    }
+
+    if targets.is_empty() {
+        Err(io::Error::new(
+            io::ErrorKind::Other,
+            "Failed to find targets".to_owned(),
+        ))
+    } else {
+        Ok(targets)
+    }
+}
+
+fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
+    let metadata = get_cargo_metadata(None)?;
+
+    for package in metadata.packages {
+        for target in package.targets {
+            targets.insert(Target::from_target(&target));
+        }
+    }
+
+    Ok(())
+}
+
+fn get_targets_recursive(
+    manifest_path: Option<&Path>,
+    mut targets: &mut HashSet<Target>,
+    visited: &mut HashSet<String>,
+) -> Result<(), io::Error> {
+    let metadata = get_cargo_metadata(manifest_path)?;
+
+    for package in metadata.packages {
+        add_targets(&package.targets, &mut targets);
+
+        // Look for local dependencies.
+        for dependency in package.dependencies {
+            if dependency.source.is_some() || visited.contains(&dependency.name) {
+                continue;
+            }
+
+            let mut manifest_path = PathBuf::from(&package.manifest_path);
+
+            manifest_path.pop();
+            manifest_path.push(&dependency.name);
+            manifest_path.push("Cargo.toml");
+
+            if manifest_path.exists() {
+                visited.insert(dependency.name);
+                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
+            }
+        }
+    }
+
+    Ok(())
+}
+
+fn get_targets_with_hitlist(
+    hitlist: &[String],
+    targets: &mut HashSet<Target>,
+) -> Result<(), io::Error> {
+    let metadata = get_cargo_metadata(None)?;
+
+    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);
+
+    for package in metadata.packages {
+        if workspace_hitlist.remove(&package.name) {
+            for target in package.targets {
+                targets.insert(Target::from_target(&target));
+            }
+        }
+    }
+
+    if workspace_hitlist.is_empty() {
+        Ok(())
+    } else {
+        let package = workspace_hitlist.iter().next().unwrap();
+        Err(io::Error::new(
+            io::ErrorKind::InvalidInput,
+            format!("package `{}` is not a member of the workspace", package),
+        ))
+    }
+}
+
+fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
+    for target in target_paths {
+        targets.insert(Target::from_target(target));
+    }
+}
+
+fn run_rustfmt(
+    files: &[PathBuf],
+    fmt_args: &[String],
+    verbosity: Verbosity,
+) -> Result<ExitStatus, io::Error> {
+    let stdout = if verbosity == Verbosity::Quiet {
+        std::process::Stdio::null()
+    } else {
+        std::process::Stdio::inherit()
+    };
+
+    if verbosity == Verbosity::Verbose {
+        print!("rustfmt");
+        for a in fmt_args {
+            print!(" {}", a);
+        }
+        for f in files {
+            print!(" {}", f.display());
+        }
+        println!();
+    }
+
+    let mut command = Command::new("rustfmt")
+        .stdout(stdout)
+        .args(files)
+        .args(fmt_args)
+        .spawn()
+        .map_err(|e| match e.kind() {
+            io::ErrorKind::NotFound => io::Error::new(
+                io::ErrorKind::Other,
+                "Could not run rustfmt, please make sure it is in your PATH.",
+            ),
+            _ => e,
+        })?;
+
+    command.wait()
+}
+
+fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
+    match cargo_metadata::metadata(manifest_path) {
+        Ok(metadata) => Ok(metadata),
+        Err(..) => Err(io::Error::new(
+            io::ErrorKind::Other,
+            "`cargo manifest` failed.",
+        )),
+    }
+}
diff --git a/src/bin/cargo-fmt.rs b/src/bin/cargo-fmt.rs
deleted file mode 100644 (file)
index 1acad99..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2015-2016 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)
-
-#![cfg(not(test))]
-#![deny(warnings)]
-
-extern crate cargo_metadata;
-extern crate getopts;
-extern crate serde_json as json;
-
-use std::collections::HashSet;
-use std::env;
-use std::fs;
-use std::hash::{Hash, Hasher};
-use std::io::{self, Write};
-use std::iter::FromIterator;
-use std::path::{Path, PathBuf};
-use std::process::{Command, ExitStatus};
-use std::str;
-
-use getopts::{Matches, Options};
-
-fn main() {
-    let exit_status = execute();
-    std::io::stdout().flush().unwrap();
-    std::process::exit(exit_status);
-}
-
-const SUCCESS: i32 = 0;
-const FAILURE: i32 = 1;
-
-fn execute() -> i32 {
-    let mut opts = getopts::Options::new();
-    opts.optflag("h", "help", "show this message");
-    opts.optflag("q", "quiet", "no output printed to stdout");
-    opts.optflag("v", "verbose", "use verbose output");
-    opts.optmulti(
-        "p",
-        "package",
-        "specify package to format (only usable in workspaces)",
-        "<package>",
-    );
-    opts.optflag("", "version", "print rustfmt version and exit");
-    opts.optflag("", "all", "format all packages (only usable in workspaces)");
-
-    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
-    let mut is_package_arg = false;
-    for arg in env::args().skip(2).take_while(|a| a != "--") {
-        if arg.starts_with('-') {
-            is_package_arg = arg.starts_with("--package");
-        } else if !is_package_arg {
-            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
-            return FAILURE;
-        } else {
-            is_package_arg = false;
-        }
-    }
-
-    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
-        Ok(m) => m,
-        Err(e) => {
-            print_usage_to_stderr(&opts, &e.to_string());
-            return FAILURE;
-        }
-    };
-
-    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
-        (false, false) => Verbosity::Normal,
-        (false, true) => Verbosity::Quiet,
-        (true, false) => Verbosity::Verbose,
-        (true, true) => {
-            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
-            return FAILURE;
-        }
-    };
-
-    if matches.opt_present("h") {
-        print_usage_to_stdout(&opts, "");
-        return SUCCESS;
-    }
-
-    if matches.opt_present("version") {
-        return handle_command_status(get_version(verbosity), &opts);
-    }
-
-    let strategy = CargoFmtStrategy::from_matches(&matches);
-    handle_command_status(format_crate(verbosity, &strategy), &opts)
-}
-
-macro_rules! print_usage {
-    ($print: ident, $opts: ident, $reason: expr) => {{
-        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
-        $print!(
-            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
-             Arguments after `--` are passed to rustfmt.",
-            $opts.usage(&msg)
-        );
-    }};
-}
-
-fn print_usage_to_stdout(opts: &Options, reason: &str) {
-    print_usage!(println, opts, reason);
-}
-
-fn print_usage_to_stderr(opts: &Options, reason: &str) {
-    print_usage!(eprintln, opts, reason);
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Verbosity {
-    Verbose,
-    Normal,
-    Quiet,
-}
-
-fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
-    match status {
-        Err(e) => {
-            print_usage_to_stderr(opts, &e.to_string());
-            FAILURE
-        }
-        Ok(status) => {
-            if status.success() {
-                SUCCESS
-            } else {
-                status.code().unwrap_or(FAILURE)
-            }
-        }
-    }
-}
-
-fn get_version(verbosity: Verbosity) -> Result<ExitStatus, io::Error> {
-    run_rustfmt(&[], &[String::from("--version")], verbosity)
-}
-
-fn format_crate(
-    verbosity: Verbosity,
-    strategy: &CargoFmtStrategy,
-) -> Result<ExitStatus, io::Error> {
-    let rustfmt_args = get_fmt_args();
-    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
-        HashSet::new()
-    } else {
-        get_targets(strategy)?
-    };
-
-    // Currently only bin and lib files get formatted
-    let files: Vec<_> = targets
-        .into_iter()
-        .inspect(|t| {
-            if verbosity == Verbosity::Verbose {
-                println!("[{}] {:?}", t.kind, t.path)
-            }
-        })
-        .map(|t| t.path)
-        .collect();
-
-    run_rustfmt(&files, &rustfmt_args, verbosity)
-}
-
-fn get_fmt_args() -> Vec<String> {
-    // All arguments after -- are passed to rustfmt
-    env::args().skip_while(|a| a != "--").skip(1).collect()
-}
-
-/// Target uses a `path` field for equality and hashing.
-#[derive(Debug)]
-pub struct Target {
-    /// A path to the main source file of the target.
-    path: PathBuf,
-    /// A kind of target (e.g. lib, bin, example, ...).
-    kind: String,
-}
-
-impl Target {
-    pub fn from_target(target: &cargo_metadata::Target) -> Self {
-        let path = PathBuf::from(&target.src_path);
-        let canonicalized = fs::canonicalize(&path).unwrap_or(path);
-
-        Target {
-            path: canonicalized,
-            kind: target.kind[0].clone(),
-        }
-    }
-}
-
-impl PartialEq for Target {
-    fn eq(&self, other: &Target) -> bool {
-        self.path == other.path
-    }
-}
-
-impl Eq for Target {}
-
-impl Hash for Target {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.path.hash(state);
-    }
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum CargoFmtStrategy {
-    /// Format every packages and dependencies.
-    All,
-    /// Format pacakges that are specified by the command line argument.
-    Some(Vec<String>),
-    /// Format the root packages only.
-    Root,
-}
-
-impl CargoFmtStrategy {
-    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
-        match (matches.opt_present("all"), matches.opt_present("p")) {
-            (false, false) => CargoFmtStrategy::Root,
-            (true, _) => CargoFmtStrategy::All,
-            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
-        }
-    }
-}
-
-/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
-fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
-    let mut targets = HashSet::new();
-
-    match *strategy {
-        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
-        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
-        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
-    }
-
-    if targets.is_empty() {
-        Err(io::Error::new(
-            io::ErrorKind::Other,
-            "Failed to find targets".to_owned(),
-        ))
-    } else {
-        Ok(targets)
-    }
-}
-
-fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(None)?;
-
-    for package in metadata.packages {
-        for target in package.targets {
-            targets.insert(Target::from_target(&target));
-        }
-    }
-
-    Ok(())
-}
-
-fn get_targets_recursive(
-    manifest_path: Option<&Path>,
-    mut targets: &mut HashSet<Target>,
-    visited: &mut HashSet<String>,
-) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path)?;
-
-    for package in metadata.packages {
-        add_targets(&package.targets, &mut targets);
-
-        // Look for local dependencies.
-        for dependency in package.dependencies {
-            if dependency.source.is_some() || visited.contains(&dependency.name) {
-                continue;
-            }
-
-            let mut manifest_path = PathBuf::from(&package.manifest_path);
-
-            manifest_path.pop();
-            manifest_path.push(&dependency.name);
-            manifest_path.push("Cargo.toml");
-
-            if manifest_path.exists() {
-                visited.insert(dependency.name);
-                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
-            }
-        }
-    }
-
-    Ok(())
-}
-
-fn get_targets_with_hitlist(
-    hitlist: &[String],
-    targets: &mut HashSet<Target>,
-) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(None)?;
-
-    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);
-
-    for package in metadata.packages {
-        if workspace_hitlist.remove(&package.name) {
-            for target in package.targets {
-                targets.insert(Target::from_target(&target));
-            }
-        }
-    }
-
-    if workspace_hitlist.is_empty() {
-        Ok(())
-    } else {
-        let package = workspace_hitlist.iter().next().unwrap();
-        Err(io::Error::new(
-            io::ErrorKind::InvalidInput,
-            format!("package `{}` is not a member of the workspace", package),
-        ))
-    }
-}
-
-fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
-    for target in target_paths {
-        targets.insert(Target::from_target(target));
-    }
-}
-
-fn run_rustfmt(
-    files: &[PathBuf],
-    fmt_args: &[String],
-    verbosity: Verbosity,
-) -> Result<ExitStatus, io::Error> {
-    let stdout = if verbosity == Verbosity::Quiet {
-        std::process::Stdio::null()
-    } else {
-        std::process::Stdio::inherit()
-    };
-
-    if verbosity == Verbosity::Verbose {
-        print!("rustfmt");
-        for a in fmt_args {
-            print!(" {}", a);
-        }
-        for f in files {
-            print!(" {}", f.display());
-        }
-        println!();
-    }
-
-    let mut command = Command::new("rustfmt")
-        .stdout(stdout)
-        .args(files)
-        .args(fmt_args)
-        .spawn()
-        .map_err(|e| match e.kind() {
-            io::ErrorKind::NotFound => io::Error::new(
-                io::ErrorKind::Other,
-                "Could not run rustfmt, please make sure it is in your PATH.",
-            ),
-            _ => e,
-        })?;
-
-    command.wait()
-}
-
-fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
-    match cargo_metadata::metadata(manifest_path) {
-        Ok(metadata) => Ok(metadata),
-        Err(..) => Err(io::Error::new(
-            io::ErrorKind::Other,
-            "`cargo manifest` failed.",
-        )),
-    }
-}