去除-f参数,同时添加md文件进行说明

This commit is contained in:
Jeff
2026-05-19 15:25:29 +08:00
parent 63891dab14
commit abcbc88399
8 changed files with 479 additions and 121 deletions

View File

@@ -353,11 +353,11 @@ void PrintFullUsageExamples()
LPCTSTR lpUsageText = LPCTSTR lpUsageText =
_T("用法:\n") _T("用法:\n")
_T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n") _T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n")
_T(" gitver rewrite [PEType可选]\n") _T(" gitver rewrite [PEType可选] [-f可选]\n")
_T(" gitver setver=<pid> [repoPath可选] [-f可选] [-test可选]\n") _T(" gitver setver=<pid> [repodir=<path>可选] [-test可选]\n")
_T(" gitver nuitkabuild [pid] [mainPy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n") _T(" gitver nuitkabuild=<pid> <mainPy> [repodir=<path>可选] [-test可选] [params=\"<nuitka参数>\"可选]\n")
_T(" gitver nuitkapydbuild [pid] [modulePy] [repoPath可选] [-test可选] [nuitka额外参数可选]\n") _T(" gitver nuitkapydbuild=<pid> <modulePy> [repodir=<path>可选] [-test可选] [params=\"<nuitka参数>\"可选]\n")
_T(" gitver -setup=0|1 [pid] [repoPath可选] [-f可选] [-test可选]\n") _T(" gitver -setup=0|1 [pid] [repodir=<path>可选] [-test可选]\n")
_T(" -setup=0: 使用 Inno Setup 脚本 (setup.iss)\n") _T(" -setup=0: 使用 Inno Setup 脚本 (setup.iss)\n")
_T(" -setup=1: 使用 NSIS 脚本 (setup.nsh)\n") _T(" -setup=1: 使用 NSIS 脚本 (setup.nsh)\n")
_T("\n示例:\n") _T("\n示例:\n")
@@ -365,24 +365,21 @@ void PrintFullUsageExamples()
_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 repodir=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 -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 -test\n")
_T(" gitver nuitkabuild 5 main.py -test\n") _T(" gitver nuitkabuild=5 src\\app.py repodir=E:\\Code\\MyPyProj params=\"--standalone --output-dir=dist\"\n")
_T(" gitver nuitkabuild 5 src\\app.py E:\\Code\\MyPyProj --standalone --output-dir=dist\n") _T(" gitver nuitkapydbuild=5 module.py\n")
_T(" gitver nuitkabuild 5 main.py --standalone -f\n") _T(" gitver nuitkapydbuild=5 module.py -test\n")
_T(" gitver nuitkapydbuild 5 module.py\n") _T(" gitver nuitkapydbuild=5 src\\core.py repodir=E:\\Code\\MyPyProj params=\"--output-dir=dist\"\n")
_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=0 5\n")
_T(" gitver -setup=1 5 E:\\Code\\MyProj\n") _T(" gitver -setup=1 5 repodir=E:\\Code\\MyProj\n")
_T("\n说明: nuitkabuild/nuitkapydbuild 中,-f/-test 在额外参数开始前表示 gitver 选项;进入额外参数后会透传给 Nuitka\n") _T("params: 传递给 Nuitka 的额外参数,用双引号括起来,如 params=\"--standalone --output-dir=dist\"\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")
_T("未找到当前分支 tag 时自动使用默认版本 1.0。\n");
_tprintf(_T("%s"), lpUsageText); _tprintf(_T("%s"), lpUsageText);
} }
@@ -393,9 +390,9 @@ 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> [repodir=<path>可选]\n"));
_tprintf(_T("gitver nuitkabuild [pid] [mainPy] [repoPath可选] [nuitka额外参数可选]\n")); _tprintf(_T("gitver nuitkabuild=<pid> <mainPy> [repodir=<path>可选] [params=\"<nuitka参数>\"可选]\n"));
_tprintf(_T("gitver nuitkapydbuild [pid] [modulePy] [repoPath可选] [nuitka额外参数可选]\n")); _tprintf(_T("gitver nuitkapydbuild=<pid> <modulePy> [repodir=<path>可选] [params=\"<nuitka参数>\"可选]\n"));
} }
/// <summary> /// <summary>
@@ -406,15 +403,15 @@ void PrintShortCommandUsage()
/// <param name="lpExampleRequiredArgs">示例中的必选参数。</param> /// <param name="lpExampleRequiredArgs">示例中的必选参数。</param>
void PrintCommandUsageAndExamples(LPCTSTR lpCommandName, LPCTSTR lpRequiredArgs, LPCTSTR lpExampleRequiredArgs) void PrintCommandUsageAndExamples(LPCTSTR lpCommandName, LPCTSTR lpRequiredArgs, LPCTSTR lpExampleRequiredArgs)
{ {
_tprintf(_T("用法gitver %s %s [repoPath可选]\n"), lpCommandName, lpRequiredArgs); _tprintf(_T("用法gitver %s %s [repodir=<path>可选]\n"), lpCommandName, lpRequiredArgs);
if (lpExampleRequiredArgs != NULL && _tcslen(lpExampleRequiredArgs) > 0) if (lpExampleRequiredArgs != NULL && _tcslen(lpExampleRequiredArgs) > 0)
{ {
_tprintf(_T("示例gitver %s 5 %s E:\\Code\\OTH\\gitver\n"), lpCommandName, lpExampleRequiredArgs); _tprintf(_T("示例gitver %s 5 %s repodir=E:\\Code\\OTH\\gitver\n"), lpCommandName, lpExampleRequiredArgs);
_tprintf(_T("示例gitver %s 5 %s\n"), lpCommandName, lpExampleRequiredArgs); _tprintf(_T("示例gitver %s 5 %s\n"), lpCommandName, lpExampleRequiredArgs);
} }
else else
{ {
_tprintf(_T("示例gitver %s 5 E:\\Code\\OTH\\gitver\n"), lpCommandName); _tprintf(_T("示例gitver %s 5 repodir=E:\\Code\\OTH\\gitver\n"), lpCommandName);
_tprintf(_T("示例gitver %s 5\n"), lpCommandName); _tprintf(_T("示例gitver %s 5\n"), lpCommandName);
} }
} }
@@ -583,9 +580,8 @@ int HandleSetVerCommand(int argc, TCHAR* argv[])
} }
LPCTSTR lpRepoPath = NULL; LPCTSTR lpRepoPath = NULL;
BOOL bUseDefaultTagWhenMissing = FALSE;
BOOL bTestMode = FALSE; BOOL bTestMode = FALSE;
int nRepoArgRet = ParseSetVerOptions(argc, argv, 2, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); int nRepoArgRet = ParseSetVerOptions(argc, argv, 2, lpRepoPath, bTestMode);
if (nRepoArgRet != 0) if (nRepoArgRet != 0)
{ {
return nRepoArgRet; return nRepoArgRet;
@@ -600,7 +596,6 @@ int HandleSetVerCommand(int argc, TCHAR* argv[])
errorCodes, errorCodes,
strProductVersion, strProductVersion,
strFileVersion, strFileVersion,
bUseDefaultTagWhenMissing,
DEFAULT_MAJOR_WHEN_NO_TAG, DEFAULT_MAJOR_WHEN_NO_TAG,
DEFAULT_MINOR_WHEN_NO_TAG); DEFAULT_MINOR_WHEN_NO_TAG);
if (nVersionRet != 0) if (nVersionRet != 0)
@@ -873,7 +868,7 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[])
return nCmdRet; return nCmdRet;
} }
if (argc >= 2 && _tcsicmp(argv[1], _T("nuitkabuild")) == 0) if (argc >= 2 && _tcsnicmp(argv[1], _T("nuitkabuild="), 12) == 0)
{ {
DWORD dwStartTick = LogCommandStart(_T("nuitkabuild")); DWORD dwStartTick = LogCommandStart(_T("nuitkabuild"));
int nCmdRet = HandleNuitkaBuildCommand(argc, argv); int nCmdRet = HandleNuitkaBuildCommand(argc, argv);
@@ -882,7 +877,7 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[])
return nCmdRet; return nCmdRet;
} }
if (argc >= 2 && _tcsicmp(argv[1], _T("nuitkapydbuild")) == 0) if (argc >= 2 && _tcsnicmp(argv[1], _T("nuitkapydbuild="), 15) == 0)
{ {
DWORD dwStartTick = LogCommandStart(_T("nuitkapydbuild")); DWORD dwStartTick = LogCommandStart(_T("nuitkapydbuild"));
int nCmdRet = HandleNuitkaPydBuildCommand(argc, argv); int nCmdRet = HandleNuitkaPydBuildCommand(argc, argv);

View File

@@ -10,21 +10,14 @@ 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[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode) int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bTestMode)
{ {
lpRepoPath = NULL; lpRepoPath = NULL;
bUseDefaultTagWhenMissing = FALSE;
bTestMode = FALSE; bTestMode = FALSE;
for (int i = nStartIndex; i < argc; ++i) for (int i = nStartIndex; i < argc; ++i)
{ {
CString strArg = argv[i]; CString strArg = argv[i];
if (strArg.CompareNoCase(_T("-f")) == 0)
{
bUseDefaultTagWhenMissing = TRUE;
continue;
}
if (strArg.CompareNoCase(_T("-test")) == 0) if (strArg.CompareNoCase(_T("-test")) == 0)
{ {
bTestMode = TRUE; bTestMode = TRUE;
@@ -37,14 +30,20 @@ int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepo
continue; continue;
} }
if (lpRepoPath == NULL) if (strArg.GetLength() > 8 && strArg.Left(8).CompareNoCase(_T("repodir=")) == 0)
{ {
if (!PathIsDirectory(argv[i])) if (lpRepoPath != NULL)
{ {
PrintInvalidRepoPathError(argv[i]); _tprintf(_T("错误: repodir 参数重复: %s\n"), argv[i]);
return 23; return 23;
} }
lpRepoPath = argv[i]; LPCTSTR lpPath = argv[i] + 8;
if (!PathIsDirectory(lpPath))
{
PrintInvalidRepoPathError(lpPath);
return 23;
}
lpRepoPath = lpPath;
continue; continue;
} }

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
void PrintInvalidRepoPathError(LPCTSTR lpRepoPath); void PrintInvalidRepoPathError(LPCTSTR lpRepoPath);
int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, BOOL& bTestMode); int ParseSetVerOptions(int argc, TCHAR* argv[], int nStartIndex, LPCTSTR& lpRepoPath, BOOL& bTestMode);
int ParseRewriteOptions(int argc, TCHAR* argv[], int& nPEType, BOOL& bForceRewrite); int ParseRewriteOptions(int argc, TCHAR* argv[], int& nPEType, BOOL& bForceRewrite);

View File

@@ -13,52 +13,56 @@ void PrintCommandUsageAndExamples(LPCTSTR lpCommand, LPCTSTR lpRequiredArgs, LPC
const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_NUITKA = 1; const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_NUITKA = 1;
const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_NUITKA = 0; const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_NUITKA = 0;
static int ParseNuitkaOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, BOOL& bUseDefaultTagWhenMissing, CString& strExtraArgs, BOOL& bTestMode) static int ParseNuitkaOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, CString& strExtraArgs, BOOL& bTestMode)
{ {
lpRepoPath = NULL; lpRepoPath = NULL;
bUseDefaultTagWhenMissing = FALSE;
strExtraArgs.Empty(); strExtraArgs.Empty();
bTestMode = FALSE; bTestMode = FALSE;
BOOL bExtraArgsStarted = FALSE;
for (int i = 4; i < argc; ++i) for (int i = 3; i < argc; ++i)
{ {
CString strArg = argv[i]; CString strArg = argv[i];
BOOL bOptionStyleArg = !strArg.IsEmpty() && strArg.Left(1) == _T("-");
// 仅在额外参数尚未开始时,将 -f 解释为 gitver 选项; if (strArg.CompareNoCase(_T("-test")) == 0)
// 一旦进入额外参数阶段,-f 应透传给 Nuitka。
if (!bExtraArgsStarted && strArg.CompareNoCase(_T("-f")) == 0)
{
bUseDefaultTagWhenMissing = TRUE;
continue;
}
if (!bExtraArgsStarted && strArg.CompareNoCase(_T("-test")) == 0)
{ {
bTestMode = TRUE; bTestMode = TRUE;
continue; continue;
} }
if (!bExtraArgsStarted && lpRepoPath == NULL && !bOptionStyleArg && PathIsDirectory(argv[i])) if (strArg.GetLength() > 8 && strArg.Left(8).CompareNoCase(_T("repodir=")) == 0)
{ {
lpRepoPath = argv[i]; if (lpRepoPath != NULL)
{
_tprintf(_T("错误: repodir 参数重复: %s\n"), argv[i]);
return 23;
}
LPCTSTR lpPath = argv[i] + 8;
if (!PathIsDirectory(lpPath))
{
PrintInvalidRepoPathError(lpPath);
return 23;
}
lpRepoPath = lpPath;
continue; continue;
} }
if (!bExtraArgsStarted && lpRepoPath == NULL && !bOptionStyleArg && IsLikelyPathArg(argv[i])) if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("params=")) == 0)
{ {
PrintInvalidRepoPathError(argv[i]);
return 23;
}
bExtraArgsStarted = TRUE;
if (!strExtraArgs.IsEmpty()) if (!strExtraArgs.IsEmpty())
{ {
strExtraArgs += _T(" "); _tprintf(_T("错误: params 参数重复。\n"));
return 3;
} }
strExtraArgs += QuoteCmdArg(argv[i]); CString strVal = strArg.Mid(7);
// 去掉外层双引号(如 params="--standalone"
if (strVal.GetLength() >= 2 && strVal[0] == _T('"') && strVal[strVal.GetLength() - 1] == _T('"'))
strVal = strVal.Mid(1, strVal.GetLength() - 2);
strExtraArgs = strVal;
continue;
}
_tprintf(_T("错误: 未知的参数 %s\n"), argv[i]);
return 3;
} }
if (lpRepoPath == NULL) if (lpRepoPath == NULL)
@@ -87,6 +91,7 @@ static void RunNuitkaBuild(LPCTSTR lpStartMessage, CString& strNuitkaCmd, const
static int HandleNuitkaBuildCommandCore( static int HandleNuitkaBuildCommandCore(
int argc, int argc,
TCHAR* argv[], TCHAR* argv[],
int nCmdPrefixLen,
BOOL bBuildModule, BOOL bBuildModule,
LPCTSTR lpStartMessage, LPCTSTR lpStartMessage,
LPCTSTR lpUsageName, LPCTSTR lpUsageName,
@@ -97,28 +102,27 @@ static int HandleNuitkaBuildCommandCore(
int nTagErrorCode, int nTagErrorCode,
int nCommitErrorCode) int nCommitErrorCode)
{ {
if (argc < 4) // 解析 pid内嵌在 argv[1] 中,如 "nuitkabuild=5"
CString strPid = CString(argv[1]).Mid(nCmdPrefixLen);
UINT nPid = 0;
if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid))
{ {
_tprintf(_T("错误: 参数不足。\n")); _tprintf(_T("错误: %s= 后的 pid 无效:%s应为 0-65535 范围的整数。\n"), lpUsageName, strPid.GetString());
CString strRequiredArgs; return nPidErrorCode;
strRequiredArgs.Format(_T("[pid] [%s]"), lpEntryArgName); }
PrintCommandUsageAndExamples(lpUsageName, strRequiredArgs.GetString(), lpEntryArgName);
if (argc < 3)
{
_tprintf(_T("错误: 参数不足,缺少 %s。\n"), lpEntryArgName);
_tprintf(_T("用法gitver %s=<pid> <%s> [repodir=<path>可选] [-test可选] [params=\"<nuitka参数>\"\u53ef选]\n"), lpUsageName, lpEntryArgName);
return nArgLackErrorCode; return nArgLackErrorCode;
} }
UINT nPid = 0; CString strMainOrModulePy = argv[2];
int nArgRet = ParseUInt16ArgOrError(argv, 2, _T("pid"), nPid, nPidErrorCode);
if (nArgRet != 0)
{
return nArgRet;
}
CString strMainOrModulePy = argv[3];
LPCTSTR lpRepoPath = NULL; LPCTSTR lpRepoPath = NULL;
BOOL bUseDefaultTagWhenMissing = FALSE;
CString strExtraArgs; CString strExtraArgs;
BOOL bTestMode = FALSE; BOOL bTestMode = FALSE;
int nRepoArgRet = ParseNuitkaOptions(argc, argv, lpRepoPath, bUseDefaultTagWhenMissing, strExtraArgs, bTestMode); int nRepoArgRet = ParseNuitkaOptions(argc, argv, lpRepoPath, strExtraArgs, bTestMode);
if (nRepoArgRet != 0) if (nRepoArgRet != 0)
{ {
return nRepoArgRet; return nRepoArgRet;
@@ -133,7 +137,6 @@ static int HandleNuitkaBuildCommandCore(
errorCodes, errorCodes,
strProductVersion, strProductVersion,
strFileVersion, strFileVersion,
bUseDefaultTagWhenMissing,
DEFAULT_MAJOR_WHEN_NO_TAG_FOR_NUITKA, DEFAULT_MAJOR_WHEN_NO_TAG_FOR_NUITKA,
DEFAULT_MINOR_WHEN_NO_TAG_FOR_NUITKA); DEFAULT_MINOR_WHEN_NO_TAG_FOR_NUITKA);
if (nVersionRet != 0) if (nVersionRet != 0)
@@ -181,6 +184,7 @@ int HandleNuitkaBuildCommand(int argc, TCHAR* argv[])
return HandleNuitkaBuildCommandCore( return HandleNuitkaBuildCommandCore(
argc, argc,
argv, argv,
12,
FALSE, FALSE,
_T("Nuitka 打包开始.."), _T("Nuitka 打包开始.."),
_T("nuitkabuild"), _T("nuitkabuild"),
@@ -197,6 +201,7 @@ int HandleNuitkaPydBuildCommand(int argc, TCHAR* argv[])
return HandleNuitkaBuildCommandCore( return HandleNuitkaBuildCommandCore(
argc, argc,
argv, argv,
15,
TRUE, TRUE,
_T("Nuitka pyd 打包开始.."), _T("Nuitka pyd 打包开始.."),
_T("nuitkapydbuild"), _T("nuitkapydbuild"),

View File

@@ -14,7 +14,7 @@ BOOL ReadTextFileAsAnsi(LPCTSTR lpFile, std::string& strContent, std::string& st
BOOL WriteTextFileAsAnsi(LPCTSTR lpFile, const std::string& strContent, const std::string& strBomPrefix); BOOL WriteTextFileAsAnsi(LPCTSTR lpFile, const std::string& strContent, const std::string& strBomPrefix);
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& bTestMode);
static const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP = 1; static const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP = 1;
static const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP = 0; static const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP = 0;
@@ -334,9 +334,9 @@ int HandleSetupCommand(int argc, TCHAR* argv[])
if (argc < 3) if (argc < 3)
{ {
_tprintf(_T("错误: 参数不足。\n")); _tprintf(_T("错误: 参数不足。\n"));
_tprintf(_T("用法gitver -setup=0|1 [pid] [repoPath可选]\n")); _tprintf(_T("用法gitver -setup=0|1 [pid] [repodir=<path>可选]\n"));
_tprintf(_T("示例gitver -setup=0 5\n")); _tprintf(_T("示例gitver -setup=0 5\n"));
_tprintf(_T("示例gitver -setup=1 5 E:\\Code\\MyProj\n")); _tprintf(_T("示例gitver -setup=1 5 repodir=E:\\Code\\MyProj\n"));
return 3; return 3;
} }
@@ -348,9 +348,8 @@ int HandleSetupCommand(int argc, TCHAR* argv[])
} }
LPCTSTR lpRepoPath = NULL; LPCTSTR lpRepoPath = NULL;
BOOL bUseDefaultTagWhenMissing = FALSE;
BOOL bTestMode = FALSE; BOOL bTestMode = FALSE;
int nRepoArgRet = ParseSetVerOptions(argc, argv, 3, lpRepoPath, bUseDefaultTagWhenMissing, bTestMode); int nRepoArgRet = ParseSetVerOptions(argc, argv, 3, lpRepoPath, bTestMode);
if (nRepoArgRet != 0) if (nRepoArgRet != 0)
{ {
return nRepoArgRet; return nRepoArgRet;
@@ -365,7 +364,6 @@ int HandleSetupCommand(int argc, TCHAR* argv[])
errorCodes, errorCodes,
strProductVersion, strProductVersion,
strFileVersion, strFileVersion,
bUseDefaultTagWhenMissing,
DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP, DEFAULT_MAJOR_WHEN_NO_TAG_FOR_SETUP,
DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP); DEFAULT_MINOR_WHEN_NO_TAG_FOR_SETUP);
if (nVersionRet != 0) if (nVersionRet != 0)

View File

@@ -6,7 +6,7 @@
BOOL TryGetCurrentBranch(LPCTSTR lpRepoPath, CString& strBranch) BOOL TryGetCurrentBranch(LPCTSTR lpRepoPath, CString& strBranch)
{ {
_tprintf(_T("获取当前分支名称:\n")); _tprintf(_T("<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>֧<EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD>\n"));
strBranch = StartProcess(NULL, _T("cmd /c git rev-parse --abbrev-ref HEAD"), lpRepoPath); strBranch = StartProcess(NULL, _T("cmd /c git rev-parse --abbrev-ref HEAD"), lpRepoPath);
strBranch.Replace(_T("\r"), _T("")); strBranch.Replace(_T("\r"), _T(""));
strBranch.Replace(_T("\n"), _T("")); strBranch.Replace(_T("\n"), _T(""));
@@ -92,7 +92,7 @@ BOOL GetLastMajorMinorTag(LPCTSTR lpRepoPath, const CString& strBranch, CString&
CString strTagList = StartProcess(NULL, _T("cmd /c git tag --list --sort=v:refname"), lpRepoPath); CString strTagList = StartProcess(NULL, _T("cmd /c git tag --list --sort=v:refname"), lpRepoPath);
if (strTagList.IsEmpty()) if (strTagList.IsEmpty())
{ {
_tprintf(_T("错误: 获取标签列表失败\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1>ǩ<EFBFBD>б<EFBFBD>ʧ<EFBFBD><CAA7>\n"));
return FALSE; return FALSE;
} }
@@ -103,7 +103,7 @@ BOOL GetLastMajorMinorTag(LPCTSTR lpRepoPath, const CString& strBranch, CString&
strLine.Trim(); strLine.Trim();
if (strLine.Left(6).CompareNoCase(_T("fatal:")) == 0) if (strLine.Left(6).CompareNoCase(_T("fatal:")) == 0)
{ {
_tprintf(_T("错误: 获取标签列表失败 %s\n"), strLine.GetString()); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1>ǩ<EFBFBD>б<EFBFBD>ʧ<EFBFBD><CAA7> %s\n"), strLine.GetString());
return FALSE; return FALSE;
} }
@@ -125,7 +125,7 @@ BOOL GetLastMajorMinorTag(LPCTSTR lpRepoPath, const CString& strBranch, CString&
void GetFileVersionDateFromSystemTime(const SYSTEMTIME& stLocal, UINT& nYY, UINT& nMMDD) void GetFileVersionDateFromSystemTime(const SYSTEMTIME& stLocal, UINT& nYY, UINT& nMMDD)
{ {
nYY = stLocal.wYear % 100; nYY = stLocal.wYear % 100;
// 为了让版本号对齐4位月份从1-12映射到11-22; // Ϊ<EFBFBD><EFBFBD><EFBFBD>ð汾<EFBFBD>Ŷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·ݴ<EFBFBD>1-12ӳ<EFBFBD>11-22;
nMMDD = (stLocal.wMonth + 10) * 100 + stLocal.wDay; nMMDD = (stLocal.wMonth + 10) * 100 + stLocal.wDay;
} }
@@ -221,32 +221,32 @@ BOOL ResolveFileVersionDateAndCommitCount(LPCTSTR lpRepoPath, const CString& str
UINT nTodayCommitCount = 0; UINT nTodayCommitCount = 0;
if (!TryGetBranchCommitCountByDate(lpRepoPath, strBranch, stTargetDate, nTodayCommitCount)) if (!TryGetBranchCommitCountByDate(lpRepoPath, strBranch, stTargetDate, nTodayCommitCount))
{ {
_tprintf(_T("错误: 获取当天提交数量失败\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E1BDBB><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>\n"));
return FALSE; return FALSE;
} }
if (nTodayCommitCount == 0) if (nTodayCommitCount == 0)
{ {
_tprintf(_T("当天提交数量为0将获取最后一次提交日期\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n"));
if (!TryGetLastBranchCommitDate(lpRepoPath, strBranch, stTargetDate)) if (!TryGetLastBranchCommitDate(lpRepoPath, strBranch, stTargetDate))
{ {
_tprintf(_T("错误: 获取最后一次提交日期失败\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><E1BDBB><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>\n"));
return FALSE; return FALSE;
} }
if (!TryGetBranchCommitCountByDate(lpRepoPath, strBranch, stTargetDate, nTodayCommitCount)) if (!TryGetBranchCommitCountByDate(lpRepoPath, strBranch, stTargetDate, nTodayCommitCount))
{ {
_tprintf(_T("错误: 获取[%s]提交数量失败\n"), strBranch.GetString()); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ[%s]<5D><EFBFBD><E1BDBB><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>\n"), strBranch.GetString());
return FALSE; return FALSE;
} }
_tprintf(_T("获取到最后一次提交日期: %04u-%02u-%02u, 提交数量: %u\n"), _tprintf(_T("<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: %04u-%02u-%02u, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: %u\n"),
stTargetDate.wYear, stTargetDate.wMonth, stTargetDate.wDay, nTodayCommitCount); stTargetDate.wYear, stTargetDate.wMonth, stTargetDate.wDay, nTodayCommitCount);
} }
else else
{ {
_tprintf(_T("获取到当天提交数量: %u\n"), nTodayCommitCount); _tprintf(_T("<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: %u\n"), nTodayCommitCount);
} }
GetFileVersionDateFromSystemTime(stTargetDate, nYY, nMMDD); GetFileVersionDateFromSystemTime(stTargetDate, nYY, nMMDD);
@@ -260,14 +260,12 @@ int BuildVersionsFromRepo(
const VersionBuildErrorCodes& errorCodes, const VersionBuildErrorCodes& errorCodes,
CString& strProductVersion, CString& strProductVersion,
CString& strFileVersion, CString& strFileVersion,
BOOL bUseDefaultTagWhenMissing,
UINT nDefaultMajor, UINT nDefaultMajor,
UINT nDefaultMinor) UINT nDefaultMinor)
{ {
_tprintf(_T("开始构建版本: 仓库路径=%s pid=%u 默认Tag(%s)=%u.%u\n"), _tprintf(_T("\xBF\xAA\xCA\xBC\xB9\xB9\xBD\xA8\xB0\xE6\xB1\xBE: \xB2\xD6\xBF\xE2\xC2\xB7\xBE\xB6=%s pid=%u default=%u.%u\n"),
lpRepoPath == NULL ? _T("<null>") : lpRepoPath, lpRepoPath == NULL ? _T("<null>") : lpRepoPath,
nPid, nPid,
bUseDefaultTagWhenMissing ? _T("启用") : _T("关闭"),
nDefaultMajor, nDefaultMajor,
nDefaultMinor); nDefaultMinor);
@@ -275,36 +273,30 @@ int BuildVersionsFromRepo(
CString strBranch; CString strBranch;
if (!TryGetCurrentBranch(lpRepoPath, strBranch)) if (!TryGetCurrentBranch(lpRepoPath, strBranch))
{ {
_tprintf(_T("错误: 获取当前分支失败。\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0>֧ʧ<D6A7>ܡ<EFBFBD>\n"));
return errorCodes.nBidErrorCode; return errorCodes.nBidErrorCode;
} }
_tprintf(_T("当前分支: %s\n"), strBranch.GetString()); _tprintf(_T("<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>֧: %s\n"), strBranch.GetString());
if (!TryGetBidFromBranch(strBranch, nBid)) if (!TryGetBidFromBranch(strBranch, nBid))
{ {
_tprintf(_T("错误: 获取分支 bid 失败\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1>֧ bid ʧ<EFBFBD><EFBFBD>\n"));
return errorCodes.nBidErrorCode; return errorCodes.nBidErrorCode;
} }
_tprintf(_T("分支 bid: %u\n"), nBid); _tprintf(_T("<EFBFBD><EFBFBD>֧ bid: %u\n"), nBid);
CString strLastTag; CString strLastTag;
UINT nMajor = 0; UINT nMajor = 0;
UINT nMinor = 0; UINT nMinor = 0;
if (!GetLastMajorMinorTag(lpRepoPath, strBranch, strLastTag, nMajor, nMinor)) if (!GetLastMajorMinorTag(lpRepoPath, strBranch, strLastTag, nMajor, nMinor))
{ {
if (!bUseDefaultTagWhenMissing)
{
_tprintf(_T("错误: 获取标签失败\n"));
return errorCodes.nTagErrorCode;
}
nMajor = nDefaultMajor; nMajor = nDefaultMajor;
nMinor = nDefaultMinor; nMinor = nDefaultMinor;
_tprintf(_T("使用默认标签 %u %u\n"), nMajor, nMinor); _tprintf(_T("ʹ<EFBFBD><EFBFBD>Ĭ<EFBFBD>ϱ<EFBFBD>ǩ %u %u\n"), nMajor, nMinor);
} }
else else
{ {
_tprintf(_T("获取到的标签: %s (major=%u minor=%u)\n"), strLastTag.GetString(), nMajor, nMinor); _tprintf(_T("<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>ǩ: %s (major=%u minor=%u)\n"), strLastTag.GetString(), nMajor, nMinor);
} }
UINT nYY = 0; UINT nYY = 0;
@@ -312,13 +304,13 @@ int BuildVersionsFromRepo(
UINT nId = 0; UINT nId = 0;
if (!ResolveFileVersionDateAndCommitCount(lpRepoPath, strBranch, nYY, nMMDD, nId)) if (!ResolveFileVersionDateAndCommitCount(lpRepoPath, strBranch, nYY, nMMDD, nId))
{ {
_tprintf(_T("错误: 获取分支提交信息失败\n")); _tprintf(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><>ȡ<EFBFBD><C8A1>֧<EFBFBD><EFBFBD><E1BDBB>Ϣʧ<CFA2><CAA7>\n"));
return errorCodes.nCommitErrorCode; return errorCodes.nCommitErrorCode;
} }
_tprintf(_T("分支提交信息: yy=%u mmdd=%u id=%u\n"), nYY, nMMDD, nId); _tprintf(_T("<EFBFBD><EFBFBD>֧<EFBFBD><EFBFBD><EFBFBD>Ϣ: yy=%u mmdd=%u id=%u\n"), nYY, nMMDD, nId);
strProductVersion.Format(_T("%u.%u.%u.%u"), nPid, nBid, nMajor, nMinor); strProductVersion.Format(_T("%u.%u.%u.%u"), nPid, nBid, nMajor, nMinor);
strFileVersion.Format(_T("%u.%u.%u.%u"), nPid, nYY, nMMDD, nId); strFileVersion.Format(_T("%u.%u.%u.%u"), nPid, nYY, nMMDD, nId);
_tprintf(_T("文件版本信息: ProductVersion=%s FileVersion=%s\n"), strProductVersion.GetString(), strFileVersion.GetString()); _tprintf(_T("<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ: ProductVersion=%s FileVersion=%s\n"), strProductVersion.GetString(), strFileVersion.GetString());
return 0; return 0;
} }

View File

@@ -17,6 +17,5 @@ int BuildVersionsFromRepo(
const VersionBuildErrorCodes& errorCodes, const VersionBuildErrorCodes& errorCodes,
CString& strProductVersion, CString& strProductVersion,
CString& strFileVersion, CString& strFileVersion,
BOOL bUseDefaultTagWhenMissing,
UINT nDefaultMajor, UINT nDefaultMajor,
UINT nDefaultMinor); UINT nDefaultMinor);

372
README.md
View File

@@ -1,2 +1,372 @@
# GitVer # GitVer
# 命令行版本管理工具
命令行版本管理工具,从 Git 仓库读取 tag 自动生成并回写版本号。
---
## 用法总览
```
gitver
gitver rewrite [PEType] [-f]
gitver setver=<pid> [repodir=<path>] [-f] [-test] [-setup=0|1]
gitver nuitkabuild=<pid> <mainPy> [repodir=<path>] [-f] [-test] [params="<nuitka参数>"]
gitver nuitkapydbuild=<pid> <modulePy> [repodir=<path>] [-f] [-test] [params="<nuitka参数>"]
gitver -setup=0|1 <pid> [repodir=<path>] [-f] [-test]
```
**通用参数说明:**
| 参数 | 说明 |
|---|---|
| `pid` | 产品 ID整数范围 0-65535内嵌在命令名中`setver=5` |
| `repodir=<path>` | Git 仓库目录,缺省使用当前运行目录 |
| `-f` | 未找到当前分支 tag 时使用默认 major/minor1.0)继续 |
| `-test` | 将产品版本号的 major/minor 置为 0测试版本构建 |
| `params="..."` | 传递给 Nuitka 的额外参数,用双引号括起来 |
**BID 规则:**
`main`/`master` 分支固定 `bid=0`;其他分支格式须为 `<描述>.<数字>`,自动读取末尾数字作为 `bid`
---
## 命令详解
### `gitver`(无参数交互模式)
自动读取当前分支最近三次符合 `<分支>.major.minor` 格式的 tag提示用户选择 major+1 或 minor+1二次确认后创建新 tag。
当前分支无有效 tag 时进入首发引导:提示输入默认 major/minor回车使用默认 1/0再创建首个 tag。
**交互示例(已有 tag**
```
当前分支: main最近三个 tag
main.1920.9
main.1920.10
main.1920.11
输入 1 → 创建 main.1921.0
输入 2 → 创建 main.1920.12
```
**交互示例(无 tag 首发):**
```
未找到符合规则的历史标签
输入默认 major回车=1: 2
输入默认 minor回车=0: 5
→ 创建 <分支>.2.5
```
---
### `gitver rewrite`
自动识别当前目录源码类型C++、C#、Python执行默认版本回写。
```
gitver rewrite [PEType] [-f]
```
| 参数 | 说明 |
|---|---|
| `PEType` | 可选,`1`=EXE默认`2`=DLL最多出现一次 |
| `-f` | 强制模式:未找到目标文件或回写失败仅提示,不返回错误码 35 |
**回写行为:**
- **C++**:递归查找首个 `.rc` 文件,回写 `FILEVERSION``PRODUCTVERSION``VALUE "FileVersion"``VALUE "ProductVersion"`(限定在 `VS_VERSION_INFO` 版本块内)
- **C#**:递归查找首个 `AssemblyInfo.cs`,回写 `AssemblyVersion``AssemblyFileVersion`
- **Python**:不执行回写,提示改用 `nuitkabuild=``nuitkapydbuild=`
**示例:**
```
gitver rewrite
gitver rewrite 2
gitver rewrite -f
```
---
### `gitver setver=<pid>`
从 Git 仓库读取 tag生成产品版本号与文件版本号并按源码类型自动回写。
```
gitver setver=<pid> [repodir=<path>] [-f] [-test] [-setup=0|1]
```
**版本号生成规则:**
- `ProductVersion = pid.bid.major.minor`(取当前分支前缀的最新 tag
- `FileVersion = pid.yy.mmdd.id`id = 当天当前分支提交次数)
**`-setup=N` 标志(打包模式):**
存在 `-setup=N` 时,**不回写**版本信息到项目文件,改为:
1. 在 exe 目录或上级目录查找安装脚本
2. 修改脚本中的版本号字段
3. 调用对应编译器打包
| 值 | 脚本文件 | 编译器 |
|---|---|---|
| `0` | `setup.iss` | Inno Setup`ISCC.exe` |
| `1` | `setup.nsi` | NSIS`makensis.exe` |
**示例:**
```
gitver setver=5
gitver setver=5 repodir=E:\Code\OTH\gitver
gitver setver=5 -f
gitver setver=5 -test
gitver setver=5 -setup=0
gitver setver=5 repodir=E:\Code\MyProj -setup=1
```
**输出示例:**
```
ProductVersion=5.0.1920.11
FileVersion=5.26.0519.3
```
**回写说明:**
- **C++**:回写 `.rc` 文件中的 FILEVERSION、PRODUCTVERSION 及对应字符串字段
- **C#**:回写 `AssemblyInfo.cs` 中的 AssemblyVersion、AssemblyFileVersion
- **Python**:仅输出版本号,不执行文件回写,提示改用 Nuitka 命令
- 编码:支持 ANSI/UTF-8保留 UTF-8 BOMUTF-16 文件会报错停止
---
### `gitver nuitkabuild=<pid>`
生成版本号并调用 Nuitka 打包 Python 程序EXE 模式)。
```
gitver nuitkabuild=<pid> <mainPy> [repodir=<path>] [-f] [-test] [params="<nuitka参数>"]
```
自动调用:
```
python -m nuitka --windows-product-version=<版本> --windows-file-version=<版本> <extra> <mainPy>
```
**示例:**
```
gitver nuitkabuild=5 main.py
gitver nuitkabuild=5 main.py -f
gitver nuitkabuild=5 main.py -test
gitver nuitkabuild=5 src\app.py repodir=E:\Code\MyPyProj params="--standalone --output-dir=dist"
```
**输出示例:**
```
Nuitka 打包开始..
ProductVersion=5.0.1920.11
FileVersion=5.26.0519.3
```
> 需要当前环境已安装 Nuitka可通过 `python -m nuitka --version` 验证)。
---
### `gitver nuitkapydbuild=<pid>`
生成版本号并调用 Nuitka 打包 Python 模块pyd/DLL 模式)。
```
gitver nuitkapydbuild=<pid> <modulePy> [repodir=<path>] [-f] [-test] [params="<nuitka参数>"]
```
自动调用:
```
python -m nuitka --module --windows-product-version=<版本> --windows-file-version=<版本> <extra> <modulePy>
```
**示例:**
```
gitver nuitkapydbuild=5 module.py
gitver nuitkapydbuild=5 module.py -f
gitver nuitkapydbuild=5 module.py -test
gitver nuitkapydbuild=5 src\core.py repodir=E:\Code\MyPyProj params="--output-dir=dist"
```
> 需要当前环境已安装 Nuitka可通过 `python -m nuitka --version` 验证)。
---
### `gitver -setup=0|1`(独立打包命令)
独立调用安装脚本打包,不依赖 `setver=` 命令。
```
gitver -setup=0|1 <pid> [repodir=<path>] [-f] [-test]
```
**示例:**
```
gitver -setup=0 5
gitver -setup=1 5 repodir=E:\Code\MyProj
```
---
## 错误码
| 码 | 含义 |
|---|---|
| 2 | 默认回写流程下未获取到 git 提交号 |
| 3 | 参数非法或未知参数 |
| 4 | `setver=` 的 pid 非法 |
| 5 | `setver=` 无法根据分支名计算 bid |
| 6 | `setver=` 未找到当前分支格式 tag |
| 9 | `setver=` 获取当天分支提交次数失败 |
| 15 | 回写流程未识别源码类型 |
| 16 | 回写流程识别到 Python请改用 nuitka 命令 |
| 17 | `nuitkabuild=` 参数不足(缺少 mainPy |
| 18 | `nuitkabuild=` 的 pid 非法 |
| 19 | `nuitkabuild=` 无法根据分支名计算 bid |
| 20 | `nuitkabuild=` 未找到当前分支格式 tag |
| 21 | `nuitkabuild=` 获取当天分支提交次数失败 |
| 22 | `rewrite` 参数非法PEType 非法或重复) |
| 23 | `repodir=` 不是有效目录 |
| 24 | `nuitkapydbuild=` 参数不足(缺少 modulePy |
| 25 | `nuitkapydbuild=` 的 pid 非法 |
| 26 | `nuitkapydbuild=` 无法根据分支名计算 bid |
| 27 | `nuitkapydbuild=` 未找到当前分支格式 tag |
| 28 | `nuitkapydbuild=` 获取当天分支提交次数失败 |
| 29 | 无参数模式下无法获取当前分支 |
| 30 | 无参数模式下读取标签列表失败 |
| 31 | 无参数模式下未读取到用户输入 |
| 32 | 无参数模式下用户选择非法,或 major/minor 已达上限 |
| 33 | 无参数模式下创建 tag 失败 |
| 34 | 无参数模式下创建 tag 后校验失败 |
| 35 | 未找到可回写目标文件,或回写失败 |
| 36 | `-setup=` 值不支持(仅支持 0 和 1 |
| 37 | 未找到安装脚本setup.iss / setup.nsi |
| 38 | 修改安装脚本失败 |
| 39 | 未找到安装编译器ISCC.exe / makensis.exe |
---
## 最小自测
### 基础验证:`setver=`
```bash
# 初始化测试仓库
mkdir test_repo && cd test_repo
git init
echo test > README.txt
git add . && git commit -m "init"
git tag main.1920.10
git tag main.1920.11
# 验证版本生成
gitver setver=5
# 预期:
# ProductVersion=5.0.1920.11
# FileVersion=5.yy.mmdd.<id>
# 返回码: 0
```
### 验证 `-f`(无 tag 时使用默认版本)
```bash
git checkout -b newbranch
gitver setver=5 -f
# 预期: ProductVersion=5.<bid>.1.0
# 返回码: 0
```
### 验证分支 tag 隔离
```bash
git checkout -b feature.12
git tag feature.12.1930.7
git tag feature.12.1930.8
gitver setver=5
# 预期: ProductVersion=5.12.1930.8(忽略 main.* tag
# 返回码: 0
```
### 验证 `-test`
```bash
gitver setver=5 -test
# 预期: ProductVersion=5.0.0.0major/minor 置零)
# 返回码: 0
```
### 验证 `nuitkabuild=`
```bash
gitver nuitkabuild=5 main.py
# 预期: 调用 python -m nuitka注入版本号参数
gitver nuitkabuild=5 src\app.py params="--standalone --output-dir=dist"
# 预期: 额外参数传递给 Nuitka
```
### 验证 `-setup=`
```bash
# 确保 exe 目录或上级目录有 setup.iss
gitver setver=5 -setup=0
# 预期: 修改 setup.iss 中的版本号并调用 ISCC.exe 编译
```
---
## 回归清单
### rewrite 组
| 命令 | 预期返回码 |
|---|---|
| `gitver rewrite` | 0 / 15 / 16 / 35 |
| `gitver rewrite -f` | 0 / 15 / 16 |
| `gitver rewrite 2` | 0 / 15 / 35 |
| `gitver rewrite 1 2` | 22 |
### setver= 组
| 命令 | 预期返回码 |
|---|---|
| `gitver setver=5` | 0 |
| `gitver setver=5 -f` | 0 |
| `gitver setver=5 -test` | 0 |
| `gitver setver=5 repodir=E:\NotExists` | 23 |
| `gitver setver=5 -setup=0` | 0 / 37 / 38 / 39 |
| `gitver setver=5 -setup=9` | 36 |
| `gitver setver=abc` | 4 |
### nuitkabuild= 组
| 命令 | 预期返回码 |
|---|---|
| `gitver nuitkabuild=5 main.py` | 0 / 19 / 20 / 21 |
| `gitver nuitkabuild=5 main.py -f` | 0 |
| `gitver nuitkabuild=5 main.py -test` | 0 |
| `gitver nuitkabuild=5 main.py params="--standalone"` | 0 |
| `gitver nuitkabuild=5 main.py repodir=E:\NotExists` | 23 |
| `gitver nuitkabuild=5` | 17 |
### nuitkapydbuild= 组
| 命令 | 预期返回码 |
|---|---|
| `gitver nuitkapydbuild=5 module.py` | 0 / 26 / 27 / 28 |
| `gitver nuitkapydbuild=5 module.py -f` | 0 |
| `gitver nuitkapydbuild=5 module.py params="--output-dir=dist"` | 0 |
| `gitver nuitkapydbuild=5 module.py repodir=E:\NotExists` | 23 |
| `gitver nuitkapydbuild=5` | 24 |