diff --git a/git-version-macro/src/describe_submodules.rs b/git-version-macro/src/describe_submodules.rs index a327372..36dc357 100644 --- a/git-version-macro/src/describe_submodules.rs +++ b/git-version-macro/src/describe_submodules.rs @@ -1,18 +1,8 @@ -extern crate proc_macro; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use std::ffi::OsStr; use std::path::Path; -use std::process::Command; -use syn::{ - bracketed, - parse::{Parse, ParseStream}, - punctuated::Punctuated, - token::{Comma, Eq}, - Ident, LitStr, -}; -use crate::utils::{git_dir, run_git}; +use crate::Args; macro_rules! error { ($($args:tt)*) => { @@ -20,67 +10,20 @@ macro_rules! error { }; } -#[derive(Default)] -pub(crate) struct GitModArgs { - args: Option>, - prefix: Option, - suffix: Option, - fallback: Option, -} - -impl Parse for GitModArgs { - fn parse(input: ParseStream) -> syn::Result { - let mut result = GitModArgs::default(); - loop { - if input.is_empty() { - break; - } - let ident: Ident = input.parse()?; - let _: Eq = input.parse()?; - let check_dup = |dup: bool| { - if dup { - Err(error!("`{} = ` can only appear once", ident)) - } else { - Ok(()) - } - }; - match ident.to_string().as_str() { - "args" => { - check_dup(result.args.is_some())?; - let content; - bracketed!(content in input); - result.args = Some(Punctuated::parse_terminated(&content)?); - } - "prefix" => { - check_dup(result.prefix.is_some())?; - result.prefix = Some(input.parse()?); - } - "suffix" => { - check_dup(result.suffix.is_some())?; - result.suffix = Some(input.parse()?); - } - "fallback" => { - check_dup(result.fallback.is_some())?; - result.fallback = Some(input.parse()?); - } - x => Err(error!("Unexpected argument name `{}`", x))?, - } - if input.is_empty() { - break; - } - let _: Comma = input.parse()?; - } - Ok(result) +pub fn git_submodule_versions_impl(args: Args) -> syn::Result { + if let Some(cargo_prefix) = &args.cargo_prefix { + return Err(syn::Error::new_spanned(cargo_prefix, "invalid argument `cargo_prefix` for `git_submodule_versions!()`")); + } + if let Some(cargo_suffix) = &args.cargo_suffix { + return Err(syn::Error::new_spanned(cargo_suffix, "invalid argument `cargo_suffix` for `git_submodule_versions!()`")); } -} -pub(crate) fn git_submodule_versions_impl(args: GitModArgs) -> syn::Result { let manifest_dir = std::env::var_os("CARGO_MANIFEST_DIR") .ok_or_else(|| error!("CARGO_MANIFEST_DIR is not set"))?; - let git_dir = git_dir(&manifest_dir) + let git_dir = crate::utils::git_dir(&manifest_dir) .map_err(|e| error!("failed to determine .git directory: {}", e))?; - let modules = match get_submodules(&manifest_dir) { + let modules = match crate::utils::get_submodules(&manifest_dir) { Ok(x) => x, Err(err) => return Err(error!("{}", err)), }; @@ -90,22 +33,7 @@ pub(crate) fn git_submodule_versions_impl(args: GitModArgs) -> syn::Result x.value(), - _ => "".to_string(), - }; - let suffix = match args.suffix { - Some(x) => x.value(), - _ => "".to_string(), - }; - let fallback = args.fallback.map(|x| x.value()); - - let versions = describe_submodules(&git_dir.join(".."), &modules, &git_describe_args, &prefix, &suffix, fallback.as_deref()) + let versions = describe_submodules(&git_dir.join(".."), &modules, &args) .map_err(|e| error!("{}", e))?; Ok(quote!({ @@ -113,56 +41,39 @@ pub(crate) fn git_submodule_versions_impl(args: GitModArgs) -> syn::Result) -> Result, String> { - let dir = dir.as_ref(); - let result = run_git("git submodule", - Command::new("git") - .arg("-C") - .arg(dir) - .arg("submodule") - .arg("foreach") - .arg("--quiet") - .arg("--recursive") - .arg("echo $displaypath"), - )?; - - Ok(result.lines() - .filter(|x| !x.is_empty()) - .map(|x| x.to_owned()) - .collect() - ) -} - /// Run `git describe` for each submodule to get the git version with the specified args. -fn describe_submodules( +fn describe_submodules( root: &Path, submodules: &[String], - describe_args: I, - prefix: &str, - suffix: &str, - fallback: Option<&str>, -) -> Result, String> -where - I: IntoIterator + Clone, - S: AsRef, -{ - let mut versions: Vec = vec![]; + args: &Args, +) -> Result, String> { + let mut versions = Vec::new(); + + let git_args = args.git_args.as_ref().map_or_else( + || vec!["--always".to_string(), "--dirty=-modified".to_string()], + |list| list.iter().map(|x| x.value()).collect(), + ); for submodule in submodules { let path = root.join(submodule); // Get the submodule version or fallback. - let version = match crate::utils::describe(path, describe_args.clone()) { - Ok(version) => version, + let version = match crate::utils::describe(path, &git_args) { + Ok(version) => { + let prefix = args.prefix.iter(); + let suffix = args.suffix.iter(); + quote!{ + ::core::concat!(#(#prefix,)* #version #(, #suffix)*) + } + } Err(e) => { - if let Some(fallback) = fallback { - fallback.to_owned() + if let Some(fallback) = &args.fallback { + quote!( #fallback ) } else { return Err(e) } }, }; - versions.push(format!("{}{}{}", prefix, version, suffix)) + versions.push(version); } Ok(versions) diff --git a/git-version-macro/src/lib.rs b/git-version-macro/src/lib.rs index 846543a..ff6c123 100644 --- a/git-version-macro/src/lib.rs +++ b/git-version-macro/src/lib.rs @@ -243,7 +243,7 @@ fn git_version_impl(args: Args) -> syn::Result { /// ``` #[proc_macro] pub fn git_submodule_versions(input: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(input as describe_submodules::GitModArgs); + let args = syn::parse_macro_input!(input as Args); let tokens = match describe_submodules::git_submodule_versions_impl(args) { Ok(x) => x, diff --git a/git-version-macro/src/utils.rs b/git-version-macro/src/utils.rs index f1fd9da..b5f3d39 100644 --- a/git-version-macro/src/utils.rs +++ b/git-version-macro/src/utils.rs @@ -25,7 +25,28 @@ pub fn git_dir(dir: impl AsRef) -> Result { Ok(dir.join(path)) } -pub fn run_git(program: &str, command: &mut std::process::Command) -> Result { +/// Run `git submodule foreach` command to discover submodules in the project. +pub fn get_submodules(dir: impl AsRef) -> Result, String> { + let dir = dir.as_ref(); + let result = run_git("git submodule", + Command::new("git") + .arg("-C") + .arg(dir) + .arg("submodule") + .arg("foreach") + .arg("--quiet") + .arg("--recursive") + .arg("echo $displaypath"), + )?; + + Ok(result.lines() + .filter(|x| !x.is_empty()) + .map(|x| x.to_owned()) + .collect() + ) +} + +fn run_git(program: &str, command: &mut std::process::Command) -> Result { let output = command .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped())