fusion-engineering / rust-git-version

Compile the Git version (tag name, or hash otherwise) and dirty state into your Rust program.

Home Page:https://docs.rs/git-version

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

interested in a proc-macro?

droundy opened this issue · comments

Would you be interested in making a major change to change this to a proc-macro so that the build script is not required?

Sounds like a good idea! Should simplify the usage a lot, not having to make a build script. Will implement that, this weekend probably.

Normal proc_macros can't be used as an expression, like

let VERSION = git_version!();

or something like that. proc-macr-hack makes it possible, but that requires splitting the crate into two crates git-version and git-version-impl.

The other option (keeping this a single (proc macro) crate) is to expose the functionality as a statement macro, something like:

git_version!(VERSION);

fn main() {
    println!("{}", VERSION);
}

Another option would be to make a more generic run_command kind of macro:

run_command!("git describe --always --dirty=-modified > git-version");

let VERSION = include_str!("git-version");

Or maybe a generic run_command wich captures the output into a variable:

run_command!("git describe --always --dirty=-modified" > VERSION);

fn main() {
    println!("{}", VERSION);
}

What are your thoughts?

I've actually already implemented the statement macro portion, in a separate crate, but when I went to put it on crates.io noticed that there were already numerous existing git-version-like crates, and figured that fewer would make it easier for users to manage.

My (tentative) leaning would be to use a next version of my crate (git-version-macro) as the internal implementation for an expression proc-macro using proc-macro-hack. I think that's the most friendly API. I'm also thinking that it would be nice to allow optional arguments that get passed to git describe (which I have not yet implemented).

Possibly something like git_version(--dirty=-modified --other-flag).

See https://github.com/droundy/git-version-macro for an implementation (sans proc-macro-hack).

A macro is definitely an interesting idea. There might be some problems with triggering new builds though. Adding a dependency on .git/HEAD or .git/logs/HEAD is relatively easy, but that won't trigger a rebuild when a tag is added without changing HEAD.

I haven't been able to find a file in .git to depend on that will cause a rebuild when a tag is added or deleted. @droundy: Did you manage to find a work-around for that?

No, I don't have a solution to rebuild if a tag is added or removed, I agree that that is hard. I have trouble imagining that this is a show-stopper, though, for a few reasons. It is very easy to trigger a rebuild by touching a file, so for aware and bothered users there is an easy workaround. Furthermore, since every commit will trigger a rebuild, the information will still be there about which version of the code has been built, and it will still be accurate, it just might not be the most compact representation.

BTW, you may have seen in the code that I'm actually putting a dependency (in a hokey way, but the only way I know how) on .git/HEAD as well as every file in .git/refs/heads. I was not previously aware of .git/logs/HEAD, and that does sound like a more elegant solution than mine was.

Furthermore, since every commit will trigger a rebuild, the information will still be there about which version of the code has been built, and it will still be accurate, it just might not be the most compact representation.

True. Besides, if there's a proc macro and a runtime function then people can still choose to use a build script if they really want the tag in there.

I was not previously aware of .git/logs/HEAD, and that does sound like a more elegant solution than mine was.

I'm not sure it's better actually. I had some faint hope that the reflog might pick up tags, but it doesn't. So .git/HEAD probably works just as well.

@droundy: I have some tweaks/improvements in mind. Shall I send a PR to your repository, or should I fork from this PR and send it here?

The advantage of .git/logs/HEAD is that .git/HEAD is a symlink that doesn't change when a commit is made only if a different branch is checked out, which is why I also check all the files in .git/refs/heads.

I'm fine with you forking from this PR and tweaking from there, whichever is easier for you.

The advantage of .git/logs/HEAD is that .git/HEAD is a symlink that doesn't change when a commit is made only if a different branch is checked out, which is why I also check all the files in .git/refs/heads.

Right, good point.

I'm fine with you forking from this PR and tweaking from there, whichever is easier for you.

I posted the PR here at #7. Could you take a look at it?

The proc macros are now in master! Thanks for your effort :)

This is now published as version 0.3.0! 🎉