1、setver 5改为setver=5

2、新增-setupd=n命令行参数,n=0表示使用inno setup,n=1表示使用nsis脚本,并自动设置脚本的版本号和自动运行脚本。
This commit is contained in:
Jeff
2026-05-19 13:58:59 +08:00
parent 9eaec59bfc
commit 63891dab14
6 changed files with 488 additions and 25 deletions

View File

@@ -12,6 +12,7 @@
#include "gitver_tag.h" #include "gitver_tag.h"
#include "gitver_types.h" #include "gitver_types.h"
#include "gitver_version.h" #include "gitver_version.h"
#include "gitver_setup.h"
#ifdef _DEBUG #ifdef _DEBUG
#define new DEBUG_NEW #define new DEBUG_NEW
@@ -353,18 +354,21 @@ void PrintFullUsageExamples()
_T("用法:\n") _T("用法:\n")
_T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n") _T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n")
_T(" gitver rewrite [PEType可选]\n") _T(" gitver rewrite [PEType可选]\n")
_T(" gitver setver [pid] [repoPath可选] [-test可选]\n") _T(" gitver setver=<pid> [repoPath可选] [-f可选] [-test可选]\n")
_T(" gitver nuitkabuild [pid] [mainPy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n") _T(" gitver nuitkabuild [pid] [mainPy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n")
_T(" gitver nuitkapydbuild [pid] [modulePy] [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("\n示例:\n")
_T(" gitver\n") _T(" gitver\n")
_T(" gitver rewrite\n") _T(" gitver rewrite\n")
_T(" gitver rewrite 2\n") _T(" gitver rewrite 2\n")
_T(" gitver rewrite -f\n") _T(" gitver rewrite -f\n")
_T(" gitver setver 5 E:\\Code\\OTH\\gitver\n") _T(" gitver setver=5 E:\\Code\\OTH\\gitver\n")
_T(" gitver setver 5\n") _T(" gitver setver=5\n")
_T(" gitver setver 5 -f\n") _T(" gitver setver=5 -f\n")
_T(" gitver setver 5 -test\n") _T(" gitver setver=5 -test\n")
_T(" gitver nuitkabuild 5 main.py\n") _T(" gitver nuitkabuild 5 main.py\n")
_T(" gitver nuitkabuild 5 main.py -f\n") _T(" gitver nuitkabuild 5 main.py -f\n")
_T(" gitver nuitkabuild 5 main.py -test\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 -f\n")
_T(" gitver nuitkapydbuild 5 module.py -test\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 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("\n说明: nuitkabuild/nuitkapydbuild 中,-f/-test 在额外参数开始前表示 gitver 选项;进入额外参数后会透传给 Nuitka。\n")
_T("-test: 将产品版本号的 major 和 minor 都置为 0用于测试版本构建\n") _T("-test: 将产品版本号的 major 和 minor 都置为 0用于测试版本构建\n")
_T("无参数时会读取当前分支最近三次 tag并提示选择 major 加 1 或 minor 加 1然后创建新 tag。\n"); _T("无参数时会读取当前分支最近三次 tag并提示选择 major 加 1 或 minor 加 1然后创建新 tag。\n");
@@ -387,7 +393,7 @@ void PrintFullUsageExamples()
void PrintShortCommandUsage() void PrintShortCommandUsage()
{ {
_tprintf(_T("请使用gitver rewrite [PE类型可选]\n")); _tprintf(_T("请使用gitver rewrite [PE类型可选]\n"));
_tprintf(_T("请使用gitver setver [pid] [repoPath可选]\n")); _tprintf(_T("请使用gitver setver=<pid> [repoPath可选]\n"));
_tprintf(_T("gitver nuitkabuild [pid] [mainPy] [repoPath可选] [nuitka额外参数可选]\n")); _tprintf(_T("gitver nuitkabuild [pid] [mainPy] [repoPath可选] [nuitka额外参数可选]\n"));
_tprintf(_T("gitver nuitkapydbuild [pid] [modulePy] [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"); return _T("interactive: verify tag failed");
case 35: case 35:
return _T("rewrite version file failed"); 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: default:
return _T(""); return _T("");
} }
@@ -559,28 +573,19 @@ void GetDirInfo()
/// <returns>返回值。</returns> /// <returns>返回值。</returns>
int HandleSetVerCommand(int argc, TCHAR* argv[]) int HandleSetVerCommand(int argc, TCHAR* argv[])
{ {
if (argc < 3) // 解析 "setver=N" 中的 pid
{ CString strPid = CString(argv[1]).Mid(7); // 跳过 "setver="
_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;
}
UINT nPid = 0; UINT nPid = 0;
int nArgRet = ParseUInt16ArgOrError(argv, 2, _T("pid"), nPid, 4); if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid))
if (nArgRet != 0)
{ {
return nArgRet; _tprintf(_T("错误: setver= 后的 pid 无效:%s应为 0-65535 范围的整数。\n"), strPid.GetString());
return 4;
} }
LPCTSTR lpRepoPath = NULL; LPCTSTR lpRepoPath = NULL;
BOOL bUseDefaultTagWhenMissing = FALSE; BOOL bUseDefaultTagWhenMissing = FALSE;
BOOL bTestMode = FALSE; BOOL bTestMode = FALSE;
int nRepoArgRet = ParseSetVerOptions(argc, argv, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); int nRepoArgRet = ParseSetVerOptions(argc, argv, 2, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode);
if (nRepoArgRet != 0) if (nRepoArgRet != 0)
{ {
return nRepoArgRet; return nRepoArgRet;
@@ -617,6 +622,35 @@ int HandleSetVerCommand(int argc, TCHAR* argv[])
_tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString()); _tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString());
_tprintf(_T("FileVersion=%s\n"), strFileVersion.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\" 不支持,仅支持 0Inno Setup或 1NSIS\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); return RewriteSetVerByProjectType(lpRepoPath, strProductVersion, strFileVersion);
} }
@@ -857,7 +891,7 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[])
return nCmdRet; 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")); DWORD dwStartTick = LogCommandStart(_T("setver"));
int nCmdRet = HandleSetVerCommand(argc, argv); int nCmdRet = HandleSetVerCommand(argc, argv);
@@ -875,6 +909,15 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[])
return nCmdRet; 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]); _tprintf(_T("错误:未知命令:%s\n"), argv[1]);
PrintShortCommandUsage(); PrintShortCommandUsage();

View File

@@ -151,6 +151,7 @@
<ClInclude Include="GitVer_nuitka.h" /> <ClInclude Include="GitVer_nuitka.h" />
<ClInclude Include="GitVer_process.h" /> <ClInclude Include="GitVer_process.h" />
<ClInclude Include="GitVer_rewrite.h" /> <ClInclude Include="GitVer_rewrite.h" />
<ClInclude Include="GitVer_setup.h" />
<ClInclude Include="GitVer_tag.h" /> <ClInclude Include="GitVer_tag.h" />
<ClInclude Include="GitVer_types.h" /> <ClInclude Include="GitVer_types.h" />
<ClInclude Include="GitVer_version.h" /> <ClInclude Include="GitVer_version.h" />
@@ -165,6 +166,7 @@
<ClCompile Include="GitVer_nuitka.cpp" /> <ClCompile Include="GitVer_nuitka.cpp" />
<ClCompile Include="GitVer_process.cpp" /> <ClCompile Include="GitVer_process.cpp" />
<ClCompile Include="GitVer_rewrite.cpp" /> <ClCompile Include="GitVer_rewrite.cpp" />
<ClCompile Include="GitVer_setup.cpp" />
<ClCompile Include="GitVer_tag.cpp" /> <ClCompile Include="GitVer_tag.cpp" />
<ClCompile Include="GitVer_version.cpp" /> <ClCompile Include="GitVer_version.cpp" />
<ClCompile Include="pch.cpp"> <ClCompile Include="pch.cpp">

View File

@@ -10,13 +10,13 @@ void PrintInvalidRepoPathError(LPCTSTR lpRepoPath)
_tprintf(_T("错误: 无效的仓库路径 %s\n"), lpRepoPath == NULL ? _T("<null>") : lpRepoPath); _tprintf(_T("错误: 无效的仓库路径 %s\n"), lpRepoPath == NULL ? _T("<null>") : 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; lpRepoPath = NULL;
bUseDefaultTagWhenMissing = FALSE; bUseDefaultTagWhenMissing = FALSE;
bTestMode = FALSE; bTestMode = FALSE;
for (int i = 3; i < argc; ++i) for (int i = nStartIndex; i < argc; ++i)
{ {
CString strArg = argv[i]; CString strArg = argv[i];
if (strArg.CompareNoCase(_T("-f")) == 0) if (strArg.CompareNoCase(_T("-f")) == 0)
@@ -31,6 +31,12 @@ int ParseSetVerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseD
continue; continue;
} }
// -setup=N 由调用方单独处理,此处静默跳过
if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("-setup=")) == 0)
{
continue;
}
if (lpRepoPath == NULL) if (lpRepoPath == NULL)
{ {
if (!PathIsDirectory(argv[i])) if (!PathIsDirectory(argv[i]))

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
void PrintInvalidRepoPathError(LPCTSTR lpRepoPath); 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); int ParseRewriteOptions(int argc, TCHAR* argv[], int& nPEType, BOOL& bForceRewrite);

396
GitVer/GitVer_setup.cpp Normal file
View File

@@ -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;
// ─────────────────────────────────────────────
// 内部工具:行级文本替换
// ─────────────────────────────────────────────
/// <summary>
/// 在字符串内容中查找首个包含 strToken 的整行,
/// 用 strNewLine 替换该行(不含行尾换行符)。
/// </summary>
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;
}
// ─────────────────────────────────────────────
// 查找安装脚本
// ─────────────────────────────────────────────
/// <summary>
/// 在 exe 所在目录及其上级目录中查找安装脚本。
/// nSetupType=0 查找 setup.issnSetupType=1 查找 setup.nsi。
/// </summary>
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 脚本
// ─────────────────────────────────────────────
/// <summary>
/// 修改 .iss 脚本中的 AppVersion= 行。
/// </summary>
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 脚本
// ─────────────────────────────────────────────
/// <summary>
/// 修改 .nsh 脚本中的 !define PRODUCT_VERSION 行。
/// </summary>
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;
}
// ─────────────────────────────────────────────
// 查找编译器
// ─────────────────────────────────────────────
/// <summary>
/// 查找 Inno Setup 编译器 (ISCC.exe)。
/// 先查 PATH再尝试常见安装路径。
/// </summary>
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();
}
/// <summary>
/// 查找 NSIS 编译器 (makensis.exe)。
/// 先查 PATH再尝试常见安装路径。
/// </summary>
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\" 不支持,仅支持 0Inno Setup或 1NSIS\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;
}

16
GitVer/GitVer_setup.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
/// <summary>
/// 查找安装脚本、修改版本号并调用编译器打包。
/// nSetupType=0: Inno Setup (.iss)nSetupType=1: NSIS (.nsi)。
/// 不写回项目版本文件(.rc / AssemblyInfo.cs
/// </summary>
/// <returns>TRUE 成功FALSE 失败(错误已打印)。</returns>
BOOL ExecuteSetupBuild(int nSetupType, const CString& strProductVersion);
/// <summary>
/// 处理独立的 -setup=n 命令行入口。
/// 退出码0 成功36 -setup 值不支持37 未找到脚本,
/// 38 修改脚本失败39 未找到编译器,其他同通用错误码。
/// </summary>
int HandleSetupCommand(int argc, TCHAR* argv[]);