ever-macro 0.2.0

Helper macro for `ever`, which prints the build information with minimal boilerplate.
Documentation
use proc_macro2::TokenStream;
use quote::quote;

fn rustc() -> Option<String> {
    let meta = rustc_version::version_meta().ok()?;

    Some(format!(
        "{} ({} {})",
        meta.semver,
        meta.commit_hash
            .as_deref()
            .and_then(|s| s.get(..9))
            .unwrap_or("<unknown>"),
        meta.commit_date.as_deref().unwrap_or("<unknown>")
    ))
}

fn last_commit() -> Option<String> {
    let repo = git2::Repository::open_from_env().ok()?;
    let head = repo
        .branches(None)
        .ok()?
        .filter_map(|b| b.ok())
        .find(|b| b.0.is_head())?;
    let name = head.0.name().ok()??;
    let object = repo.revparse_single(&name).ok()?;
    let commit = object.peel_to_commit().ok()?;

    let dirty = if repo
        .diff_index_to_workdir(None, None)
        .ok()?
        .deltas()
        .count()
        != 0
    {
        "-dirty"
    } else {
        ""
    };

    Some(format!("{}{}", commit.id(), dirty))
}

fn lock() -> Option<String> {
    let meta = cargo_metadata::MetadataCommand::new().exec().ok()?;

    let mut p = meta.workspace_root;
    p.push("Cargo.lock");

    Some(String::from_utf8_lossy(&std::fs::read(p).ok()?).to_string())
}

pub fn package_name() -> TokenStream {
    quote! {
        option_env!("CARGO_PKG_NAME").unwrap_or("<unknown_package>")
    }
}

pub fn package_version() -> TokenStream {
    quote! {
        option_env!("CARGO_PKG_VERSION").unwrap_or("<unknown_package>")
    }
}

pub fn package_description() -> TokenStream {
    quote! {
        option_env!("CARGO_PKG_DESCRIPTION").unwrap_or("")
    }
}

pub fn build_date() -> TokenStream {
    let date = chrono::Local::now().format("%c %z").to_string();
    quote! { #date }
}

pub fn build_mode() -> TokenStream {
    #[cfg(debug_assertions)]
    let mode = "debug";
    #[cfg(not(debug_assertions))]
    let mode = "release";
    quote! { #mode }
}

pub fn build_commit_hash() -> TokenStream {
    let hash = last_commit().unwrap_or_else(|| "<unknown>".into());
    quote! { #hash }
}

pub fn build_username() -> TokenStream {
    let user = whoami::username();
    quote! { #user }
}

pub fn build_hostname() -> TokenStream {
    let host = whoami::hostname();
    quote! { #host }
}

pub fn build_dir() -> TokenStream {
    let dir = std::env::current_dir()
        .map(|p| p.display().to_string())
        .unwrap_or_else(|_| "<unknown>".into());
    quote! { #dir }
}

pub fn rustc_version() -> TokenStream {
    let rustc = rustc().unwrap_or_else(|| "<unknown>".into());
    quote! { #rustc }
}

pub fn lock_file() -> TokenStream {
    let lock = lock().unwrap_or_else(|| "<unknown>".into());
    quote! { #lock }
}