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_macro
s 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! 🎉