diff --git a/.idea/.idea.gradle-util-rs.dir/.idea/indexLayout.xml b/.idea/.idea.gradle-util-rs.dir/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.gradle-util-rs.dir/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.gradle-util-rs.dir/.idea/projectSettingsUpdater.xml b/.idea/.idea.gradle-util-rs.dir/.idea/projectSettingsUpdater.xml
new file mode 100644
index 0000000..4bb9f4d
--- /dev/null
+++ b/.idea/.idea.gradle-util-rs.dir/.idea/projectSettingsUpdater.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.gradle-util-rs.dir/.idea/workspace.xml b/.idea/.idea.gradle-util-rs.dir/.idea/workspace.xml
new file mode 100644
index 0000000..f60f699
--- /dev/null
+++ b/.idea/.idea.gradle-util-rs.dir/.idea/workspace.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "keyToString": {
+ "WebServerToolWindowFactoryState": "false",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
+ "vue.rearranger.settings.migration": "true"
+ }
+}
+
+
+
+
+
+
+
+ $USER_HOME$/.subversion
+
+
+
+
+ 1644642687414
+
+
+ 1644642687414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 01ba70e..f73f3c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -46,6 +46,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits",
+ "time",
+ "winapi 0.3.9",
+]
+
[[package]]
name = "clap"
version = "3.0.14"
@@ -138,13 +151,15 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "gradle-util-rs"
-version = "0.1.0-alpha.2"
+version = "0.1.0-alpha.3"
dependencies = [
+ "chrono",
"clap",
"env_logger",
"humantime",
"log",
"notify",
+ "termcolor",
]
[[package]]
@@ -328,6 +343,25 @@ dependencies = [
"winapi 0.3.9",
]
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "os_str_bytes"
version = "6.0.0"
@@ -452,6 +486,17 @@ version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi",
+ "winapi 0.3.9",
+]
+
[[package]]
name = "unicode-xid"
version = "0.2.2"
@@ -475,6 +520,12 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
[[package]]
name = "winapi"
version = "0.2.8"
diff --git a/Cargo.toml b/Cargo.toml
index ca6652f..a496862 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "gradle-util-rs"
-version = "0.1.0-alpha.2"
+version = "0.1.0-alpha.3"
edition = "2021"
description = "Gradle util written in Rust"
repository = "https://github.com/jason5lee/gradle-util-rs"
@@ -14,6 +14,8 @@ notify = "4.0"
env_logger = "0.9"
clap = { version = "3.0", features = ["derive"] }
humantime = "2.1"
+termcolor = "1.1"
+chrono = "0.4"
[[bin]]
name = "gur"
diff --git a/README.md b/README.md
index 5fb4f4b..967802e 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Note that this project is still in the alpha stage. The functionalities and beha
## Install
-You can find the pre-built binaries at the [release page](https://github.com/jason5lee/gradle-util-rs/releases). You can build and install it via `cargo install gradle-util-rs --version 0.1.0-alpha.2`.
+You can find the pre-built binaries at the [release page](https://github.com/jason5lee/gradle-util-rs/releases). You can build and install it via `cargo install gradle-util-rs --version 0.1.0-alpha.3`.
## Usage
@@ -30,7 +30,7 @@ This is made as a workaround of [IDEA-177325](https://youtrack.jetbrains.com/iss
Example:
-`gur set-new 7.3.3 --watch-dir path1 --watch-dir path2` : watch the gradle project creation under `path1` and `path2` recursively, and create the gradle wrapper properties for the new projects using gradle version `7.3.3`.
+`gur set-new 7.3.3 path1 path2` : watch the gradle project creation under `path1` and `path2` recursively, and create the gradle wrapper properties for the new projects using gradle version `7.3.3`.
### `chver`
@@ -48,6 +48,7 @@ You might be surprised that a Gradle utility is written in Rust instead of Java
The major reason is that Gradle already requires a java instance to run. I don't want yet another java process.
Instead, just keep it as light as possible.
-The reason I choose Rust instead of C/C++ or any others is that its mental model is surprisingly closed to Kotlin, the
+The reason I choose Rust is that its mental model is surprisingly closed to Kotlin, the
major language I used with Gradle. Many building blocks in Kotlin like data class, sealed class and nullable type have their
corresponding in Rust like struct, enum and option.
+
diff --git a/src/bin/gur.rs b/src/bin/gur.rs
index f42af50..50a8516 100644
--- a/src/bin/gur.rs
+++ b/src/bin/gur.rs
@@ -1,5 +1,6 @@
use clap::{Parser, Subcommand};
use gradle_util_rs::LoggedSideEffect;
+use std::path::PathBuf;
use std::time::Duration;
#[derive(Parser)]
@@ -13,14 +14,17 @@ struct Cli {
enum Command {
#[clap(about = "Watch for the new Gradle project and set the gradle version")]
SetNew {
- #[clap(help = "The gradle wrapper version to be set for the new projects.")]
+ #[clap(
+ required = true,
+ help = "The gradle wrapper version to be set for the new projects."
+ )]
version: String,
#[clap(
- long,
required = true,
+ parse(from_os_str),
help = "Directories to be watched recursively for the new projects. You can have multiple watched directories."
)]
- watch_dir: Vec,
+ watch_dir: Vec,
#[clap(long, default_value = "1s", parse(try_from_str = humantime::parse_duration), help = "Duration of file watching delay. Default to 1 second.")]
watch_duration: Duration,
},
@@ -31,18 +35,13 @@ enum Command {
version: String,
#[clap(
long,
- help = "Enable the yolo mode. It will change the gradle-wrapper.properties file before running the wrapper task. With this flag, the gradle distribution of the old version won't be downloaded. But it may have potential problems."
+ help = "Enable the yolo mode. It will change the gradle-wrapper.properties file before running the wrapper task. With this flag, the gradle distribution of the old version won't be downloaded. But it may not work as expected."
)]
yolo: bool,
},
}
fn main() {
- env_logger::init_from_env(
- env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
- );
- log::debug!("DEBUG ON");
-
let cli = Cli::parse();
match cli.command {
diff --git a/src/chver.rs b/src/chver.rs
index b118f74..2723607 100644
--- a/src/chver.rs
+++ b/src/chver.rs
@@ -1,4 +1,4 @@
-use crate::{utils, Logged};
+use crate::{log_error, utils, Logged};
#[cfg(windows)]
const GRADLEW: &str = "./gradlew.bat";
@@ -16,11 +16,11 @@ fn run_gradlew_wrapper(ver: &str) -> Result<(), Logged> {
std::process::Command::new(GRADLEW)
.args(&["wrapper", "--gradle-version", ver])
.spawn()
- .map_err(|err| log_error!("Failed to run `gradlew`. {}.", err))
+ .map_err(|err| log_error(format_args!("failed to run `gradlew`, {}", err)))
.and_then(|mut child| {
child
.wait()
- .map_err(|err| log_error!("Failed to run `gradlew`. {}.", err))
+ .map_err(|err| log_error(format_args!("failed to run `gradlew`, {}", err)))
.and_then(|status| {
if !status.success() {
Err(handle_gradlew_status(status))
@@ -33,7 +33,7 @@ fn run_gradlew_wrapper(ver: &str) -> Result<(), Logged> {
fn handle_gradlew_status(status: std::process::ExitStatus) -> Logged {
match status.code() {
- Some(code) => log_error!("`gradlew` exited with status code: {}.", code),
- None => log_error!("`gradlew` terminated by signal."),
+ Some(code) => log_error(format_args!("`gradlew` exited with status code: {}", code)),
+ None => log_error(format_args!("`gradlew` terminated by signal.")),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 2b32398..f9bc437 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,25 +1,9 @@
+use std::io::Write;
+use termcolor::WriteColor;
+
#[derive(Clone, Copy)]
pub struct Logged;
-macro_rules! log_error {
- (target: $target:expr, $($arg:tt)+) => ({
- log::log!(target: $target, log::Level::Error, $($arg)+);
- Logged
- });
- ($($arg:tt)+) => ({
- log::log!(log::Level::Error, $($arg)+);
- Logged
- });
- (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
- log::log!(target: $target, $lvl, $($arg)+);
- Logged
- });
- ($lvl:expr, $($arg:tt)+) => ({
- log::log!($lvl, $($arg)+);
- Logged
- })
-}
-
pub trait LoggedSideEffect {
fn ignore_logged_error(self);
}
@@ -27,6 +11,36 @@ impl LoggedSideEffect for Result<(), Logged> {
fn ignore_logged_error(self) {}
}
+pub fn log_error(err: std::fmt::Arguments) -> Logged {
+ let stderr = termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto);
+ let mut stderr = stderr.lock();
+ let _ = stderr.set_color(termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Red)));
+ let _ = stderr.write(b"error");
+ let _ = stderr.reset();
+ let _ = writeln!(stderr, ": {}", err);
+ Logged
+}
+
+pub fn log_error_with_timestamp(err: std::fmt::Arguments) -> Logged {
+ let stderr = termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto);
+ let mut stderr = stderr.lock();
+ let _ = write!(stderr, "[{}]", chrono::Local::now());
+ let _ = stderr.set_color(termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Red)));
+ let _ = stderr.write(b"error");
+ let _ = stderr.reset();
+ let _ = writeln!(stderr, ": {}", err);
+ Logged
+}
+
+pub fn log_warn(warn: std::fmt::Arguments) {
+ let stderr = termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto);
+ let mut stderr = stderr.lock();
+ let _ = stderr.set_color(termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Yellow)));
+ let _ = stderr.write(b"warning");
+ let _ = stderr.reset();
+ let _ = writeln!(stderr, ": {}", warn);
+}
+
pub mod chver;
pub mod set_new;
pub(crate) mod utils;
diff --git a/src/set_new.rs b/src/set_new.rs
index 0cd0187..7dc2217 100644
--- a/src/set_new.rs
+++ b/src/set_new.rs
@@ -1,38 +1,53 @@
use notify::{DebouncedEvent, RecursiveMode, Watcher};
use std::ffi::OsStr;
-use std::sync::mpsc;
+use std::path::PathBuf;
use std::time::Duration;
+use std::{path::Path, sync::mpsc};
-use crate::{utils, Logged, LoggedSideEffect};
-
-const GRADDLE_PROPERTIES_FILENAME: &str = "gradle.properties";
+use crate::{log_error, log_error_with_timestamp, utils, Logged, LoggedSideEffect};
+fn is_gradle_project_file(path: &Path) -> bool {
+ if let Some(file_name) = path.file_name() {
+ if file_name == OsStr::new("build.gradle") || file_name == OsStr::new("build.gradle.kts") {
+ return true;
+ }
+ }
+ false
+}
pub fn set_new(
- watch_dirs: Vec,
+ watch_dirs: Vec,
version: String,
watch_duration: Duration,
) -> Result<(), Logged> {
let (tx, rx) = mpsc::channel();
let mut watcher = notify::watcher(tx, watch_duration)
- .map_err(|err| log_error!("Unable to create watcher. {}", err))?;
+ .map_err(|err| log_error(format_args!("unable to create watcher, {}", err)))?;
for watch_dir in watch_dirs.into_iter() {
watcher
.watch(watch_dir, RecursiveMode::Recursive)
- .map_err(|err| log_error!("Unable to watch. {}", err))?
+ .map_err(|err| log_error(format_args!("unable to watch, {}", err)))?
}
loop {
match rx.recv() {
Ok(DebouncedEvent::Create(mut path)) => {
- if path.file_name() == Some(OsStr::new(GRADDLE_PROPERTIES_FILENAME)) {
+ if is_gradle_project_file(&path) {
path.pop();
- log::info!("New gradle project detected at: {:?}.", path);
+ eprintln!(
+ "[{}] new gradle project detected at `{}`",
+ chrono::Local::now(),
+ path.display()
+ );
path.push(utils::WRAPPER_PROPERTIES_DIR);
(|| -> Result<(), Logged> {
std::fs::create_dir_all(&path).map_err(|err| {
- log_error!("Failed to create directory `{:?}`. {}", path, err)
+ log_error_with_timestamp(format_args!(
+ "failed to create directory `{}`, {}",
+ path.display(),
+ err
+ ))
})?;
path.push(utils::WRAPPER_PROPERTIES_FILENAME);
@@ -42,10 +57,15 @@ pub fn set_new(
}
}
Ok(DebouncedEvent::Error(err, _)) => {
- log::error!("Error while watching directories. {}", err)
+ log_error_with_timestamp(format_args!("error while watching directories, {}", err));
}
- Err(err) => log::error!("Error while receiving watch event. {}", err),
+ Err(err) => {
+ log_error_with_timestamp(format_args!(
+ "error while receiving watch event, {}",
+ err
+ ));
+ }
_ => {}
}
}
diff --git a/src/utils.rs b/src/utils.rs
index 2e12d6d..ec67591 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,4 +1,4 @@
-use crate::Logged;
+use crate::{log_error_with_timestamp, Logged};
use std::path::Path;
pub const WRAPPER_PROPERTIES_FILENAME: &str = "gradle-wrapper.properties";
@@ -18,9 +18,9 @@ zipStorePath=wrapper/dists"#,
pub fn write_wrapper_properties>(path: P, version: &str) -> Result<(), Logged> {
std::fs::write(path, wrapper_properties_content(version)).map_err(|err| {
- log_error!(
- "Error while writing to gradle wrapper properties file. {}.",
+ log_error_with_timestamp(format_args!(
+ "error while writing to gradle wrapper properties file, {}",
err
- )
+ ))
})
}