From 0982207f4954ed5d5069249a08060bc911589982 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 20 Nov 2019 17:52:27 +0900 Subject: [PATCH] Handle ctrl-c --- Cargo.lock | 48 +++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/main.rs | 82 +++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 111 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96b4a7c6..a6ed597e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "anyhow" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -15,6 +15,11 @@ name = "autocfg" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.2" @@ -24,7 +29,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "cargo-hack" version = "0.3.0" dependencies = [ - "anyhow 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "easy-ext 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", @@ -34,6 +40,16 @@ dependencies = [ "toml_edit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "chrono" version = "0.4.9" @@ -57,6 +73,15 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ctrlc" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "easy-ext" version = "0.1.6" @@ -91,6 +116,18 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.41" @@ -260,18 +297,23 @@ dependencies = [ ] [metadata] -"checksum anyhow 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "73232834f4ba605439f8ab8e134569bc52e29d19e7ec2d910c73fd6e8af46557" +"checksum anyhow 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "e19f23ab207147bbdbcdfa7f7e4ca5e84963d79bae3937074682177ab9150968" "checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +"checksum ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" "checksum easy-ext 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ed79d40452cc72aa676b63ddde7f415865b412984738a1ba11096615ab0b262c" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" diff --git a/Cargo.toml b/Cargo.toml index 4d7adf33..b95cc46a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,8 @@ A tool to work around some limitations on cargo. [workspace] [dependencies] -anyhow = "1.0.20" +anyhow = "1.0.22" +ctrlc = "3.1.3" serde = "1.0.102" # Depends directly on `serde_derive` instead of using `derive` feature of # `serde` to reduce compile time. When pipeline compilation for proc-macro is diff --git a/src/main.rs b/src/main.rs index 01e71c15..0b0a2c41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,16 @@ mod manifest; mod metadata; mod process; -use std::{env, ffi::OsString, fs, path::Path}; +use std::{ + env, + ffi::OsString, + fs, + path::{Path, PathBuf}, + sync::{ + atomic::{AtomicBool, Ordering::SeqCst}, + Arc, Mutex, + }, +}; use anyhow::{bail, Context, Error}; @@ -121,33 +130,70 @@ fn no_dev_deps( manifest: &Manifest, line: &ProcessBuilder, ) -> Result<()> { - struct Bomb<'a> { - manifest: &'a Manifest, - args: &'a Args, - done: bool, - res: &'a mut Result<()>, + struct Restore { + manifest: String, + manifest_path: PathBuf, + color: Option, + restore: AtomicBool, + done: AtomicBool, + res: Arc>>>, } - impl Drop for Bomb<'_> { - fn drop(&mut self) { - if !self.args.remove_dev_deps { - let res = fs::write(&self.manifest.path, &self.manifest.raw).with_context(|| { - format!("failed to restore manifest file: {}", self.manifest.path.display()) + impl Restore { + #[allow(clippy::type_complexity)] + fn new( + args: &Args, + manifest: &Manifest, + ) -> (Bomb, Arc, Arc>>>) { + let res = Arc::new(Mutex::new(Some(Ok(())))); + + let bomb = Arc::new(Self { + manifest: manifest.raw.to_string(), + manifest_path: manifest.path.to_path_buf(), + color: args.color, + // if `--remove-dev-deps` flag is off, restore manifest file. + restore: AtomicBool::new(args.no_dev_deps && !args.remove_dev_deps), + done: AtomicBool::new(false), + res: res.clone(), + }); + + (Bomb(bomb.clone()), bomb, res) + } + + fn restore_dev_deps(&self) { + if self.restore.load(SeqCst) { + let res = fs::write(&self.manifest_path, &self.manifest).with_context(|| { + format!("failed to restore manifest file: {}", self.manifest_path.display()) }); - if self.done { - *self.res = res; + if self.done.load(SeqCst) { + *self.res.lock().unwrap() = Some(res); } else if let Err(e) = res { - error!(self.args.color, "{:#}", e); + error!(self.color, "{:#}", e); } + + self.restore.store(false, SeqCst); } } } + struct Bomb(Arc); + + impl Drop for Bomb { + fn drop(&mut self) { + self.0.restore_dev_deps(); + } + } + if args.no_dev_deps || args.remove_dev_deps { - let mut res = Ok(()); let new = manifest.remove_dev_deps()?; - let mut bomb = Bomb { manifest, args, done: false, res: &mut res }; + let (bomb, restore, res) = Restore::new(args, manifest); + + ctrlc::set_handler(move || { + restore.restore_dev_deps(); + std::process::exit(0) + }) + .unwrap(); fs::write(&package.manifest_path, new).with_context(|| { format!("failed to update manifest file: {}", package.manifest_path.display()) @@ -157,9 +203,9 @@ fn no_dev_deps( each_feature(args, package, line)?; } - bomb.done = true; + bomb.0.done.store(true, SeqCst); drop(bomb); - res?; + res.lock().unwrap().take().unwrap()?; } else if args.subcommand.is_some() { each_feature(args, package, line)?; }