version-check: parse .git_archival.txt as fallback when .git is absent - #524
Merged
mrjimenez merged 1 commit intoMay 4, 2026
Merged
Conversation
GitHub's "Download ZIP" button and `git archive` produce source
archives without a `.git` directory. Without that directory the
existing CMakeLists.txt auto-detection block — gated on
`EXISTS "${CMAKE_SOURCE_DIR}/.git"` — is skipped, so VERSION,
PACKAGE_VERSION, PACKAGE_STRING all stay at the dev placeholders
("GIT" / "SVN" / "aMule SVN"), SVNDATE never gets set, and the
resulting binary's banner reads:
Initialising aMule GIT compiled with ...
with no `(Snapshot: rev. ...)` trailer and no version info beyond
the integer triplet from ClientVersion.h. That's been the behaviour
for as long as the cmake build has existed — works, but the binary
can't self-identify which commit it was built from.
`git archive` has a built-in mechanism for embedding metadata into
archives: files marked with `export-subst` in `.gitattributes` get
their `$Format:...$` placeholders substituted at archive-creation
time. This is the standard idiom (used by setuptools-scm and a number
of CMake projects) for making zip / tarball downloads self-identifying.
This commit adds the three pieces:
- `.gitattributes` binds `.git_archival.txt` to `export-subst`.
- `.git_archival.txt` is a tiny template file with four
`$Format:...$` placeholders (full SHA, commit date,
`git describe --tags` output, ref names). `git archive`
substitutes these at archive time; a working-tree copy of the file
keeps the literal `$Format:` markers as the signal that no
archive substitution has happened.
- CMakeLists.txt: added an `else` branch to the
`if (GIT_FOUND AND EXISTS .git)` block. When .git is absent and
`.git_archival.txt` exists in substituted form, parse the
`describe-name:` field and feed it into the same VERSION /
SVNDATE / AMULE_TAGGED_RELEASE machinery the .git path uses.
Detection logic:
- If `.git_archival.txt` still contains literal `$Format:`,
it's an unsubstituted template (e.g. someone tar'd up `src/`
without running `git archive`). Fall through to defaults — the
file is ignored.
- Otherwise, parse `describe-name`. An off-tag `git describe`
output is the `<tag>-<N>-g<sha>` form (e.g.
`2.3.3-296-ge3f87f77f`); detect by the trailing `-N-g<hex>`
regex and treat as SVNDATE for the snapshot trailer. An exact-tag
describe output is just the tag itself; treat as
AMULE_TAGGED_RELEASE and feed into VERSION / PACKAGE_VERSION /
PACKAGE_STRING the same way the .git tag-detection block does.
Net effect: a zip download of a tagged release reads as
`aMule 3.0.0 compiled with ...` (no Snapshot trailer), and a zip
download of master tip reads as
`aMule GIT compiled with ... (Snapshot: rev. <describe-output>)` —
identical to what a .git-present clone of the same commit would
produce.
Verified locally on macOS via four configure-paths:
- `.git` present, off-tag → SVNDATE='rev. 2.3.3-NNN-gXXX' (existing
path, unchanged).
- No `.git`, archival file with off-tag describe → SVNDATE matches
the same shape as the .git path.
- No `.git`, archival file with exact-tag describe ("3.0.0") →
AMULE_TAGGED_RELEASE=1, VERSION=3.0.0, PACKAGE_STRING='aMule 3.0.0',
SVNDATE undef → release-form banner.
- No `.git`, archival file unsubstituted (template form) → file
ignored, defaults retained.
Plus an end-to-end `git archive`-and-build run that produced a
working amuled binary self-identifying as
`aMuleD GIT compiled with ... (Snapshot: rev. 2.3.3-NNN-gXXX) (OS: macOS)`
from a .git-stripped source tree.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GitHub's "Download ZIP" button and
git archiveproduce source archives without a.gitdirectory. Without.git, the existing CMake auto-detection block inCMakeLists.txtis skipped, so VERSION / PACKAGE_VERSION / PACKAGE_STRING all stay at the dev placeholders (GIT/SVN/aMule SVN),SVNDATEnever gets set, and the resulting binary's banner reads:— with no
(Snapshot: rev. ...)trailer and no commit/tag info recoverable.This PR uses the standard
git archivemechanism (export-substin.gitattributes) to bake metadata into archives at archive-creation time, then teaches CMake to read it as a fallback when.gitis absent. After this lands, a zip download identifies itself the same way a.git-present clone of the same commit would — for both off-tag dev snapshots and tagged releases.How it works
Three pieces
.gitattributes— binds.git_archival.txttoexport-subst, tellinggit archiveto substitute$Format:...$placeholders in that file at archive time..git_archival.txt— a small template with four placeholders:In the working tree (
git clone), these stay as the literal$Format:...$strings. In an archive produced bygit archive(or downloaded via GitHub's "Download ZIP"), they're substituted with the actual SHA / commit date /git describe --tagsoutput / ref names.CMakeLists.txt — added an
elsebranch toif (GIT_FOUND AND EXISTS .git). When.gitis absent and.git_archival.txtis present in substituted form, parsedescribe-name:and feed it into the sameVERSION/SVNDATE/AMULE_TAGGED_RELEASEmachinery the.gitpath uses.Detection logic
Net effect by source-of-build
git clone(any branch / commit, off-tag)aMule GIT ... (Snapshot: rev. <describe-output>)(existing)git cloneof tagged commitaMule <tag> ...(existing)aMule GIT ... (Snapshot: rev. <describe-output>)(new)aMule <tag> ...(new)git archive --format=tar v3.0.0by distro packageraMule 3.0.0 ...(new)tar czf src.tar.gz src/(nogit archive)aMule GIT ...(template still un-substituted, file ignored, defaults retained)-DPACKAGE_VERSION=…etc. on the cmake command line-Doverrides take precedence (existing distro-packager contract)How to use it at release time
Maintainer's workflow when tagging a release: no change.
git tag -a 3.0.0 -m "release 3.0.0"git push origin 3.0.0That's it. The substitution mechanism kicks in automatically:
git archiveserver-side → substituted.git_archival.txtbaked into the zip → users who download and build get a cleanaMule 3.0.0banner.git archive.git archive --format=tar.gz v3.0.0 -o amule-3.0.0.tar.gzget the same self-identifying tarball; downstream Debian / Fedora / openSUSE / etc. builds can drop their per-distro-DPACKAGE_VERSION=...cmake overrides if they want (the existing override path still works for backward compat).Verifying the substitution worked (sanity check after pushing a tag):
Or just: download the GitHub "Source code (zip)" attachment for the release, extract, look at
.git_archival.txt— it should have real values, not$Format:...$strings.Test plan
Verified locally on macOS via four configure paths:
.gitpresent, off-tag (master tip) → STATUS linegit revision rev. 2.3.3-297-g25a194d41 found;config.h:SVNDATEset,AMULE_TAGGED_RELEASEundef. Existing path, unchanged..git, archival file with off-tag describe (describe-name: 2.3.3-296-ge3f87f77f) → STATUS linegit archival metadata: rev. 2.3.3-296-ge3f87f77f found; sameconfig.hshape as the.gitpath → identical banner output..git, archival file with exact-tag describe (describe-name: 3.0.0) → STATUS linegit archival metadata: tagged release aMule 3.0.0;config.h:AMULE_TAGGED_RELEASEdefined,VERSION="3.0.0",PACKAGE_STRING="aMule 3.0.0",SVNDATEundef → release-form banner..git, archival file unsubstituted (template still has$Format:...$markers) → file detected as un-substituted, ignored; falls to CMakeLists defaults.git archiverun:git archive HEAD .gitattributes .git_archival.txt | tar -xproduced a substituted file; cmake configured against that source tree (no.git); builtamuled; ranamuled --version→ banneraMuleD GIT compiled with wxBase(OSX Cocoa) v3.3.2 and Boost 1.90 (Snapshot: rev. 2.3.3-298-g666c8e2a2) (OS: macOS)— identical to a.git-present build of the same commit.Sized
Three files added, one file edited (
CMakeLists.txt+50 LOC for the fallback block + theCONFIGURE_DEPENDSregistration). Single commit. No conflicts with anything in flight.