Skip to content

Instantly share code, notes, and snippets.

@qryxip
Last active November 18, 2019 03:40
Show Gist options
  • Select an option

  • Save qryxip/bb4eef6135b5d3961004f5ab5927422d to your computer and use it in GitHub Desktop.

Select an option

Save qryxip/bb4eef6135b5d3961004f5ab5927422d to your computer and use it in GitHub Desktop.
//! ```toml
//! [package]
//! edition = "2018"
//! name = "cargo-touch-workspace"
//! version = "0.0.0"
//! authors = ["Ryo Yamashita <[email protected]>"]
//! description = "Touch the source files in the workspace."
//! publish = false
//! license = "CC0-1.0"
//!
//! [dependencies]
//! anyhow = "1.0.20"
//! atty = "0.2.13"
//! cargo_metadata = "0.9.0"
//! filetime = "0.2.8"
//! structopt = "0.3.4"
//! tracing = "0.1.10"
//! tracing-subscriber = "0.1.6"
//! ```
use anyhow::Context as _;
use cargo_metadata::MetadataCommand;
use filetime::FileTime;
use structopt::StructOpt;
use tracing::{info, Level};
use tracing_subscriber::FmtSubscriber;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
#[derive(Debug, StructOpt)]
#[structopt(author, about, bin_name("cargo"))]
enum Cargo {
#[structopt(
author,
about,
after_help(
r#"This Cargo subcommand does almost the same thing as the following Bash script.
​```
cargo metadata --format-version 1 |
jq -r '.workspace_members[] as $members | .packages[] | select(.id == $members) | .targets[].src_path' |
xargs touch
​```
"#,
)
)]
TouchWorkspace(CargoTouchWorkspace),
}
#[derive(Debug, StructOpt)]
struct CargoTouchWorkspace {
#[structopt(long, help("Path to Cargo.toml"))]
manifest_path: Option<PathBuf>,
}
fn main() -> anyhow::Result<()> {
let Cargo::TouchWorkspace(CargoTouchWorkspace { manifest_path }) = Cargo::from_args();
FmtSubscriber::builder()
.without_time()
.with_ansi(should_enable_color_for_stderr())
.with_max_level(Level::INFO)
.init();
let mut cmd = MetadataCommand::new();
if let Some(manifest_path) = manifest_path {
cmd.manifest_path(manifest_path);
}
let metadata = cmd.exec()?;
let members = metadata.workspace_members.iter().collect::<HashSet<_>>();
metadata
.packages
.iter()
.filter(|p| members.contains(&p.id))
.flat_map(|p| &p.targets)
.try_for_each(|t| touch(&t.src_path))
}
#[cfg(not(windows))]
fn should_enable_color_for_stderr() -> bool {
use std::env;
atty::is(atty::Stream::Stderr) && env::var("TERM").ok().map_or(false, |v| v != "dumb")
}
#[cfg(windows)]
fn should_enable_color_for_stderr() -> bool {
use tracing::warn;
warn!("TODO");
false
}
fn touch(path: impl AsRef<Path>) -> anyhow::Result<()> {
let now = FileTime::from_system_time(SystemTime::now());
filetime::set_file_times(&path, now, now)
.with_context(|| format!("Failed to touch {}", path.as_ref().display()))?;
info!("Touched {}", path.as_ref().display());
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment