From a24e15ded76d8a74bd7e646b9b5b877134fd0455 Mon Sep 17 00:00:00 2001
From: Caleb Cartwright <caleb.cartwright@outlook.com>
Date: Thu, 3 Oct 2019 17:11:46 -0500
Subject: [PATCH] feat: add offline flag to cargo fmt

---
 src/cargo-fmt/main.rs | 74 +++++++++++++++++++++++++++++++------------
 1 file changed, 54 insertions(+), 20 deletions(-)

diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs
index acaf81e0665..3f6b3cd32fa 100644
--- a/src/cargo-fmt/main.rs
+++ b/src/cargo-fmt/main.rs
@@ -56,6 +56,10 @@ pub struct Opts {
     /// Format all packages (only usable in workspaces)
     #[structopt(long = "all")]
     format_all: bool,
+
+    ///  Run without accessing the network
+    #[structopt(long = "offline")]
+    offline: bool,
 }
 
 fn main() {
@@ -112,6 +116,12 @@ fn execute() -> i32 {
         }
     }
 
+    let mut cargo_metadata_other_opts: Vec<String> = vec![];
+
+    if opts.offline {
+        cargo_metadata_other_opts.push(String::from("--offline"));
+    }
+
     if let Some(specified_manifest_path) = opts.manifest_path {
         if !specified_manifest_path.ends_with("Cargo.toml") {
             print_usage_to_stderr("the manifest-path must be a path to a Cargo.toml file");
@@ -123,9 +133,16 @@ fn execute() -> i32 {
             &strategy,
             rustfmt_args,
             Some(&manifest_path),
+            &cargo_metadata_other_opts,
         ))
     } else {
-        handle_command_status(format_crate(verbosity, &strategy, rustfmt_args, None))
+        handle_command_status(format_crate(
+            verbosity,
+            &strategy,
+            rustfmt_args,
+            None,
+            &cargo_metadata_other_opts,
+        ))
     }
 }
 
@@ -229,8 +246,9 @@ fn format_crate(
     strategy: &CargoFmtStrategy,
     rustfmt_args: Vec<String>,
     manifest_path: Option<&Path>,
+    cargo_metadata_other_opts: &[String],
 ) -> Result<i32, io::Error> {
-    let targets = get_targets(strategy, manifest_path)?;
+    let targets = get_targets(strategy, manifest_path, cargo_metadata_other_opts)?;
 
     // Currently only bin and lib files get formatted.
     run_rustfmt(&targets, &rustfmt_args, verbosity)
@@ -310,17 +328,26 @@ impl CargoFmtStrategy {
 fn get_targets(
     strategy: &CargoFmtStrategy,
     manifest_path: Option<&Path>,
+    cargo_metadata_other_opts: &[String],
 ) -> Result<BTreeSet<Target>, io::Error> {
     let mut targets = BTreeSet::new();
 
     match *strategy {
-        CargoFmtStrategy::Root => get_targets_root_only(manifest_path, &mut targets)?,
-        CargoFmtStrategy::All => {
-            get_targets_recursive(manifest_path, &mut targets, &mut BTreeSet::new())?
-        }
-        CargoFmtStrategy::Some(ref hitlist) => {
-            get_targets_with_hitlist(manifest_path, hitlist, &mut targets)?
+        CargoFmtStrategy::Root => {
+            get_targets_root_only(manifest_path, &mut targets, cargo_metadata_other_opts)?
         }
+        CargoFmtStrategy::All => get_targets_recursive(
+            manifest_path,
+            &mut targets,
+            &mut BTreeSet::new(),
+            cargo_metadata_other_opts,
+        )?,
+        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(
+            manifest_path,
+            hitlist,
+            &mut targets,
+            cargo_metadata_other_opts,
+        )?,
     }
 
     if targets.is_empty() {
@@ -336,8 +363,9 @@ fn get_targets(
 fn get_targets_root_only(
     manifest_path: Option<&Path>,
     targets: &mut BTreeSet<Target>,
+    cargo_metadata_other_opts: &[String],
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
+    let metadata = get_cargo_metadata(manifest_path, false, cargo_metadata_other_opts)?;
     let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
     let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path {
         (
@@ -380,9 +408,10 @@ fn get_targets_recursive(
     manifest_path: Option<&Path>,
     mut targets: &mut BTreeSet<Target>,
     visited: &mut BTreeSet<String>,
+    cargo_metadata_other_opts: &[String],
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
-    let metadata_with_deps = get_cargo_metadata(manifest_path, true)?;
+    let metadata = get_cargo_metadata(manifest_path, false, cargo_metadata_other_opts)?;
+    let metadata_with_deps = get_cargo_metadata(manifest_path, true, cargo_metadata_other_opts)?;
 
     for package in metadata.packages {
         add_targets(&package.targets, &mut targets);
@@ -409,7 +438,12 @@ fn get_targets_recursive(
 
             if manifest_path.exists() {
                 visited.insert(dependency.name);
-                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
+                get_targets_recursive(
+                    Some(&manifest_path),
+                    &mut targets,
+                    visited,
+                    cargo_metadata_other_opts,
+                )?;
             }
         }
     }
@@ -421,8 +455,9 @@ fn get_targets_with_hitlist(
     manifest_path: Option<&Path>,
     hitlist: &[String],
     targets: &mut BTreeSet<Target>,
+    cargo_metadata_other_opts: &[String],
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
+    let metadata = get_cargo_metadata(manifest_path, false, cargo_metadata_other_opts)?;
 
     let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);
 
@@ -511,6 +546,7 @@ fn run_rustfmt(
 fn get_cargo_metadata(
     manifest_path: Option<&Path>,
     include_deps: bool,
+    other_opts: &[String],
 ) -> Result<cargo_metadata::Metadata, io::Error> {
     let mut cmd = cargo_metadata::MetadataCommand::new();
     if !include_deps {
@@ -519,16 +555,11 @@ fn get_cargo_metadata(
     if let Some(manifest_path) = manifest_path {
         cmd.manifest_path(manifest_path);
     }
+    cmd.other_options(other_opts);
 
     match cmd.exec() {
         Ok(metadata) => Ok(metadata),
-        Err(_) => {
-            cmd.other_options(&[String::from("--offline")]);
-            match cmd.exec() {
-                Ok(metadata) => Ok(metadata),
-                Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
-            }
-        }
+        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
     }
 }
 
@@ -543,6 +574,7 @@ mod cargo_fmt_tests {
         assert_eq!(false, o.quiet);
         assert_eq!(false, o.verbose);
         assert_eq!(false, o.version);
+        assert_eq!(false, o.offline);
         assert_eq!(empty, o.packages);
         assert_eq!(empty, o.rustfmt_options);
         assert_eq!(false, o.format_all);
@@ -561,6 +593,7 @@ mod cargo_fmt_tests {
             "p2",
             "--message-format",
             "short",
+            "--offline",
             "--",
             "--edition",
             "2018",
@@ -568,6 +601,7 @@ mod cargo_fmt_tests {
         assert_eq!(true, o.quiet);
         assert_eq!(false, o.verbose);
         assert_eq!(false, o.version);
+        assert_eq!(true, o.offline);
         assert_eq!(vec!["p1", "p2"], o.packages);
         assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
         assert_eq!(false, o.format_all);