tags:

views:

3135

answers:

6

I'd like to have revision number of source code to Delphi's source code and exe version. What is the best way to do this automatically?

I'd like to display the revision number in "About" screen and in the version info of the project.

I'm using currently Delphi IDE (2006/2007) and Tortoise SVN.

+1  A: 

Suggestion: modify your build scripts to change some version file that gets compiled in afterwards. It's difficult to suggest anything more specific without knowing the build environment you're using.

Vilx-
+10  A: 

There is a program called SubWCRev.exe that comes with TortoiseSVN that will do token replacement for you. So somewhere in your source, you insert the token, and pass the input and output filenames to SubWCRev.exe, and it will replace the token with various SVN info, e.g., revision number. Note, this is a standalone program you can use with your build script, you do not need to use TortoiseSVN with it.

RedFilter
That's how I use it. We used the script above before but today we were creating a release tag and the script included the wrong version number into the build because of the reasons explained above. My bad. We've switched to using SubWCRev.exe now.
Timo Kosig
+1  A: 

If you use svn:keywords, and include $Revision$ in your file, it will get updated every time that file is committed.

So stick that in a version file at the top-level of your project, which you change/commit on every build, and read that in to get the version.

ieure
Sounds great except I'd like to get the "global revision", which is discussed in documentation.
Harriv
This will not work unless there is some automated way to change that file, else it will not be committed, and the revision number will not change. And even so it's a hack at best, because you get a lot of unnecessary SVN changes and polution of diffs.
mghie
+4  A: 

In a comment you mention you want the global revision, not the revision of any particular file. You're not going to get that number in a keyword since the number isn't related to any one file, but rather to whichever file was checked in recently most recently anywhere in the tree.

You can make a script or small program that runs svn info and then parses the output to grab the revision number you're after. You can use that number in conjunction with a template of an RC file to insert the revision number in the version-info record. This generated file would not be checked in. Run the script as part of your MSBuild procedure.

For pre-MSBuild Delphi versions, make a project group, and then make the script the first project in the group. "Build all" or "Compile all" will run the script before compiling the main project.

You could also have code in each unit's initialization section that adds its revision (as gotten by Ieure's answer) to a global list. Then select the highest number in the list at run time. That can get you the number to display in the "about" box, but you can't use it in your program's version information.

Rob Kennedy
+7  A: 

I agree with the comments about $Revision$ not being the right tool for the job. Using a tool to extract the revision number from the output of svn info is indeed the correct thing to do.

There are however two more things to note:

  1. svn info will only return the correct information if svn update has been run on the directory with the checked out sources. If you use custom build steps you should probably add a command for it too.

  2. svn info gives you also information about the repository path. This is the only way to differentiate between sources in trunk and somewhere else, like in tags. If you want your About box to contain a string to correctly identify the sources used to build the application, make sure that the repository path is available too.

Edit:

This is a command script that should be copied to the project top level directory. It will update the sources from the repository, get the SVN revision number from the svn info call and compare it with the constant SVN_REVISION from the file src\SvnRev.inc. If the file is missing it will create it, if the revision is different it will overwrite it. If svn is not available it will write the revision number 0 to the file.

The resulting file src\SvnRev.inc can simply be included in a source file. A similar file could be created to be included in the version resource.

@echo off

setlocal
rem determine project top level directory from command file name
set PRJDIR=%~dp0
cd %PRJDIR%

set SVNREVFILE=src\SvnRev.inc

rem execute "svn info", extract "Revision: 1234" line, and take SVN rev from there
svn update
for /F " usebackq tokens=1,2 delims=: " %%i in (`svn info`) do set key=%%i&set value=%%j&call :read-svn-rev
@echo SVN revision "%SVNREV%"

rem extract "const SVN_REVISION = 1234;" line, and take header SVN rev from there
for /F " usebackq tokens=2,4 " %%i in (%SVNREVFILE%) do set name=%%i&set value=%%j&call :read-file-rev
@echo Include file revision "%FILEREV%"

rem check for valid SVN rev
if "%SVNREV%" EQU "" goto :no-svn-ref
rem do not write file if SVN ref is equal
if "%FILEREV%" EQU "%SVNREV%" goto :EOF

@echo Writing svn revision %SVNREV% to %SVNREVFILE%
@echo const SVN_REVISION = %SVNREV% ; > %SVNREVFILE%
goto :EOF

:no-svn-ref
if not exist %SVNREVFILE% goto :no-header-file
rem do not write file if SVN ref is already unset
if "%FILEREV%" EQU "0" goto :EOF
@echo Writing svn revision 0 to %SVNREVFILE%
goto :write-no-version

:no-header-file
@echo Creating %SVNREVFILE% with svn revision 0
:write-no-version
@echo const SVN_REVISION = 0 ; > %SVNREVFILE%
goto :EOF

endlocal
goto :EOF

:read-svn-rev
if "%key%" EQU "Revision" set SVNREV=%value%&
goto :EOF

:read-file-rev
if "%name%" EQU "SVN_REVISION" set FILEREV=%value%&
goto :EOF
mghie
I found this to be not working properly. I think the reason is probably because my working copy always contains my complete project structure, including tags and branches. Therefore the script will take the revision number of the last change globally instead of just the folder where it is executed. SubWCRev.exe on the other hand works flawlessly with my usage scenario.
Timo Kosig
@Timo: It's certainly working properly, even though it may not do what you expect it to do. This script returns the global revision, which is the one the OP asked for. I never claimed this to return the last commit revision, which is of course different. Thanks for the down vote, though.
mghie
@mghie: After re-reading your answer I admit, yes you're right. You never claimed that it would return the last commit revision on the current working copy. Therefore I have removed my down vote. It is still not the right solution for me but I'm sure others found this answer useful.
Timo Kosig
@mghie: I tried to remove my down vote but it says: "Vote too old to be changed unless this answer is edited". Sorry for that.
Timo Kosig
@Timo: If *SubWCRev* works for you, that's great. However I don't understand why the script *doesn't* work for you. If rev 42 was the last commit that changed your branch it is entirely irrelevant which revision your working copy has, provided it is at least 42 - the code built on that branch will be exactly the same for **any** later revision as well. That's why the commit revision is meaningless, the repository path used with a certain revision is important. You require your build number to be the last *commit* revision, and I don't know why you would care.
mghie
@mghie: If you're interested I'll try to explain why it doesn't work for us and how we use(d) it: We called the batch file before the compiler from our build script. It worked OK but for this situation: Create a release tag (commit results in rXYZ). Build the code from the release tag. The code has the correct revision number (e.g. XYZ). So far OK. Now e.g. delete any old tag from the tags directory (commit results in rXYZ+1). Build the code from the X.Y release tag again. The script now pulls revision number XYZ+1 into SvnRev.inc. Should that happen?
Timo Kosig
@Timo: Thanks for the explanation. It all depends on what you want the number in SvnRev.inc to mean. If you want it to be exactly the last commit rev number, then sure, the script won't work for you. But as I wrote in my last comment, for me this isn't important. There may be *n* different versions of the sources that all have the same revision (different paths in the repository). And there may be *m* different revisions of a checked out tag or branch that are all identical, because all the revisions only changed other parts of the repository. The revision number alone just doesn't mean much.
mghie
Note also that a single commit may actually affect several branches and tags and even trunk all at the same time. That's why as long as the top-level of the working copy is fully updated the revision number there is good enough for me. If I need older revisions of a certain repository path I generally check them out into their own working copies.
mghie
A: 

I maintain some C code for an old DOS app, and recently have brought it under source control using SVN. I wanted a way to display the SVN rev number of the project within the app and your solution is perfect. Thanks.

Rob