Inject SVN revision into executable's version infos last segment (4.0.0.[r]). Don't modify main.pas any longer, just version.rc by a new console app.

This commit is contained in:
Ansgar Becker
2010-01-10 13:53:52 +00:00
parent 85bf9b1602
commit 43b010d227
13 changed files with 306 additions and 71 deletions

View File

@ -0,0 +1,164 @@
program SetVersion;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, SynRegExpr, Classes;
var
FileName, FileContent, Line, Revision, CurDir, SvnOutput, Cmd: String;
FileHandle: TextFile;
rx: TRegExpr;
SvnOutputLines: TStringList;
function RunConsoleAppWaitAndCapture(const cConsoleApp, cParameters,
cWorkingDir: string; aResults: TStringList): DWord;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
hStdOut, hAppProcess, hAppThread: THandle;
cTemp, cTempFile: String;
aBuffer: Array[0..255] of Char;
begin
Result := 0;
hAppProcess := 0;
hAppThread := 0;
aResults.Clear;
GetTempPath( 255, aBuffer );
cTemp := StrPas( aBuffer );
cTempFile := cTemp + 'stdout.tmp';
if FileExists(cTempFile) then
SysUtils.DeleteFile( cTempFile );
// Initialize output file security attributes
FillChar(SA, SizeOf(SA), #0 );
SA.nLength := SizeOf(SA);
SA.lpSecurityDescriptor := nil;
SA.bInheritHandle := true;
// Create Output File
hStdOut := CreateFile(PChar(cTempFile),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
@SA,
CREATE_ALWAYS, // Always create it
FILE_ATTRIBUTE_TEMPORARY or // Will cache in memory if possible
FILE_FLAG_WRITE_THROUGH,
0);
if hStdOut = INVALID_HANDLE_VALUE then begin
ExitCode := 103;
Raise Exception.CreateFmt('Creating temporary stdout "'+cTempFile+'" file failed.', [cConsoleApp]);
end;
// Initialize Startup Info
FillChar(SI, SizeOf(SI), #0);
with SI do begin
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE);
hStdError := hStdOut;
hStdOutput := hStdOut;
end;
try
// Create the process
cTemp := cConsoleApp + ' ' + cParameters;
if CreateProcess(nil,
PChar( cTemp ),
nil,
nil,
true,
0,
nil,
PChar(cWorkingDir),
SI,
PI
) then begin
WaitforSingleObject( PI.hProcess, INFINITE );
hAppProcess := PI.hProcess;
hAppThread := PI.hThread;
GetExitCodeProcess( hAppProcess, result );
end else begin
ExitCode := 104;
Raise Exception.CreateFmt('CreateProcess() failed!'#10#13'Command line = %s', [cConsoleApp]);
end;
CloseHandle( hStdOut );
if FileExists(cTempFile) then begin
try
aResults.LoadFromFile(cTempFile);
except
on e:Exception do
WriteLn(e.Message);
end;
SysUtils.DeleteFile(cTempFile);
end;
finally
if hAppProcess <> 0 then
CloseHandle(hAppProcess);
if hAppThread <> 0 then
CloseHandle(hAppThread);
end;
end;
begin
try
FileName := Paramstr(1);
if not FileExists(FileName) then begin
raise Exception.Create('File "'+FileName+'" is not a valid resource file.');
ExitCode := 101;
end;
// Read resource file
AssignFile(FileHandle, FileName);
Reset(FileHandle);
while not Eof(FileHandle) do begin
ReadLn(FileHandle, Line);
FileContent := FileContent + Line + #13#10;
end;
Delete(FileContent, Length(FileContent)-1, 2);
CloseFile(FileHandle);
// Regular expression object
rx := TRegExpr.Create;
rx.ModifierI := True;
// Find Subversion revision number
CurDir := ExtractFilePath(paramStr(0));
SvnOutputLines := TStringList.Create;
Cmd := 'svnversion.exe';
RunConsoleAppWaitAndCapture(Cmd, ExtractFilePath(ExpandFileName(FileName)), CurDir, SvnOutputLines);
SvnOutput := Trim(SvnOutputLines.Text);
// 123:123M
// 123M
// 123
rx.Expression := '^(\d+\:)?(\d+)M?$';
if rx.Exec(SvnOutput) then
Revision := rx.Match[2]
else begin
ExitCode := 102;
raise Exception.Create('Could not find SVN revision');
end;
// Inject revision into file content
rx.Expression := '(\bFILEVERSION\s\d+,\d+,\d+,)\d+(\b)';
FileContent := rx.Replace(FileContent, '${1}'+Revision+'${2}', True);
rx.Free;
// Save modified file
Rewrite(FileHandle);
WriteLn(FileHandle, FileContent);
CloseFile(FileHandle);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

View File

@ -0,0 +1,107 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{2E249C21-5A3E-430F-AC5A-E8BAAF56C3FC}</ProjectGuid>
<ProjectVersion>12.0</ProjectVersion>
<MainSource>SetVersion.dpr</MainSource>
<Config Condition="'$(Config)'==''">Debug</Config>
<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DependencyCheckOutputName>SetVersion.exe</DCC_DependencyCheckOutputName>
<DCC_ImageBase>00400000</DCC_ImageBase>
<DCC_DebugInformation>false</DCC_DebugInformation>
<DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias)</DCC_UnitAlias>
<DCC_Platform>x86</DCC_Platform>
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_K>false</DCC_K>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_ImportedDataReferences>false</DCC_ImportedDataReferences>
<DCC_E>false</DCC_E>
<DCC_F>false</DCC_F>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>false</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="SetVersion.dpr">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">SetVersion.dpr</Source>
</Source>
<Parameters>
<Parameters Name="UseLauncher">False</Parameters>
<Parameters Name="LoadAllSymbols">True</Parameters>
<Parameters Name="LoadUnspecifiedSymbols">False</Parameters>
</Parameters>
<VersionInfo>
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">1</VersionInfo>
<VersionInfo Name="MinorVer">0</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
<VersionInfo Name="PreRelease">False</VersionInfo>
<VersionInfo Name="Special">False</VersionInfo>
<VersionInfo Name="Private">False</VersionInfo>
<VersionInfo Name="DLL">False</VersionInfo>
<VersionInfo Name="Locale">1031</VersionInfo>
<VersionInfo Name="CodePage">1252</VersionInfo>
</VersionInfo>
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription"/>
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"/>
<VersionInfoKeys Name="LegalCopyright"/>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename"/>
<VersionInfoKeys Name="ProductName"/>
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
</Delphi.Personality>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>

Binary file not shown.

View File

@ -25,7 +25,7 @@ echo.
:test_dcc32
dcc32.exe --version >NUL: 2>NUL:
if %errorlevel% == 0 goto test_svn
if %errorlevel% == 0 goto test_libs
:dcc32_not_found
echo Error: Delphi compiler 'dcc32.exe' was not found in PATH.
@ -39,22 +39,6 @@ echo.
pause > NUL:
goto :eof
:test_svn
svnversion.exe --version >NUL: 2>NUL:
if %errorlevel% == 0 goto test_libs
:svn_not_found
echo Error: Subversion executable 'svnversion.exe' was not found in PATH.
echo.
echo Please install Subversion. When installing, Subversion should modify
echo your system path to include the location of this file.
echo.
echo See also:
echo http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91^&filter=setup.exe
echo.
pause > NUL:
goto :eof
:locate_dcc32
if not "%compiler_dir%" == "none" goto :eof
pushd %~f1
@ -124,34 +108,8 @@ goto param_loop
:param_done
echo Base directory: %base_dir%
echo Compiler directory: %compiler_dir%
:find_wcver
rem Unix tool, may not handle Windows paths well, so go to base directory and use dot.
cd /d "%base_dir%"
for /f "usebackq" %%s in (`svnversion.exe . ^|^| ECHO unknown`) DO SET wcver=WC %%s
if "%wcver%" == "WC unknown" (set wcver=unknown) else (goto insert_wcver)
:svnversion_failure
rem Non-fatal, continue if this happens.
echo.
echo Error: svnversion failed - run this step manually to see what went wrong?
echo.
:insert_wcver
echo Version: %WCVER%
echo.
rem Put WC version or "unknown" into main.pas
"%base_dir%\extra\sed\sed.exe" "s/\$Revision.*\$/\$Revision: %WCVER% \$/g" -i "%base_dir%\source\main.pas"
if not %errorlevel% == 0 goto sedfail
"%base_dir%\extra\sed\sed.exe" "s/\$Rev[^i].*\$/\$Rev: %WCVER% \$/g" -i "%base_dir%\source\main.pas"
if not %errorlevel% == 0 goto sedfail
goto start
:sedfail
echo Error: SED failure - run this step manually to see what went wrong?
echo.
goto end
:start
rem Delete old binaries
echo Cleaning build directories.
@ -198,6 +156,7 @@ if not %err% == 0 goto end
rem Build main executable
echo Compiling main project.
cd /d "%base_dir%\packages\%package_dir%\"
..\..\extra\SetVersion\SetVersion.exe ..\..\res\version.rc
brcc32 ..\..\res\version.rc
brcc32 ..\..\res\icon.rc
brcc32 ..\..\res\manifest.rc

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -47,6 +47,7 @@
<DCC_AssertionsAtRuntime>False</DCC_AssertionsAtRuntime>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<BRCC_OutputDir>..\..\res</BRCC_OutputDir>
<DCC_MapFile>3</DCC_MapFile>
<DCC_DependencyCheckOutputName>..\..\out\heidisql.exe</DCC_DependencyCheckOutputName>
<Version>7.0</Version>

View File

@ -100,7 +100,7 @@ begin
MemoAuthors.Text := TrimRight(MemoAuthors.Text);
// App-Version
LabelVersion.Caption := FullAppVersion;
LabelVersion.Caption := 'Version '+AppVersion;
// Compile-date
FileAge(ParamStr(0), Compiled);

View File

@ -846,7 +846,7 @@ begin
else
NodeCount := Grid.RootNodeCount;
EnableProgressBar(NodeCount);
Generator := APPNAME+' '+FullAppVersion;
Generator := APPNAME+' '+AppVersion;
tmp :=
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' + CRLF +
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' + CRLF + CRLF +

View File

@ -864,9 +864,8 @@ end;
var
MainForm : TMainForm;
AppVersion : String = '4.0';
AppRevision : String = '$Rev$';
FullAppVersion : String;
AppVerMajor, AppVerMinor, AppVerRelease, AppVerRevision: Integer;
AppVersion : String;
DirnameCommonAppData,
DirnameUserAppData,
DirnameSnippets,
@ -1143,6 +1142,11 @@ var
DisableProcessWindowsGhostingProc: procedure;
QueryTab: TQueryTab;
Action: TAction;
dwInfoSize, // Size of VERSIONINFO structure
dwVerSize, // Size of Version Info Data
dwWnd: DWORD; // Handle for the size call.
FI: PVSFixedFileInfo; // Delphi structure; see WINDOWS.PAS
ptrVerBuf: Pointer; // pointer to a version buffer
begin
caption := APPNAME;
setLocales;
@ -1156,16 +1160,17 @@ begin
refreshMonitorConfig;
loadWindowConfig;
// Beautify AppRevision
if Pos('$Rev: WC', AppRevision) < 1 then
AppRevision := 'unknown'
else begin
AppRevision := StringReplace( AppRevision, '$Rev: WC', '', [rfIgnoreCase] );
AppRevision := StringReplace( AppRevision, '$', '', [] );
AppRevision := Trim( AppRevision );
end;
// Compose full version string
FullAppVersion := 'Version ' + AppVersion + ', Revision ' + AppRevision;
// Detect version
dwInfoSize := GetFileVersionInfoSize(PChar(Application.ExeName), dwWnd);
GetMem(ptrVerBuf, dwInfoSize);
GetFileVersionInfo(PChar(Application.ExeName), dwWnd, dwInfoSize, ptrVerBuf);
VerQueryValue(ptrVerBuf, '\', Pointer(FI), dwVerSize );
AppVerMajor := HiWord(FI.dwFileVersionMS);
AppVerMinor := LoWord(FI.dwFileVersionMS);
AppVerRelease := HiWord(FI.dwFileVersionLS);
AppVerRevision := LoWord(FI.dwFileVersionLS);
FreeMem(ptrVerBuf);
AppVersion := Format('%d.%d.%d.%d', [AppVerMajor, AppVerMinor, AppVerRelease, AppVerRevision]);
// "All users" folder for HeidiSQL's data (All Users\Application Data)
DirnameCommonAppData := GetShellFolder(CSIDL_COMMON_APPDATA) + '\' + APPNAME + '\';
@ -1394,7 +1399,7 @@ begin
end;
if DaysBetween(Now, LastStatsCall) >= 30 then begin
// Report used SVN revision
StatsURL := APPDOMAIN + 'savestats.php?c=' + AppRevision;
StatsURL := APPDOMAIN + 'savestats.php?c=' + IntToStr(AppVerRevision);
// Enumerate actively used server versions
SessionNames := TStringlist.Create;
if MainReg.OpenKey(REGPATH + REGKEY_SESSIONS, true) then
@ -1411,7 +1416,7 @@ begin
end;
StatsCall := TDownloadUrl2.Create(Self);
StatsCall.URL := StatsURL;
StatsCall.SetUserAgent(APPNAME + ' ' + FullAppVersion);
StatsCall.SetUserAgent(APPNAME + ' ' + AppVersion);
try
StatsCall.ExecuteTarget(nil);
OpenRegistry;
@ -8488,7 +8493,7 @@ begin
Cap := Cap + ' /' + ActiveDatabase;
if SelectedTable.Name <> '' then
Cap := Cap + '/' + SelectedTable.Name;
Cap := Cap + ' - ' + APPNAME + ' ' + FullAppVersion;
Cap := Cap + ' - ' + APPNAME + ' ' + AppVersion;
Caption := Cap;
Application.Title := Cap;
end;

View File

@ -961,7 +961,7 @@ begin
WideFormat('# %-30s%s', ['Database:', DBObj.Database]) + CRLF +
WideFormat('# %-30s%s', ['Server version:', Mainform.Connection.ServerVersionUntouched]) + CRLF +
WideFormat('# %-30s%s', ['Server OS:', Mainform.Connection.GetVar('SHOW VARIABLES LIKE ' + esc('version_compile_os'), 1)]) + CRLF +
WideFormat('# %-30s%s', [APPNAME + ' version:', FullAppVersion]) + CRLF +
WideFormat('# %-30s%s', [APPNAME + ' version:', AppVersion]) + CRLF +
WideFormat('# %-30s%s', ['Date/time:', DateTimeToStr(Now)]) + CRLF +
'# --------------------------------------------------------' + CRLF + CRLF +
'/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;' + CRLF +

View File

@ -37,7 +37,7 @@ type
public
{ Public declarations }
AutoClose: Boolean; // Automatically close dialog after detecting no available downloads
CurrentRevision, BuildRevision: Integer;
BuildRevision: Integer;
CheckForBuildsInAutoMode: Boolean;
BuildSize: Integer;
end;
@ -95,7 +95,6 @@ procedure TfrmUpdateCheck.FormShow(Sender: TObject);
begin
Status('Initiating ... ');
Caption := 'Check for '+APPNAME+' updates ...';
CurrentRevision := StrToIntDef(AppRevision, 0);
// Init GUI controls
btnRelease.Enabled := False;
@ -105,8 +104,8 @@ begin
// Prepare download
CheckfileDownload := TDownLoadURL2.Create(Self);
CheckfileDownload.SetUserAgent(APPNAME + ' ' + APPVERSION + ' ' + APPREVISION + ' update checker tool');
CheckfileDownload.URL := APPDOMAIN + 'updatecheck.php?r='+APPREVISION;
CheckfileDownload.SetUserAgent(APPNAME + ' ' + AppVersion + ' update checker tool');
CheckfileDownload.URL := APPDOMAIN + 'updatecheck.php?r='+IntToStr(AppVerRevision);
CheckfileDownload.Filename := GetTempDir + APPNAME + '_updatecheck.ini';
// Download the check file
@ -118,9 +117,9 @@ begin
ReadCheckFile;
// Developer versions probably have "unknown" (0) as revision,
// which makes it impossible to compare the revisions.
if CurrentRevision = 0 then
if AppVerRevision = 0 then
Status('Error: Cannot determine current revision. Using a developer version?')
else if CurrentRevision = BuildRevision then
else if AppVerRevision = BuildRevision then
Status('Your '+APPNAME+' is up-to-date (no update available).')
else if groupRelease.Enabled or btnBuild.Enabled then
Status('Updates available.');
@ -174,7 +173,7 @@ begin
memoRelease.Lines.Add( 'Note: ' + Note );
btnRelease.Caption := 'Download version ' + ReleaseVersion;
// Enable the download button if the current version is outdated
groupRelease.Enabled := ReleaseRevision > CurrentRevision;
groupRelease.Enabled := ReleaseRevision > AppVerRevision;
btnRelease.Enabled := groupRelease.Enabled;
memoRelease.Enabled := groupRelease.Enabled;
if not memoRelease.Enabled then
@ -188,7 +187,7 @@ begin
BuildRevision := Ini.ReadInteger(INISECT_BUILD, 'Revision', 0);
BuildURL := Ini.ReadString(INISECT_BUILD, 'URL', '');
BuildSize := Ini.ReadInteger(INISECT_BUILD, 'Size', 0);
memoBuild.Lines.Add( 'Revision ' + IntToStr(BuildRevision) + ' (yours: '+AppRevision+')' );
memoBuild.Lines.Add( 'Revision ' + IntToStr(BuildRevision) + ' (yours: '+IntToStr(AppVerRevision)+')' );
FileAge(ParamStr(0), Compiled);
memoBuild.Lines.Add( 'Compiled: ' + Ini.ReadString(INISECT_BUILD, 'Date', '') + ' (yours: '+DateToStr(Compiled)+')' );
Note := Ini.ReadString(INISECT_BUILD, 'Note', '');
@ -198,7 +197,7 @@ begin
// A new release should have priority over a new nightly build.
// So the user should not be able to download a newer build here
// before having installed the new release.
btnBuild.Enabled := (CurrentRevision = 0) or ((BuildRevision > CurrentRevision) and (not btnRelease.Enabled));
btnBuild.Enabled := (AppVerRevision = 0) or ((BuildRevision > AppVerRevision) and (not btnRelease.Enabled));
end;
end;