From 63891dab14fb2161708a59958847edae60cd472f Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 19 May 2026 13:58:59 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81setver=205=E6=94=B9=E4=B8=BAsetver=3D?= =?UTF-8?q?5=202=E3=80=81=E6=96=B0=E5=A2=9E-setupd=3Dn=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E5=8F=82=E6=95=B0=EF=BC=8Cn=3D0=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8inno=20setup=EF=BC=8Cn=3D1=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8nsis=E8=84=9A=E6=9C=AC=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AE=BE=E7=BD=AE=E8=84=9A=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E5=92=8C=E8=87=AA=E5=8A=A8=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E8=84=9A=E6=9C=AC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GitVer/GitVer.cpp | 87 ++++++--- GitVer/GitVer.vcxproj | 2 + GitVer/GitVer_cli.cpp | 10 +- GitVer/GitVer_cli.h | 2 +- GitVer/GitVer_setup.cpp | 396 ++++++++++++++++++++++++++++++++++++++++ GitVer/GitVer_setup.h | 16 ++ 6 files changed, 488 insertions(+), 25 deletions(-) create mode 100644 GitVer/GitVer_setup.cpp create mode 100644 GitVer/GitVer_setup.h diff --git a/GitVer/GitVer.cpp b/GitVer/GitVer.cpp index c5850ee..d096cd3 100644 --- a/GitVer/GitVer.cpp +++ b/GitVer/GitVer.cpp @@ -12,6 +12,7 @@ #include "gitver_tag.h" #include "gitver_types.h" #include "gitver_version.h" +#include "gitver_setup.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -353,18 +354,21 @@ void PrintFullUsageExamples() _T("用法:\n") _T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n") _T(" gitver rewrite [PEType可选]\n") - _T(" gitver setver [pid] [repoPath可选] [-test可选]\n") + _T(" gitver setver= [repoPath可选] [-f可选] [-test可选]\n") _T(" gitver nuitkabuild [pid] [mainPy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n") _T(" gitver nuitkapydbuild [pid] [modulePy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n") + _T(" gitver -setup=0|1 [pid] [repoPath可选] [-f可选] [-test可选]\n") + _T(" -setup=0: 使用 Inno Setup 脚本 (setup.iss)\n") + _T(" -setup=1: 使用 NSIS 脚本 (setup.nsh)\n") _T("\n示例:\n") _T(" gitver\n") _T(" gitver rewrite\n") _T(" gitver rewrite 2\n") _T(" gitver rewrite -f\n") - _T(" gitver setver 5 E:\\Code\\OTH\\gitver\n") - _T(" gitver setver 5\n") - _T(" gitver setver 5 -f\n") - _T(" gitver setver 5 -test\n") + _T(" gitver setver=5 E:\\Code\\OTH\\gitver\n") + _T(" gitver setver=5\n") + _T(" gitver setver=5 -f\n") + _T(" gitver setver=5 -test\n") _T(" gitver nuitkabuild 5 main.py\n") _T(" gitver nuitkabuild 5 main.py -f\n") _T(" gitver nuitkabuild 5 main.py -test\n") @@ -374,6 +378,8 @@ void PrintFullUsageExamples() _T(" gitver nuitkapydbuild 5 module.py -f\n") _T(" gitver nuitkapydbuild 5 module.py -test\n") _T(" gitver nuitkapydbuild 5 src\\core.py E:\\Code\\MyPyProj --output-dir=dist\n") + _T(" gitver -setup=0 5\n") + _T(" gitver -setup=1 5 E:\\Code\\MyProj\n") _T("\n说明: nuitkabuild/nuitkapydbuild 中,-f/-test 在额外参数开始前表示 gitver 选项;进入额外参数后会透传给 Nuitka。\n") _T("-test: 将产品版本号的 major 和 minor 都置为 0(用于测试版本构建)。\n") _T("无参数时会读取当前分支最近三次 tag,并提示选择 major 加 1 或 minor 加 1,然后创建新 tag。\n"); @@ -387,7 +393,7 @@ void PrintFullUsageExamples() void PrintShortCommandUsage() { _tprintf(_T("请使用:gitver rewrite [PE类型可选]\n")); - _tprintf(_T("请使用:gitver setver [pid] [repoPath可选]\n")); + _tprintf(_T("请使用:gitver setver= [repoPath可选]\n")); _tprintf(_T("或:gitver nuitkabuild [pid] [mainPy] [repoPath可选] [nuitka额外参数可选]\n")); _tprintf(_T("或:gitver nuitkapydbuild [pid] [modulePy] [repoPath可选] [nuitka额外参数可选]\n")); } @@ -476,6 +482,14 @@ LPCTSTR GetExitCodeHint(int nRetCode) return _T("interactive: verify tag failed"); case 35: return _T("rewrite version file failed"); + case 36: + return _T("setup: unsupported -setup value"); + case 37: + return _T("setup: setup script not found"); + case 38: + return _T("setup: modify setup script failed"); + case 39: + return _T("setup: compiler not found"); default: return _T(""); } @@ -559,28 +573,19 @@ void GetDirInfo() /// 返回值。 int HandleSetVerCommand(int argc, TCHAR* argv[]) { - if (argc < 3) - { - _tprintf(_T("错误: 参数不足。\n")); - PrintCommandUsageAndExamples(_T("setver"), _T("[pid]"), _T("")); - _tprintf(_T("参数说明:\n")); - _tprintf(_T(" pid: 产品ID,必填,范围0-65535。\n")); - _tprintf(_T(" repoPath: 仓库路径,可选,默认使用当前目录。\n")); - - return 3; - } - + // 解析 "setver=N" 中的 pid + CString strPid = CString(argv[1]).Mid(7); // 跳过 "setver=" UINT nPid = 0; - int nArgRet = ParseUInt16ArgOrError(argv, 2, _T("pid"), nPid, 4); - if (nArgRet != 0) + if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid)) { - return nArgRet; + _tprintf(_T("错误: setver= 后的 pid 无效:%s,应为 0-65535 范围的整数。\n"), strPid.GetString()); + return 4; } LPCTSTR lpRepoPath = NULL; BOOL bUseDefaultTagWhenMissing = FALSE; BOOL bTestMode = FALSE; - int nRepoArgRet = ParseSetVerOptions(argc, argv, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); + int nRepoArgRet = ParseSetVerOptions(argc, argv, 2, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); if (nRepoArgRet != 0) { return nRepoArgRet; @@ -617,6 +622,35 @@ int HandleSetVerCommand(int argc, TCHAR* argv[]) _tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString()); _tprintf(_T("FileVersion=%s\n"), strFileVersion.GetString()); + // 检查是否附带了 -setup=N 标志 + int nSetupType = -1; + for (int i = 2; i < argc; ++i) + { + CString strArg = argv[i]; + if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("-setup=")) == 0) + { + UINT nVal = 0; + if (!TryParseUInt16(strArg.Mid(7), nVal) || (nVal != 0 && nVal != 1)) + { + _tprintf(_T("错误: -setup 参数值 \"%s\" 不支持,仅支持 0(Inno Setup)或 1(NSIS)。\n"), + strArg.Mid(7).GetString()); + return 36; + } + nSetupType = (int)nVal; + break; + } + } + + if (nSetupType >= 0) + { + // -setup=N 存在:不回写版本信息到项目文件,只修改安装脚本并编译 + if (!ExecuteSetupBuild(nSetupType, strProductVersion)) + { + return 38; + } + return 0; + } + return RewriteSetVerByProjectType(lpRepoPath, strProductVersion, strFileVersion); } @@ -857,7 +891,7 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[]) return nCmdRet; } - if (argc >= 2 && _tcsicmp(argv[1], _T("setver")) == 0) + if (argc >= 2 && _tcsnicmp(argv[1], _T("setver="), 7) == 0) { DWORD dwStartTick = LogCommandStart(_T("setver")); int nCmdRet = HandleSetVerCommand(argc, argv); @@ -875,6 +909,15 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[]) return nCmdRet; } + if (argc >= 2 && _tcsnicmp(argv[1], _T("-setup="), 7) == 0) + { + DWORD dwStartTick = LogCommandStart(_T("-setup")); + int nCmdRet = HandleSetupCommand(argc, argv); + LogCommandEnd(_T("-setup"), dwStartTick, nCmdRet); + PrintCommandFailedWithCode(_T("-setup"), nCmdRet); + return nCmdRet; + } + _tprintf(_T("错误:未知命令:%s\n"), argv[1]); PrintShortCommandUsage(); diff --git a/GitVer/GitVer.vcxproj b/GitVer/GitVer.vcxproj index cdf7d51..6ff3fcc 100644 --- a/GitVer/GitVer.vcxproj +++ b/GitVer/GitVer.vcxproj @@ -151,6 +151,7 @@ + @@ -165,6 +166,7 @@ + diff --git a/GitVer/GitVer_cli.cpp b/GitVer/GitVer_cli.cpp index fedc629..d07bbf1 100644 --- a/GitVer/GitVer_cli.cpp +++ b/GitVer/GitVer_cli.cpp @@ -10,13 +10,13 @@ void PrintInvalidRepoPathError(LPCTSTR lpRepoPath) _tprintf(_T(": ЧIJֿ· %s\n"), lpRepoPath == NULL ? _T("") : lpRepoPath); } -int ParseSetVerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode) +int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode) { lpRepoPath = NULL; bUseDefaultTagWhenMissing = FALSE; bTestMode = FALSE; - for (int i = 3; i < argc; ++i) + for (int i = nStartIndex; i < argc; ++i) { CString strArg = argv[i]; if (strArg.CompareNoCase(_T("-f")) == 0) @@ -31,6 +31,12 @@ int ParseSetVerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseD continue; } + // -setup=N ɵ÷˴Ĭ + if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("-setup=")) == 0) + { + continue; + } + if (lpRepoPath == NULL) { if (!PathIsDirectory(argv[i])) diff --git a/GitVer/GitVer_cli.h b/GitVer/GitVer_cli.h index 9402603..efbbcf7 100644 --- a/GitVer/GitVer_cli.h +++ b/GitVer/GitVer_cli.h @@ -1,5 +1,5 @@ #pragma once void PrintInvalidRepoPathError(LPCTSTR lpRepoPath); -int ParseSetVerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode); +int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode); int ParseRewriteOptions(int argc, TCHAR* argv[], int& nPEType, BOOL& bForceRewrite); diff --git a/GitVer/GitVer_setup.cpp b/GitVer/GitVer_setup.cpp new file mode 100644 index 0000000..443cc26 --- /dev/null +++ b/GitVer/GitVer_setup.cpp @@ -0,0 +1,396 @@ +#include "pch.h" +#include "gitver.h" +#include "gitver_setup.h" +#include "gitver_common.h" +#include "gitver_cli.h" +#include "gitver_version.h" +#include "gitver_process.h" + +extern TCHAR g_szCurModuleDir[MAX_PATH]; + +// 来自 gitver_rewrite.cpp / GitVer.cpp 的跨单元函数声明 +std::string ToAnsiString(LPCTSTR lpText); +BOOL ReadTextFileAsAnsi(LPCTSTR lpFile, std::string& strContent, std::string& strBomPrefix); +BOOL WriteTextFileAsAnsi(LPCTSTR lpFile, const std::string& strContent, const std::string& strBomPrefix); + +void PrintInvalidRepoPathError(LPCTSTR lpRepoPath); +int ParseSetVerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode); + +static const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP = 1; +static const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP = 0; + +// ───────────────────────────────────────────── +// 内部工具:行级文本替换 +// ───────────────────────────────────────────── + +/// +/// 在字符串内容中查找首个包含 strToken 的整行, +/// 用 strNewLine 替换该行(不含行尾换行符)。 +/// +static BOOL ReplaceLineByToken(std::string& strContent, + const std::string& strToken, + const std::string& strNewLine) +{ + std::string::size_type nPos = strContent.find(strToken); + if (nPos == std::string::npos) + { + return FALSE; + } + + std::string::size_type nLineStart = strContent.rfind('\n', nPos); + nLineStart = (nLineStart == std::string::npos) ? 0 : (nLineStart + 1); + + std::string::size_type nLineEnd = strContent.find('\n', nPos); + if (nLineEnd == std::string::npos) + { + nLineEnd = strContent.size(); + } + + // 去掉可能存在的 \r + std::string::size_type nReplEnd = nLineEnd; + if (nReplEnd > nLineStart && strContent[nReplEnd - 1] == '\r') + { + --nReplEnd; + } + + strContent.replace(nLineStart, nReplEnd - nLineStart, strNewLine); + return TRUE; +} + +// ───────────────────────────────────────────── +// 查找安装脚本 +// ───────────────────────────────────────────── + +/// +/// 在 exe 所在目录及其上级目录中查找安装脚本。 +/// nSetupType=0 查找 setup.iss,nSetupType=1 查找 setup.nsi。 +/// +static BOOL FindSetupScript(int nSetupType, CString& strScriptPath) +{ + strScriptPath.Empty(); + + LPCTSTR lpFileName = (nSetupType == 0) ? _T("setup.iss") : _T("setup.nsi"); + + // 当前 exe 目录(无末尾反斜杠) + CString strExeDir = g_szCurModuleDir; + + // 尝试 exe 目录 + CString strCandidate; + strCandidate.Format(_T("%s\\%s"), strExeDir.GetString(), lpFileName); + if (PathFileExists(strCandidate)) + { + strScriptPath = strCandidate; + return TRUE; + } + + // 尝试上级目录 + int nSlash = strExeDir.ReverseFind(_T('\\')); + if (nSlash > 0) + { + CString strParentDir = strExeDir.Left(nSlash); + strCandidate.Format(_T("%s\\%s"), strParentDir.GetString(), lpFileName); + if (PathFileExists(strCandidate)) + { + strScriptPath = strCandidate; + return TRUE; + } + } + + return FALSE; +} + +// ───────────────────────────────────────────── +// 修改 Inno Setup 脚本 +// ───────────────────────────────────────────── + +/// +/// 修改 .iss 脚本中的 AppVersion= 行。 +/// +static BOOL ModifyIssScript(const CString& strScriptPath, const CString& strProductVersion) +{ + std::string strContent; + std::string strBomPrefix; + if (!ReadTextFileAsAnsi(strScriptPath, strContent, strBomPrefix)) + { + _tprintf(_T("错误: 读取 .iss 文件失败: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + const std::string strToken = "AppVersion="; + if (strContent.find(strToken) == std::string::npos) + { + _tprintf(_T("错误: .iss 文件中未找到 AppVersion= 行: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + std::string strNewLine = "AppVersion=" + ToAnsiString(strProductVersion.GetString()); + if (!ReplaceLineByToken(strContent, strToken, strNewLine)) + { + _tprintf(_T("错误: 替换 .iss AppVersion= 行失败。\n")); + return FALSE; + } + + if (!WriteTextFileAsAnsi(strScriptPath, strContent, strBomPrefix)) + { + _tprintf(_T("错误: 写入 .iss 文件失败: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + _tprintf(_T("成功: 已更新 .iss AppVersion=%s\n"), strProductVersion.GetString()); + return TRUE; +} + +// ───────────────────────────────────────────── +// 修改 NSIS 脚本 +// ───────────────────────────────────────────── + +/// +/// 修改 .nsh 脚本中的 !define PRODUCT_VERSION 行。 +/// +static BOOL ModifyNshScript(const CString& strScriptPath, const CString& strProductVersion) +{ + std::string strContent; + std::string strBomPrefix; + if (!ReadTextFileAsAnsi(strScriptPath, strContent, strBomPrefix)) + { + _tprintf(_T("错误: 读取 .nsh 文件失败: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + const std::string strToken = "!define PRODUCT_VERSION"; + if (strContent.find(strToken) == std::string::npos) + { + _tprintf(_T("错误: .nsh 文件中未找到 !define PRODUCT_VERSION 行: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + std::string strNewLine = "!define PRODUCT_VERSION \"" + ToAnsiString(strProductVersion.GetString()) + "\""; + if (!ReplaceLineByToken(strContent, strToken, strNewLine)) + { + _tprintf(_T("错误: 替换 .nsh PRODUCT_VERSION 行失败。\n")); + return FALSE; + } + + if (!WriteTextFileAsAnsi(strScriptPath, strContent, strBomPrefix)) + { + _tprintf(_T("错误: 写入 .nsh 文件失败: %s\n"), strScriptPath.GetString()); + return FALSE; + } + + _tprintf(_T("成功: 已更新 .nsh PRODUCT_VERSION=%s\n"), strProductVersion.GetString()); + return TRUE; +} + +// ───────────────────────────────────────────── +// 查找编译器 +// ───────────────────────────────────────────── + +/// +/// 查找 Inno Setup 编译器 (ISCC.exe)。 +/// 先查 PATH,再尝试常见安装路径。 +/// +static CString FindInnoSetupCompiler() +{ + TCHAR szPath[MAX_PATH] = { 0 }; + if (::SearchPath(NULL, _T("ISCC.exe"), NULL, MAX_PATH, szPath, NULL) > 0) + { + return CString(szPath); + } + + static LPCTSTR lpCandidates[] = + { + _T("C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe"), + _T("C:\\Program Files\\Inno Setup 6\\ISCC.exe"), + _T("C:\\Program Files (x86)\\Inno Setup 5\\ISCC.exe"), + _T("C:\\Program Files\\Inno Setup 5\\ISCC.exe"), + }; + + for (int i = 0; i < _countof(lpCandidates); ++i) + { + if (PathFileExists(lpCandidates[i])) + { + return CString(lpCandidates[i]); + } + } + + return CString(); +} + +/// +/// 查找 NSIS 编译器 (makensis.exe)。 +/// 先查 PATH,再尝试常见安装路径。 +/// +static CString FindNsisCompiler() +{ + TCHAR szPath[MAX_PATH] = { 0 }; + if (::SearchPath(NULL, _T("makensis.exe"), NULL, MAX_PATH, szPath, NULL) > 0) + { + return CString(szPath); + } + + static LPCTSTR lpCandidates[] = + { + _T("C:\\Program Files (x86)\\NSIS\\makensis.exe"), + _T("C:\\Program Files\\NSIS\\makensis.exe"), + }; + + for (int i = 0; i < _countof(lpCandidates); ++i) + { + if (PathFileExists(lpCandidates[i])) + { + return CString(lpCandidates[i]); + } + } + + return CString(); +} + +// ───────────────────────────────────────────── +// 公共执行函数(供 HandleSetupCommand 和 setver -setup=N 共用) +// 不回写版本信息到项目文件,只修改安装脚本并调用编译器打包。 +// ───────────────────────────────────────────── + +BOOL ExecuteSetupBuild(int nSetupType, const CString& strProductVersion) +{ + // 查找安装脚本 + CString strScriptPath; + if (!FindSetupScript(nSetupType, strScriptPath)) + { + LPCTSTR lpScriptName = (nSetupType == 0) ? _T("setup.iss") : _T("setup.nsi"); + _tprintf(_T("错误: 未在 exe 目录或上级目录中找到 %s。\n"), lpScriptName); + return FALSE; + } + _tprintf(_T("找到安装脚本: %s\n"), strScriptPath.GetString()); + + // 修改脚本中的版本号(不写回 .rc / AssemblyInfo.cs) + BOOL bModifyOk = (nSetupType == 0) + ? ModifyIssScript(strScriptPath, strProductVersion) + : ModifyNshScript(strScriptPath, strProductVersion); + + if (!bModifyOk) + { + _tprintf(_T("错误: 修改安装脚本版本信息失败。\n")); + return FALSE; + } + + // 查找编译器 + CString strCompiler = (nSetupType == 0) + ? FindInnoSetupCompiler() + : FindNsisCompiler(); + + if (strCompiler.IsEmpty()) + { + LPCTSTR lpCompilerName = (nSetupType == 0) + ? _T("ISCC.exe (Inno Setup)") + : _T("makensis.exe (NSIS)"); + _tprintf(_T("错误: 未找到安装包编译器 %s,请确认已安装并加入 PATH。\n"), lpCompilerName); + return FALSE; + } + _tprintf(_T("找到编译器: %s\n"), strCompiler.GetString()); + + // 取脚本所在目录作为工作目录 + CString strScriptDir = strScriptPath; + int nSlash = strScriptDir.ReverseFind(_T('\\')); + if (nSlash >= 0) + { + strScriptDir = strScriptDir.Left(nSlash); + } + + // 构建并执行编译命令 + CString strCmd; + strCmd.Format(_T("cmd /c %s %s"), + QuoteCmdArg(strCompiler).GetString(), + QuoteCmdArg(strScriptPath).GetString()); + _tprintf(_T("执行编译: %s\n"), strCmd.GetString()); + + CString strOutput = StartProcess(NULL, strCmd.GetBuffer(), strScriptDir.GetString()); + strCmd.ReleaseBuffer(); + + if (strOutput.IsEmpty()) + { + _tprintf(_T("警告: 编译器无输出,可能执行失败。\n")); + } + + return TRUE; +} + +// ───────────────────────────────────────────── +// 独立命令入口(argv[1] 形如 "-setup=0") +// ───────────────────────────────────────────── + +int HandleSetupCommand(int argc, TCHAR* argv[]) +{ + // 解析 -setup=n 中的 n + CString strSetupArg = argv[1]; + CString strN = strSetupArg.Mid(7); // 跳过 "-setup=" + UINT nSetupType = UINT(-1); + if (!TryParseUInt16(strN, nSetupType) || (nSetupType != 0 && nSetupType != 1)) + { + _tprintf(_T("错误: -setup 参数值 \"%s\" 不支持,仅支持 0(Inno Setup)或 1(NSIS)。\n"), + strN.GetString()); + return 36; + } + + if (argc < 3) + { + _tprintf(_T("错误: 参数不足。\n")); + _tprintf(_T("用法:gitver -setup=0|1 [pid] [repoPath可选]\n")); + _tprintf(_T("示例:gitver -setup=0 5\n")); + _tprintf(_T("示例:gitver -setup=1 5 E:\\Code\\MyProj\n")); + return 3; + } + + UINT nPid = 0; + int nArgRet = ParseUInt16ArgOrError(argv, 2, _T("pid"), nPid, 4); + if (nArgRet != 0) + { + return nArgRet; + } + + LPCTSTR lpRepoPath = NULL; + BOOL bUseDefaultTagWhenMissing = FALSE; + BOOL bTestMode = FALSE; + int nRepoArgRet = ParseSetVerOptions(argc, argv, 3, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); + if (nRepoArgRet != 0) + { + return nRepoArgRet; + } + + CString strProductVersion; + CString strFileVersion; + VersionBuildErrorCodes errorCodes = { 5, 6, 9 }; + int nVersionRet = BuildVersionsFromRepo( + lpRepoPath, + nPid, + errorCodes, + strProductVersion, + strFileVersion, + bUseDefaultTagWhenMissing, + DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP, + DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP); + if (nVersionRet != 0) + { + return nVersionRet; + } + + if (bTestMode) + { + int nDot1 = strProductVersion.Find(_T('.')); + int nDot2 = (nDot1 >= 0) ? strProductVersion.Find(_T('.'), nDot1 + 1) : -1; + if (nDot2 > nDot1) + { + strProductVersion = strProductVersion.Left(nDot2 + 1) + _T("0.0"); + } + _tprintf(_T("[test] 已将 major/minor 置零: ProductVersion=%s\n"), strProductVersion.GetString()); + } + + _tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString()); + + // 不回写版本信息到项目文件,直接修改安装脚本并编译打包 + if (!ExecuteSetupBuild((int)nSetupType, strProductVersion)) + { + return 38; + } + + return 0; +} diff --git a/GitVer/GitVer_setup.h b/GitVer/GitVer_setup.h new file mode 100644 index 0000000..0d2dd5c --- /dev/null +++ b/GitVer/GitVer_setup.h @@ -0,0 +1,16 @@ +#pragma once + +/// +/// 查找安装脚本、修改版本号并调用编译器打包。 +/// nSetupType=0: Inno Setup (.iss);nSetupType=1: NSIS (.nsi)。 +/// 不写回项目版本文件(.rc / AssemblyInfo.cs)。 +/// +/// TRUE 成功;FALSE 失败(错误已打印)。 +BOOL ExecuteSetupBuild(int nSetupType, const CString& strProductVersion); + +/// +/// 处理独立的 -setup=n 命令行入口。 +/// 退出码:0 成功,36 -setup 值不支持,37 未找到脚本, +/// 38 修改脚本失败,39 未找到编译器,其他同通用错误码。 +/// +int HandleSetupCommand(int argc, TCHAR* argv[]);