auto_version/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn;
4use syn::{ItemFn};
5
6/// This attribute macro which prints the value of CARGO_PKG_VERSION and exits with status code 0
7/// if the command line arguments include either `-v` or `--version`
8///
9/// In the case where the code is not compiled with cargo, the version will be replaced with the message
10/// "`auto_version` macro only works for projects compiled with cargo".
11///
12/// Example:
13/// ```rust
14/// use auto_version::auto_version;
15///
16/// #[auto_version]
17/// fn main() {
18///     // executed code
19/// }
20/// ```
21/// Then, when this binary is called with `binary -v` or `binary --version`, it will output the `Cargo.toml`
22/// version without any specific formatting:
23/// ```shell
24/// $ ./binary -v
25/// $ 0.1.0
26/// ```
27
28#[proc_macro_attribute]
29pub fn auto_version(_: TokenStream, input: TokenStream) -> TokenStream {
30
31    let mut item: syn::Item = syn::parse(input).unwrap();
32    let fn_item = match &mut item {
33        syn::Item::Fn(fn_item) => fn_item,
34        _ => panic!("expected fn")
35    };
36
37    let version_tokens = quote! {
38        {
39            // use this inner block so that the local imports don't affect the user's code
40            use std::ffi::{OsString, OsStr};
41            use std::process::exit;
42
43            if std::env::args_os()
44                .find(|arg| arg == "-v" || arg == "--version" || arg == "-V")
45                .is_some()
46                {
47                    match option_env!("CARGO_PKG_VERSION") {
48                        Some(version) => println!("{}", version),
49                        None => println!("`auto_version` macro only works for projects compiled with cargo")
50                    }
51                    exit(0);
52                }
53        }
54    };
55
56    let ItemFn { attrs, vis, sig, block } = fn_item;
57    let stmts = &block.stmts;
58    let stream = quote! {
59        #(#attrs)* #vis #sig {
60            #version_tokens
61            #(#stmts)*
62        }
63    };
64    stream.into()
65}