diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 1713a7d7..7b56e4e2 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -4,6 +4,8 @@ on: push: branches: - master + tags: + - v*.*.* pull_request: branches: - master diff --git a/build.rs b/build.rs index ba506369..0b3f2f24 100644 --- a/build.rs +++ b/build.rs @@ -1,12 +1,53 @@ -use std::{error::Error, process::Command, str}; +use std::{ + io::{self, Error, ErrorKind}, + process::Command, +}; -fn main() -> Result<(), Box> { - let stdout = Command::new("git") +fn is_inside_git_work_tree() -> bool { + Command::new("git") .arg("rev-parse") - .arg("HEAD") - .output()? - .stdout; - let hash = str::from_utf8(&stdout)?; - println!("cargo:rustc-env=GIT_HEAD_PARTIAL_HASH={}", &hash[0..12]); + .arg("--is-inside-work-tree") + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).trim() == "true") + .unwrap_or(false) +} + +fn error(message: String) -> io::Error { + Error::new(ErrorKind::Other, message) +} + +fn commit_hash() -> io::Result { + let output = Command::new("git").arg("rev-parse").arg("HEAD").output()?; + + if !output.status.success() { + return Err(error(format!( + "Status error: `git rev-parse HEAD` failed: {}", + output.status + ))); + } + + let hash = String::from_utf8_lossy(&output.stdout) + .into_owned() + .trim() + .to_owned(); + + if !hash.chars().all(|c| "0123456789abcdef".contains(c)) { + return Err(error(format!( + "Invalid hash from `git rev-parse HEAD`: {}", + hash + ))); + } + + Ok(hash) +} + +fn main() -> io::Result<()> { + if is_inside_git_work_tree() { + let hash = commit_hash()?; + println!("cargo:rustc-env=GIT_HEAD_PARTIAL_HASH= ({})", &hash[0..12]); + } else { + println!("cargo:rustc-env=GIT_HEAD_PARTIAL_HASH="); + }; + Ok(()) } diff --git a/src/consts.rs b/src/consts.rs index df65b560..153877f0 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -8,13 +8,11 @@ pub(crate) const AUTHOR: &str = env!("CARGO_PKG_AUTHORS"); /// Default value for `created by` torrent metainfo field. /// -/// Example: imdl/0.0.0 (1234567890AB) +/// Example: imdl/0.0.0 (1234567890ab) pub(crate) const CREATED_BY_DEFAULT: &str = concat!( "imdl/", env!("CARGO_PKG_VERSION"), - " (", env!("GIT_HEAD_PARTIAL_HASH"), - ")" ); /// Value for `encoding` torrent metainfo field. @@ -22,7 +20,7 @@ pub(crate) const ENCODING_UTF8: &str = "UTF-8"; pub(crate) const HELP_MESSAGE: &str = "Print help message."; -/// The pogress chars are from the +/// The progress chars are from the /// [Block Elements unicode block](https://en.wikipedia.org/wiki/Block_Elements). pub(crate) const PROGRESS_CHARS: &str = "█▉▊▋▌▍▎▏ "; @@ -66,3 +64,32 @@ pub(crate) const TICK_CHARS: &str = concat!( pub(crate) const VERSION: &str = concat!("v", env!("CARGO_PKG_VERSION")); pub(crate) const VERSION_MESSAGE: &str = "Print version number."; + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::*; + + #[test] + fn created_by() { + let pattern = Regex::new( + r#"(?x) + imdl/ + [0-9]+.[0-9]+.[0-9]+(-.*)? + ( + [\ ] + \( + [0-9a-f]{12} + \) + )? + "#, + ) + .unwrap(); + + assert!( + pattern.is_match(CREATED_BY_DEFAULT), + "Bad created by string: `{}`", + CREATED_BY_DEFAULT + ); + } +} diff --git a/src/subcommand/torrent/create.rs b/src/subcommand/torrent/create.rs index d37353c4..f7668939 100644 --- a/src/subcommand/torrent/create.rs +++ b/src/subcommand/torrent/create.rs @@ -1578,7 +1578,7 @@ mod tests { " Name foo Created By {} Info Hash d3432a4b9d18baa413095a70f1e417021ceaca5b -Torrent Size 237 bytes +Torrent Size {} bytes Content Size 9 bytes Private no Tracker http://bar/ @@ -1590,7 +1590,8 @@ Content Size 9 bytes ├─h └─x ", - consts::CREATED_BY_DEFAULT + consts::CREATED_BY_DEFAULT, + 212 + consts::CREATED_BY_DEFAULT.len() ); assert_eq!(have, want); }