From eade8c34f3c1910edf76dee81fc0c3af256255c5 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 18 Mar 2020 13:49:33 +1100 Subject: [PATCH] refactor(windows): Use 14.0-style versioning Moves all version construction to use VERSION.md and TIER.md and reduces intermediate file usage, so we can present sensible versions across the project. --- oem/firstvoices/windows/src/inst/Makefile | 4 +- resources/build/build-utils.sh | 13 +- windows/src/.gitignore | 8 - windows/src/Defines.mak | 17 +- windows/src/Makefile | 12 +- windows/src/buildtools/inst/Makefile | 12 +- windows/src/buildtools/mkver/Main.pas | 426 +++++----- windows/src/buildtools/mkver/mkver.dpr | 4 +- windows/src/buildtools/mkver/mkver.dproj | 775 ++++++++++++++++++ windows/src/buildtools/stockeditor/Makefile | 2 +- windows/src/buildtools/version.in | 3 - windows/src/desktop/help/Makefile | 2 +- windows/src/desktop/version.in | 3 - .../src/developer/samples/imsample/Makefile | 6 +- windows/src/developer/version.in | 3 - windows/src/engine/inst/Makefile | 2 +- windows/src/engine/version.in | 3 - .../Keyman.System.KeymanSentryClient.pas | 3 +- .../Keyman.System.KeymanVersionInfo.pas | 58 ++ .../global/delphi/general/KeymanVersion.pas | 2 + .../delphi/general/KeymanVersionInfo.inc | 16 + .../delphi/general/keymanversion_build.in | 18 + windows/src/global/help/Makefile | 2 +- windows/src/support/version.in | 3 - 24 files changed, 1126 insertions(+), 271 deletions(-) create mode 100644 windows/src/global/delphi/general/Keyman.System.KeymanVersionInfo.pas create mode 100644 windows/src/global/delphi/general/KeymanVersionInfo.inc diff --git a/oem/firstvoices/windows/src/inst/Makefile b/oem/firstvoices/windows/src/inst/Makefile index bad5f7ded2..1694bb4d0c 100644 --- a/oem/firstvoices/windows/src/inst/Makefile +++ b/oem/firstvoices/windows/src/inst/Makefile @@ -26,8 +26,8 @@ prereq: # cd $(FVROOT)\src\inst - $(PROGRAM)\buildtools\mkver -v -u download.in download.mak $(ROOT)\src\desktop\version.txt - $(PROGRAM)\buildtools\mkver -v -u ..\localedef.dtd.in ..\xml\localedef.dtd $(ROOT)\src\desktop\version.txt + $(MKVER_U) download.in download.mak + $(MKVER_U) ..\localedef.dtd.in ..\xml\localedef.dtd # # Build FirstVoices keyboards fv_all.kmp diff --git a/resources/build/build-utils.sh b/resources/build/build-utils.sh index caec367713..b62071e9d6 100755 --- a/resources/build/build-utils.sh +++ b/resources/build/build-utils.sh @@ -21,6 +21,9 @@ # . "$(dirname "$THIS_SCRIPT")/../resources/build/build-utils.sh" # # END STANDARD BUILD SCRIPT INCLUDE # +# Note: keep changes to version, tier and tag determination in sync with mkver (windows/src/buildutils/mkver) +# + function die () { # TODO: consolidate this with fail() from shellHelperFunctions.sh @@ -48,7 +51,7 @@ function findVersion() { VERSION_MINOR="${BASH_REMATCH[2]}" VERSION_PATCH="${BASH_REMATCH[3]}" VERSION_RELEASE="$VERSION_MAJOR.$VERSION_MINOR" - } || { + } || { echo "Invalid VERSION.md file: expected major.minor.patch"; exit 1; } @@ -58,7 +61,7 @@ function findVersion() { # # Build a tag to append to the version string. This is not assigned - # to the version number used in the projects but may be used as a + # to the version number used in the projects but may be used as a # display string and in TeamCity configuration # @@ -66,7 +69,7 @@ function findVersion() { VERSION_TAG="-$TIER" else VERSION_TAG= - fi + fi if [ -z "${TEAMCITY_VERSION-}" ]; then # Local dev machine, not TeamCity @@ -112,7 +115,7 @@ function printBuildNumberForTeamCity() { else # For alpha/beta builds, for now we don't append the # version tag as buildNumber is used in the delivery - # of the build version. We may improve this in the + # of the build version. We may improve this in the # future. echo "##teamcity[buildNumber '$VERSION']" fi @@ -166,7 +169,7 @@ function exportEnvironmentDefinitionScript() { } # Detect if this script is running from within Xcode. Obviously, this assumes we don't have other definitions -# for these variables... but they're set within Xcode during its runs. As a result, they're not the wisest thing for +# for these variables... but they're set within Xcode during its runs. As a result, they're not the wisest thing for # someone else to intentionally use, so this check seems reasonable. # # https://gist.github.com/gdavis/6670468 has a representative copy of a standard Xcode environment variable setup. diff --git a/windows/src/.gitignore b/windows/src/.gitignore index 4b49bc56bb..79422be69b 100644 --- a/windows/src/.gitignore +++ b/windows/src/.gitignore @@ -23,14 +23,6 @@ engine/keyman64/Keyman64.res engine/keymanx64/keymanx64.res engine/mcompile/Release/ -# Version metadata -version.txt -buildtools/version.txt -desktop/version.txt -developer/version.txt -engine/version.txt -support/version.txt - # These are built from corresponding manifest.in and version.in **/manifest.xml **/version.rc diff --git a/windows/src/Defines.mak b/windows/src/Defines.mak index 5c6d8d8526..5400cbbcde 100644 --- a/windows/src/Defines.mak +++ b/windows/src/Defines.mak @@ -248,7 +248,8 @@ SIGNCODE=@$(ROOT)\src\buildtools\signtime.bat signtool.exe $(SC_PFX_SHA1) $(SC_P PLATFORM=Win32 # -# mkver commands +# mkver commands. mkver determines tag from the local build environment variables +# in the same way as /resources/build/build-utils.sh. # MKVER_APP=$(PROGRAM)\buildtools\mkver @@ -259,9 +260,15 @@ MKVER_VERSION_TXT=$(VERSION_TXT_PATH)\version.txt MKVER_VERSION_TXT=..\version.txt !ENDIF +MKVER_TIER_MD=$(KEYMAN_ROOT)\TIER.md +MKVER_VERSION_MD=$(KEYMAN_ROOT)\VERSION.md +MKVER_TAG + +MKVER_COMMON_PARAMS=-tier "$(MKVER_TIER_MD)" -version "$(MKVER_VERSION_MD)" + # Update a version.rc file -MKVER_V=$(MKVER_APP) -v $(MKVER_VERSION_TXT) +MKVER_V=$(MKVER_APP) $(MKVER_COMMON_PARAMS) -v $(MKVER_VERSION_TXT) version.in version.rc # Update a manifest.xml file -MKVER_M=$(MKVER_APP) -m $(MKVER_VERSION_TXT) -# Token replacement for all other file types; pattern: $(MKVER_U) $(MKVER_VERSION_TXT) -MKVER_U=$(MKVER_APP) -v -u +MKVER_M=$(MKVER_APP) $(MKVER_COMMON_PARAMS) -m manifest.in manifest.xml +# Token replacement for all other file types; pattern: $(MKVER_U) +MKVER_U=$(MKVER_APP) $(MKVER_COMMON_PARAMS) -u diff --git a/windows/src/Makefile b/windows/src/Makefile index 38dbecb4b6..05e53dc0d8 100644 --- a/windows/src/Makefile +++ b/windows/src/Makefile @@ -223,16 +223,8 @@ global-versions: mkver-app # Build our root version.txt cd $(ROOT)\src - # We use the version from VERSION.md - $(MKVER_APP) -c $(ROOT)\src\version.txt -r $(KEYMAN_ROOT)\VERSION.md - - $(MKVER_U) $(ROOT)\src\global\inc\keymanversion_build.in $(ROOT)\src\global\inc\keymanversion_build.h $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\global\delphi\general\keymanversion_build.in $(ROOT)\src\global\delphi\general\keymanversion_build.inc $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\buildtools\version.in $(ROOT)\src\buildtools\version.txt $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\developer\version.in $(ROOT)\src\developer\version.txt $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\desktop\version.in $(ROOT)\src\desktop\version.txt $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\engine\version.in $(ROOT)\src\engine\version.txt $(ROOT)\src\version.txt - $(MKVER_U) $(ROOT)\src\support\version.in $(ROOT)\src\support\version.txt $(ROOT)\src\version.txt + $(MKVER_U) $(ROOT)\src\global\inc\keymanversion_build.in $(ROOT)\src\global\inc\keymanversion_build.h + $(MKVER_U) $(ROOT)\src\global\delphi\general\keymanversion_build.in $(ROOT)\src\global\delphi\general\keymanversion_build.inc build-tools: global-versions cd $(ROOT)\src\buildtools\devtools diff --git a/windows/src/buildtools/inst/Makefile b/windows/src/buildtools/inst/Makefile index 449533321a..d5c621084f 100644 --- a/windows/src/buildtools/inst/Makefile +++ b/windows/src/buildtools/inst/Makefile @@ -9,7 +9,6 @@ build: copydebug clean: cd $(ROOT)\src\buildtools\inst -del copydebug.mak - -del copytointernalftp.mak -del srcbackup.mak copydebug: @@ -22,22 +21,17 @@ copydebug: -del $(ROOT)\src\tds_file.txt cd $(ROOT)\src\buildtools\inst - $(PROGRAM)\buildtools\mkver -v -u copydebug.in copydebug.mak $(ROOT)\src\developer\version.txt + $(MKVER_U) copydebug.in copydebug.mak $(MAKE) -fcopydebug.mak uploadsymbols: cd $(ROOT)\src\buildtools\inst - $(PROGRAM)\buildtools\mkver -v -u copydebug.in copydebug.mak $(ROOT)\src\developer\version.txt + $(MKVER_U) copydebug.in copydebug.mak $(MAKE) -fcopydebug.mak uploadsymbols srcbackup: cd $(ROOT)\src\buildtools\inst - $(PROGRAM)\buildtools\mkver -v -u $(ROOT)\src\buildtools\inst\srcbackup.in srcbackup.mak $(ROOT)\src\developer\version.txt + $(MKVER_U) $(ROOT)\src\buildtools\inst\srcbackup.in srcbackup.mak make -fsrcbackup.mak -copytointernalftp: - cd $(ROOT)\src\buildtools\inst - $(PROGRAM)\buildtools\mkver -v -u $(ROOT)\src\buildtools\inst\copytointernalftp.in copytointernalftp.mak $(ROOT)\src\developer\version.txt - make -fcopytointernalftp.mak - !include ..\..\Target.mak diff --git a/windows/src/buildtools/mkver/Main.pas b/windows/src/buildtools/mkver/Main.pas index 1b010fc973..978c37a127 100644 --- a/windows/src/buildtools/mkver/Main.pas +++ b/windows/src/buildtools/mkver/Main.pas @@ -22,7 +22,11 @@ unit Main; // I3308 interface -uses WinApi.Windows, System.Classes, System.SysUtils, TagFunctions; +uses + WinApi.Windows, + System.Classes, + System.SysUtils, + TagFunctions; procedure Run; @@ -30,22 +34,17 @@ implementation uses WinApi.ActiveX, + System.RegularExpressions, System.Win.ComObj, Xml.XMLIntf, - Xml.XMLDoc; + Xml.XMLDoc, -// This is the default build number used when doing a build outside of CI, and is -// appended to the release version found in resources/version.md -const - S_DebugBuildVersion = '9999'; + Keyman.System.KeymanVersionInfo; + +procedure WriteHelp; forward; type - TMKVerMode = (mmUnknown, mmSetRootVersionFromVersionMd, mmWriteVersionedFile, mmWriteManifestFile); -var - FMode: TMKVerMode = mmUnknown; - BuildVersion, ResourceMdFilename: string; - RootTemplateFileName, TemplateFileName, ResourceFileName: string; - UpdateFiles: TStringList; + TMKVerMode = (mmUnknown, mmWriteVersionedFile, mmWriteManifestFile, mmWriteVersionRc); const TAG_FILEVERSION = 1; @@ -72,88 +71,113 @@ var ('"CompanyName",', '"FileDescription",', '"FileVersion",', '"InternalName",', '"LegalCopyright",', '"LegalTradmarks",', '"OriginalFilename",', '"ProductName",', '"ProductVersion",', '"Comments",'); -function Init: Boolean; +function ConstructVersionTag(const tier: string): string; +var + TEAMCITY_VERSION, TEAMCITY_PR_NUMBER: string; +begin + // This matches the algorithm found in /resources/build/build-utils.sh + + if (tier = 'alpha') or (tier = 'beta') then + Result := '-'+tier + else + Result := ''; + + TEAMCITY_VERSION := GetEnvironmentVariable('TEAMCITY_VERSION'); + if TEAMCITY_VERSION <> '' then + begin + // Local dev machine, not TeamCity + Result := Result + '-local'; + end + else + begin + // On TeamCity; are we running a pull request build or a master/beta/stable build? + TEAMCITY_PR_NUMBER := GetEnvironmentVariable('TEAMCITY_PR_NUMBER'); + if TEAMCITY_PR_NUMBER <> '' then + begin + // Note TEAMCITY_PR_NUMBER can also be 'master', 'beta', or 'stable-x.y' + // This indicates we are running a Test build. + if TRegEx.IsMatch(TEAMCITY_PR_NUMBER, '^(master|beta|stable(-[0-9]+\.[0-9]+)?)$') then + begin + Result := Result + '-test'; + end + else + Result := Result + '-test-'+TEAMCITY_PR_NUMBER; + end; + end; +end; + +function Init(var FMode: TMKVerMode; var TemplateFileName: string; UpdateFiles: TStringList; var VersionInfo: TKeymanVersionInfo): Boolean; var s: string; n: Integer; + version, tier, tag: string; begin - Result := False; - FMode := mmUnknown; - s := LowerCase(ParamStr(1)); - - if s = '-c' then + n := 1; + s := ParamStr(n); + while s <> '' do begin - RootTemplateFileName := ParamStr(2); - if SameText(ParamStr(3), '-r') then + if s = '-u' then begin - FMode := mmSetRootVersionFromVersionMd; - ResourceMdFilename := ParamStr(4); + FMode := mmWriteVersionedFile; + UpdateFiles.AddPair(ParamStr(n+1), ParamStr(n+2)); + Inc(n,3); + end + else if s = '-v' then + begin + FMode := mmWriteVersionRc; + TemplateFileName := ParamStr(n+1); + UpdateFiles.AddPair(ParamStr(n+2), ParamStr(n+3)); + Inc(n,4); + end + else if s = '-m' then + begin + FMode := mmWriteManifestFile; + UpdateFiles.AddPair(ParamStr(n+1), ParamStr(n+2)); + Inc(n,3); + end + else if s = '-version' then + begin + version := ParamStr(n+1); + Inc(n,2); + end + else if s = '-tier' then + begin + tier := ParamStr(n+1); + Inc(n,2); end else - Exit; - end - else if s = '-v' then - begin - FMode := mmWriteVersionedFile; - n := 2; - while ParamStr(n) = '-u' do begin Inc(n); UpdateFiles.Add(ParamStr(n)+'='+ParamStr(n+1)); Inc(n,2); end; - TemplateFileName := ParamStr(n); - if TemplateFileName = '' then Exit; - ResourceFileName := ParamStr(n+1); - if ResourceFileName = '' then ResourceFileName := 'version.rc'; - end - else if s = '-m' then - begin - n := 2; - FMode := mmWriteManifestFile; - TemplateFileName := ParamStr(n); - if TemplateFileName = '' then Exit; - ResourceFileName := 'manifest.xml'; - end - else - Exit; + // Unrecognised parameter + Exit(False); + + s := ParamStr(n); + end; + + if FMode = mmUnknown then + Exit(False); + + tag := ConstructVersionTag(tier); + + VersionInfo := BuildKeymanVersionInfo(version, tier, tag); Result := True; end; -function GetCommaValue(var t: string): Integer; -var - n: Integer; -begin - if t = '' then raise Exception.Create('Cannot find valid PRODUCTVERSION.'); - n := Pos(',', t); if n = 0 then n := Length(t) + 1; - Result := StrToInt(Copy(t, 1, n-1)); - Delete(t, 1, n); -end; - -// Version number format: -// -// 5.1.22.0 -// 5 is major -// 1 is minor -// 22 is build -// 0 is reserved for later use -// - -procedure UpdateResource; +procedure UpdateResource(const template, fin, fout: string; VersionInfo: TKeymanVersionInfo); var i: Integer; - ProductVersion, FileFlags, StringCompanyName: string; + StringCompanyName: string; StringLegalCopyright, StringLegalTrademarks: string; - StringProductName, StringProductVersion: string; - xml: IXMLDocument; + StringProductName: string; begin writeln('Updating file version'); with TStringList.Create do try - LoadFromFile(TemplateFileName); + LoadFromFile(template); for i := 0 to Count - 1 do case GetTagValue(Strings[i], 1, PredefTags) of - TAG_PRODUCTVERSION: ProductVersion := GetTag(Strings[i], 2); - TAG_FILEFLAGS: FileFlags := GetTag(Strings[i], 2); TAG_VALUE: case GetTagValue(Strings[i], 2, StringTags) of TAG2_COMPANYNAME: StringCompanyName := GetTag(Strings[i], 3); @@ -175,95 +199,59 @@ begin // I'm free!!! I'm free!!! I'm finally free!! Thank God almighty I'm free at last! (end). - StringProductVersion := ProductVersion; - for i := 1 to Length(StringProductVersion) do - if StringProductVersion[i] = ',' then StringProductVersion[i] := '.'; + with TStringList.Create do + try + LoadFromFile(fin); - if ResourceFileName = 'manifest.xml' then - begin - xml := LoadXMLDocument(ChangeFileExt(ResourceFileName, '.in')); - xml.DocumentElement.ChildNodes['assemblyIdentity'].Attributes['version'] := StringProductVersion; - xml.SaveToFile(ResourceFileName); - xml := nil; - end - else - begin - StringProductVersion := '"' + StringProductVersion + '\0"'; - with TStringList.Create do - try - LoadFromFile(ChangeFileExt(ResourceFileName, '.in')); - - for i := 0 to Count - 1 do - case GetTagValue(Strings[i], 1, PredefTags) of - TAG_FILEVERSION: Strings[i] := UpdateTag(Strings[i], 2, ProductVersion); - TAG_PRODUCTVERSION: Strings[i] := UpdateTag(Strings[i], 2, ProductVersion); - TAG_FILEFLAGS: Strings[i] := UpdateTag(Strings[i], 2, FileFlags); - TAG_VALUE: - case GetTagValue(Strings[i], 2, StringTags) of - TAG2_COMPANYNAME: Strings[i] := UpdateTag(Strings[i], 3, StringCompanyName); - TAG2_FILEDESCRIPTION: ; - TAG2_FILEVERSION: Strings[i] := UpdateTag(Strings[i], 3, StringProductVersion); - TAG2_INTERNALNAME: ; - TAG2_LEGALCOPYRIGHT: Strings[i] := UpdateTag(Strings[i], 3, StringLegalCopyright); - TAG2_LEGALTRADEMARKS: Strings[i] := UpdateTag(Strings[i], 3, StringLegalTrademarks); - TAG2_ORIGINALFILENAME: ; - TAG2_PRODUCTNAME: Strings[i] := UpdateTag(Strings[i], 3, StringProductName); - TAG2_PRODUCTVERSION: Strings[i] := UpdateTag(Strings[i], 3, StringProductVersion); - TAG2_COMMENTS: ; - end; - end; - SaveToFile(ResourceFileName); - finally - Free; - end; + for i := 0 to Count - 1 do + case GetTagValue(Strings[i], 1, PredefTags) of + TAG_FILEVERSION: Strings[i] := UpdateTag(Strings[i], 2, VersionInfo.VersionRc); + TAG_PRODUCTVERSION: Strings[i] := UpdateTag(Strings[i], 2, VersionInfo.VersionRc); + TAG_VALUE: + case GetTagValue(Strings[i], 2, StringTags) of + TAG2_COMPANYNAME: Strings[i] := UpdateTag(Strings[i], 3, StringCompanyName); + TAG2_FILEDESCRIPTION: ; + TAG2_FILEVERSION: Strings[i] := UpdateTag(Strings[i], 3, '"'+VersionInfo.VersionWin+'\0"'); + TAG2_INTERNALNAME: ; + TAG2_LEGALCOPYRIGHT: Strings[i] := UpdateTag(Strings[i], 3, StringLegalCopyright); + TAG2_LEGALTRADEMARKS: Strings[i] := UpdateTag(Strings[i], 3, StringLegalTrademarks); + TAG2_ORIGINALFILENAME: ; + TAG2_PRODUCTNAME: Strings[i] := UpdateTag(Strings[i], 3, StringProductName); + TAG2_PRODUCTVERSION: Strings[i] := UpdateTag(Strings[i], 3, '"'+VersionInfo.VersionWin+'\0"'); + TAG2_COMMENTS: ; + end; + end; + SaveToFile(fout); + finally + Free; end; end; -procedure UpdateFile(const fin, fout: string); +procedure UpdateManifest(const fin, fout: string; VersionInfo: TKeymanVersionInfo); +var + xml: IXMLDocument; +begin + xml := LoadXMLDocument(fin); + xml.DocumentElement.ChildNodes['assemblyIdentity'].Attributes['version'] := VersionInfo.VersionWin; + xml.SaveToFile(fout); + xml := nil; +end; + +procedure UpdateFile(const fin, fout: string; VersionInfo: TKeymanVersionInfo); var tfi, tfo: TextFile; - ProductVersion, s: string; - ProductVersionNum, ProductVersionCvs: string; i, n: Integer; v: Integer; + s: string; FGUID: array[0..9] of string; g: TGUID; - ProductReleaseMajor, ProductReleaseMinor, ProductRelease: string; begin for i := 0 to 9 do begin CreateGUID(g); FGUID[i] := GUIDToString(g); end; - ProductVersion := ''; writeln('Updating file version for '+fin); - with TStringList.Create do - try - LoadFromFile(TemplateFileName); - for i := 0 to Count - 1 do - case GetTagValue(Strings[i], 1, PredefTags) of - TAG_PRODUCTVERSION: ProductVersion := GetTag(Strings[i], 2); - end; - finally - Free; - end; - - if ProductVersion = '' then Exit; - ProductVersionNum := ProductVersion; - ProductVersionCvs := ProductVersion; - for i := 1 to Length(ProductVersion) do - begin - if ProductVersion[i] = ',' then ProductVersion[i] := '.'; - if ProductVersionCvs[i] = ',' then ProductVersionCvs[i] := '-'; - end; - - ProductRelease := ProductVersion; - i := Pos('.', ProductRelease, Pos('.', ProductRelease)+1); - if i > 0 then - Delete(ProductRelease, i, MaxInt); - - ProductReleaseMajor := Copy(ProductRelease, 1, Pos('.', ProductRelease)-1); - ProductReleaseMinor := Copy(ProductRelease, Pos('.', ProductRelease)+1, MAXINT); AssignFile(tfi, fin); AssignFile(tfo, fout); @@ -274,13 +262,27 @@ begin begin readln(tfi, s); - s := StringReplace(s, '$VERSIONNUM', ProductVersionNum, [rfReplaceAll]); - s := StringReplace(s, '$VERSIONCVS', ProductVersionCvs, [rfReplaceAll]); - s := StringReplace(s, '$VERSION', ProductVersion, [rfReplaceAll]); + // Current replacements + s := StringReplace(s, '$Version', VersionInfo.Version, [rfReplaceAll]); + s := StringReplace(s, '$VersionWin', VersionInfo.VersionWin, [rfReplaceAll]); + s := StringReplace(s, '$VersionRelease', VersionInfo.VersionRelease, [rfReplaceAll]); + s := StringReplace(s, '$VersionMajor', IntToStr(VersionInfo.VersionMajor), [rfReplaceAll]); + s := StringReplace(s, '$VersionMinor', IntToStr(VersionInfo.VersionMinor), [rfReplaceAll]); + s := StringReplace(s, '$VersionPatch', IntToStr(VersionInfo.VersionPatch), [rfReplaceAll]); + s := StringReplace(s, '$Tier', VersionInfo.Tier, [rfReplaceAll]); + s := StringReplace(s, '$Tag', VersionInfo.Tag, [rfReplaceAll]); + s := StringReplace(s, '$VersionWithTag', VersionInfo.VersionWithTag, [rfReplaceAll]); + s := StringReplace(s, '$VersionRc', VersionInfo.VersionRc, [rfReplaceAll]); + + // Legacy replacements + // TODO(lowpri): replace these with above and eliminate + s := StringReplace(s, '$VERSIONNUM', VersionInfo.VersionRc, [rfReplaceAll]); + s := StringReplace(s, '$VERSION', VersionInfo.VersionWin, [rfReplaceAll]); + + s := StringReplace(s, '$RELEASE_MAJOR', IntToStr(VersionInfo.VersionMajor), [rfReplaceAll]); + s := StringReplace(s, '$RELEASE_MINOR', IntToStr(VersionInfo.VersionMinor), [rfReplaceAll]); + s := StringReplace(s, '$RELEASE', VersionInfo.VersionRelease, [rfReplaceAll]); - s := StringReplace(s, '$RELEASE_MAJOR', ProductReleaseMajor, [rfReplaceAll]); - s := StringReplace(s, '$RELEASE_MINOR', ProductReleaseMinor, [rfReplaceAll]); - s := StringReplace(s, '$RELEASE', ProductRelease, [rfReplaceAll]); n := Pos('$GUID', s); while n > 0 do @@ -303,77 +305,87 @@ begin CloseFile(tfo); end; -procedure WriteRootVersionTemplateFromVersionMd; -begin - with TStringList.Create do - try - LoadFromFile(ResourceMdFilename); - BuildVersion := Strings[0]; - finally - Free; - end; - - // Transform the string from 1.2 to 1,2 to match version.txt/version.rc format - BuildVersion := StringReplace(BuildVersion, '.', ',', [rfReplaceAll]); - - // VERSION.MD has only major.minor.patch, so append ,0 to satisfy Windows - // version patterns - BuildVersion := BuildVersion + ',0'; - - with TStringList.Create do - try - Add('PRODUCTVERSION '+BuildVersion); - SaveToFile(RootTemplateFileName); - finally - Free; - end; -end; - procedure Run; var + FMode: TMKVerMode; + TemplateFileName: string; + UpdateFiles: TStringList; i: Integer; + VersionInfo: TKeymanVersionInfo; begin CoInitializeEx(nil, COINIT_APARTMENTTHREADED); writeln('KMVer: Keyman project version information increment'); + + FMode := mmUnknown; UpdateFiles := TStringList.Create; - if not Init then - begin + try + if not Init(FMode, TemplateFileName, UpdateFiles, VersionInfo) then + begin + WriteHelp; + ExitCode := 2; + Exit; + end; + + case FMode of + mmWriteVersionedFile: + for i := 0 to UpdateFiles.Count - 1 do + UpdateFile(UpdateFiles.Names[i], UpdateFiles.ValueFromIndex[i], VersionInfo); + + mmWriteManifestFile: + UpdateManifest(UpdateFiles.Names[0], UpdateFiles.ValueFromIndex[0], VersionInfo); + mmWriteVersionRc: + UpdateResource(TemplateFileName, UpdateFiles.Names[0], UpdateFiles.ValueFromIndex[0], VersionInfo); + end; + + + finally UpdateFiles.Free; - writeln(#13#10+'Usage: kmver -c -r '); - writeln(' or kmver -v [-u f.in f.out]*