562 lines
16 KiB
C++
562 lines
16 KiB
C++
#include "pch.h"
|
||
#include "gitver.h"
|
||
#include "gitver_cli.h"
|
||
#include "gitver_common.h"
|
||
#include "gitver_process.h"
|
||
#include "gitver_version.h"
|
||
#include "gitver_pyinstaller.h"
|
||
|
||
extern TCHAR g_szCurModuleDir[MAX_PATH];
|
||
|
||
const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER = 1;
|
||
const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER = 0;
|
||
|
||
static int ParsePyinstallerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, CString& strExtraArgs, BOOL& bTestMode)
|
||
{
|
||
lpRepoPath = NULL;
|
||
strExtraArgs.Empty();
|
||
bTestMode = FALSE;
|
||
|
||
for (int i = 2; i < argc; ++i)
|
||
{
|
||
CString strArg = argv[i];
|
||
|
||
if (strArg.CompareNoCase(_T("-test")) == 0)
|
||
{
|
||
bTestMode = TRUE;
|
||
continue;
|
||
}
|
||
|
||
if (strArg.GetLength() > 8 && strArg.Left(8).CompareNoCase(_T("repodir=")) == 0)
|
||
{
|
||
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;
|
||
}
|
||
|
||
if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("params=")) == 0)
|
||
{
|
||
if (!strExtraArgs.IsEmpty())
|
||
{
|
||
_tprintf(_T("错误: params 参数重复。\n"));
|
||
return 3;
|
||
}
|
||
CString strVal = strArg.Mid(7);
|
||
// 去掉外层双引号(如 params="--onefile")
|
||
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)
|
||
{
|
||
lpRepoPath = g_szCurModuleDir;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
// 解析版本字符串 "a.b.c.d" → 四个分量
|
||
static BOOL ParseVersionTuple(LPCTSTR lpVer, UINT& v1, UINT& v2, UINT& v3, UINT& v4)
|
||
{
|
||
CString str(lpVer);
|
||
int p1 = str.Find(_T('.'));
|
||
if (p1 < 0) return FALSE;
|
||
int p2 = str.Find(_T('.'), p1 + 1);
|
||
if (p2 < 0) return FALSE;
|
||
int p3 = str.Find(_T('.'), p2 + 1);
|
||
if (p3 < 0) return FALSE;
|
||
v1 = (UINT)_ttoi(str.Left(p1));
|
||
v2 = (UINT)_ttoi(str.Mid(p1 + 1, p2 - p1 - 1));
|
||
v3 = (UINT)_ttoi(str.Mid(p2 + 1, p3 - p2 - 1));
|
||
v4 = (UINT)_ttoi(str.Mid(p3 + 1));
|
||
return TRUE;
|
||
}
|
||
|
||
// 提取 params 中第一个空格分隔的 token(支持双引号括起的路径)
|
||
static CString ExtractFirstToken(const CString& strParams)
|
||
{
|
||
CString str = strParams;
|
||
str.TrimLeft();
|
||
if (str.IsEmpty()) return _T("");
|
||
if (str[0] == _T('"'))
|
||
{
|
||
int nEnd = str.Find(_T('"'), 1);
|
||
if (nEnd < 0) return str.Mid(1);
|
||
return str.Mid(1, nEnd - 1);
|
||
}
|
||
int nSpace = str.Find(_T(' '));
|
||
if (nSpace < 0) return str;
|
||
return str.Left(nSpace);
|
||
}
|
||
|
||
// 生成 version_info.txt 到 lpDir 目录(PyInstaller VSVersionInfo 格式)
|
||
static BOOL WriteVersionInfoFile(LPCTSTR lpDir, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion, CString& strOutPath)
|
||
{
|
||
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
||
UINT fv1 = 0, fv2 = 0, fv3 = 0, fv4 = 0;
|
||
if (!ParseVersionTuple(lpProductVersion, pv1, pv2, pv3, pv4)) return FALSE;
|
||
if (!ParseVersionTuple(lpFileVersion, fv1, fv2, fv3, fv4)) return FALSE;
|
||
|
||
CStringA strProdVerA(lpProductVersion);
|
||
CStringA strFileVerA(lpFileVersion);
|
||
const char* szProdVer = strProdVerA;
|
||
const char* szFileVer = strFileVerA;
|
||
|
||
strOutPath.Format(_T("%s\\version_info.txt"), lpDir);
|
||
|
||
FILE* fp = NULL;
|
||
_tfopen_s(&fp, strOutPath.GetString(), _T("wb"));
|
||
if (!fp) return FALSE;
|
||
|
||
fprintf(fp,
|
||
"# UTF-8\n"
|
||
"VSVersionInfo(\n"
|
||
" ffi=FixedFileInfo(\n"
|
||
" filevers=(%u, %u, %u, %u),\n"
|
||
" prodvers=(%u, %u, %u, %u),\n"
|
||
" mask=0x3f,\n"
|
||
" flags=0x0,\n"
|
||
" OS=0x40004,\n"
|
||
" fileType=0x1,\n"
|
||
" subtype=0x0,\n"
|
||
" date=(0, 0)\n"
|
||
" ),\n"
|
||
" kids=[\n"
|
||
" StringFileInfo([\n"
|
||
" StringTable(\n"
|
||
" u'040904B0',\n"
|
||
" [StringStruct(u'CompanyName', u''),\n"
|
||
" StringStruct(u'FileDescription', u''),\n"
|
||
" StringStruct(u'FileVersion', u'%s'),\n"
|
||
" StringStruct(u'InternalName', u''),\n"
|
||
" StringStruct(u'LegalCopyright', u''),\n"
|
||
" StringStruct(u'OriginalFilename', u''),\n"
|
||
" StringStruct(u'ProductName', u''),\n"
|
||
" StringStruct(u'ProductVersion', u'%s'),\n"
|
||
" StringStruct(u'Comments', u''),\n"
|
||
" StringStruct(u'LegalTrademarks', u''),\n"
|
||
" ])\n"
|
||
" ]),\n"
|
||
" VarFileInfo([VarStruct(u'Translation', [0x0409, 1200])])\n"
|
||
" ]\n"
|
||
")\n",
|
||
fv1, fv2, fv3, fv4,
|
||
pv1, pv2, pv3, pv4,
|
||
szFileVer,
|
||
szProdVer);
|
||
|
||
fclose(fp);
|
||
return TRUE;
|
||
}
|
||
|
||
// 向 .spec 文件注入或更新 version= 参数
|
||
// 若已有 version= 则更新其值,否则在 name= 参数后新增一行
|
||
static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
||
{
|
||
if (!PathFileExists(lpSpecPath))
|
||
{
|
||
_tprintf(_T("错误: spec 文件不存在 %s\n"), lpSpecPath);
|
||
return FALSE;
|
||
}
|
||
|
||
CFile myFile;
|
||
CFileException fileEx;
|
||
if (!myFile.Open(lpSpecPath, CFile::modeReadWrite, &fileEx))
|
||
{
|
||
_tprintf(_T("错误: 无法打开 spec 文件 %s\n"), lpSpecPath);
|
||
return FALSE;
|
||
}
|
||
|
||
DWORD dwLen = (DWORD)myFile.GetLength();
|
||
std::vector<char> buf(dwLen + 1, 0);
|
||
myFile.Read(buf.data(), dwLen);
|
||
myFile.Close();
|
||
|
||
std::string strContent(buf.data(), dwLen);
|
||
const std::string strNewValue = "version='version_info.txt'";
|
||
|
||
bool bFound = false;
|
||
std::string::size_type nPos = 0;
|
||
while ((nPos = strContent.find("version=", nPos)) != std::string::npos)
|
||
{
|
||
// 确保 version= 是独立参数(前驱字符为空白或换行,而非字母/数字)
|
||
bool bIsParam = (nPos == 0
|
||
|| strContent[nPos - 1] == '\n'
|
||
|| strContent[nPos - 1] == '\r'
|
||
|| strContent[nPos - 1] == ' '
|
||
|| strContent[nPos - 1] == '\t');
|
||
if (bIsParam)
|
||
{
|
||
// 获取行首(保留缩进)
|
||
std::string::size_type nLineStart = strContent.rfind('\n', nPos);
|
||
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
||
std::string strIndent = strContent.substr(nLineStart, nPos - nLineStart);
|
||
|
||
// 获取行末
|
||
std::string::size_type nLineEnd = strContent.find('\n', nPos);
|
||
if (nLineEnd == std::string::npos) nLineEnd = strContent.size();
|
||
|
||
// 替换整行(保留缩进,统一加尾随逗号)
|
||
std::string strNewLine = strIndent + strNewValue + ",";
|
||
strContent.replace(nLineStart, nLineEnd - nLineStart, strNewLine);
|
||
_tprintf(_T("成功: 已更新 spec 文件 version 字段 -> version_info.txt\n"));
|
||
bFound = true;
|
||
break;
|
||
}
|
||
nPos += 8; // len("version=")
|
||
}
|
||
|
||
if (!bFound)
|
||
{
|
||
// 未找到 version=,在 name= 参数后插入新行
|
||
std::string::size_type nNamePos = strContent.find("name=");
|
||
if (nNamePos != std::string::npos)
|
||
{
|
||
// 获取 name= 行的缩进
|
||
std::string::size_type nLineStart = strContent.rfind('\n', nNamePos);
|
||
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
||
std::string strIndent = strContent.substr(nLineStart, nNamePos - nLineStart);
|
||
|
||
// 找到 name= 行末
|
||
std::string::size_type nLineEnd = strContent.find('\n', nNamePos);
|
||
if (nLineEnd == std::string::npos) nLineEnd = strContent.size() - 1;
|
||
|
||
// 在 name= 行后插入 version=
|
||
std::string strInsert = "\n" + strIndent + strNewValue + ",";
|
||
strContent.insert(nLineEnd, strInsert);
|
||
_tprintf(_T("成功: 已向 spec 文件新增 version 字段 -> version_info.txt\n"));
|
||
}
|
||
else
|
||
{
|
||
_tprintf(_T("警告: spec 文件中未找到 version= 或 name= 参数,跳过版本信息注入。\n"));
|
||
}
|
||
}
|
||
|
||
// 写回文件
|
||
if (!myFile.Open(lpSpecPath, CFile::modeCreate | CFile::modeWrite, &fileEx))
|
||
{
|
||
_tprintf(_T("错误: 无法写入 spec 文件 %s\n"), lpSpecPath);
|
||
return FALSE;
|
||
}
|
||
myFile.Write(strContent.c_str(), (UINT)strContent.size());
|
||
myFile.Close();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// 从 .spec 文件读取 version= 参数的值(单/双引号括起的路径)
|
||
// 返回 FALSE 表示未找到、值为 None 或值为空
|
||
static BOOL ReadVersionPathFromSpec(LPCTSTR lpSpecPath, CString& strVersionPath)
|
||
{
|
||
strVersionPath.Empty();
|
||
if (!PathFileExists(lpSpecPath)) return FALSE;
|
||
|
||
CFile myFile;
|
||
CFileException fileEx;
|
||
if (!myFile.Open(lpSpecPath, CFile::modeRead, &fileEx)) return FALSE;
|
||
|
||
DWORD dwLen = (DWORD)myFile.GetLength();
|
||
std::vector<char> buf(dwLen + 1, 0);
|
||
myFile.Read(buf.data(), dwLen);
|
||
myFile.Close();
|
||
|
||
std::string strContent(buf.data(), dwLen);
|
||
|
||
std::string::size_type nPos = 0;
|
||
while ((nPos = strContent.find("version=", nPos)) != std::string::npos)
|
||
{
|
||
bool bIsParam = (nPos == 0
|
||
|| strContent[nPos - 1] == '\n'
|
||
|| strContent[nPos - 1] == '\r'
|
||
|| strContent[nPos - 1] == ' '
|
||
|| strContent[nPos - 1] == '\t');
|
||
if (bIsParam)
|
||
{
|
||
std::string::size_type nValStart = nPos + 8; // skip "version="
|
||
while (nValStart < strContent.size() && strContent[nValStart] == ' ')
|
||
nValStart++;
|
||
if (nValStart >= strContent.size()) break;
|
||
|
||
char cQuote = strContent[nValStart];
|
||
if (cQuote == '\'' || cQuote == '"')
|
||
{
|
||
std::string::size_type nValEnd = strContent.find(cQuote, nValStart + 1);
|
||
if (nValEnd != std::string::npos && nValEnd > nValStart + 1)
|
||
{
|
||
strVersionPath = strContent.substr(nValStart + 1, nValEnd - nValStart - 1).c_str();
|
||
return TRUE;
|
||
}
|
||
}
|
||
break; // version=None 或空值,视为无
|
||
}
|
||
nPos += 8;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
// 更新已有 version_info 文件的版本字段;若文件不存在则创建
|
||
static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion)
|
||
{
|
||
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
||
UINT fv1 = 0, fv2 = 0, fv3 = 0, fv4 = 0;
|
||
if (!ParseVersionTuple(lpProductVersion, pv1, pv2, pv3, pv4)) return FALSE;
|
||
if (!ParseVersionTuple(lpFileVersion, fv1, fv2, fv3, fv4)) return FALSE;
|
||
|
||
CStringA strProdVerA(lpProductVersion);
|
||
CStringA strFileVerA(lpFileVersion);
|
||
const char* szProdVer = strProdVerA;
|
||
const char* szFileVer = strFileVerA;
|
||
|
||
if (!PathFileExists(lpPath))
|
||
{
|
||
// 文件不存在,直接创建
|
||
FILE* fp = NULL;
|
||
_tfopen_s(&fp, lpPath, _T("wb"));
|
||
if (!fp) return FALSE;
|
||
fprintf(fp,
|
||
"# UTF-8\n"
|
||
"VSVersionInfo(\n"
|
||
" ffi=FixedFileInfo(\n"
|
||
" filevers=(%u, %u, %u, %u),\n"
|
||
" prodvers=(%u, %u, %u, %u),\n"
|
||
" mask=0x3f,\n"
|
||
" flags=0x0,\n"
|
||
" OS=0x40004,\n"
|
||
" fileType=0x1,\n"
|
||
" subtype=0x0,\n"
|
||
" date=(0, 0)\n"
|
||
" ),\n"
|
||
" kids=[\n"
|
||
" StringFileInfo([\n"
|
||
" StringTable(\n"
|
||
" u'040904B0',\n"
|
||
" [StringStruct(u'CompanyName', u''),\n"
|
||
" StringStruct(u'FileDescription', u''),\n"
|
||
" StringStruct(u'FileVersion', u'%s'),\n"
|
||
" StringStruct(u'InternalName', u''),\n"
|
||
" StringStruct(u'LegalCopyright', u''),\n"
|
||
" StringStruct(u'OriginalFilename', u''),\n"
|
||
" StringStruct(u'ProductName', u''),\n"
|
||
" StringStruct(u'ProductVersion', u'%s'),\n"
|
||
" StringStruct(u'Comments', u''),\n"
|
||
" StringStruct(u'LegalTrademarks', u''),\n"
|
||
" ])\n"
|
||
" ]),\n"
|
||
" VarFileInfo([VarStruct(u'Translation', [0x0409, 1200])])\n"
|
||
" ]\n"
|
||
")\n",
|
||
fv1, fv2, fv3, fv4,
|
||
pv1, pv2, pv3, pv4,
|
||
szFileVer,
|
||
szProdVer);
|
||
fclose(fp);
|
||
return TRUE;
|
||
}
|
||
|
||
// 读取现有文件并就地更新版本字段
|
||
CFile myFile;
|
||
CFileException fileEx;
|
||
if (!myFile.Open(lpPath, CFile::modeReadWrite, &fileEx)) return FALSE;
|
||
DWORD dwLen = (DWORD)myFile.GetLength();
|
||
std::vector<char> buf(dwLen + 1, 0);
|
||
myFile.Read(buf.data(), dwLen);
|
||
myFile.Close();
|
||
|
||
std::string s(buf.data(), dwLen);
|
||
char szNew[128];
|
||
|
||
// 更新 filevers 元组
|
||
{
|
||
const std::string key = "filevers=(";
|
||
auto p = s.find(key);
|
||
if (p != std::string::npos) {
|
||
auto pValStart = p + key.size();
|
||
auto pValEnd = s.find(')', pValStart);
|
||
if (pValEnd != std::string::npos) {
|
||
snprintf(szNew, sizeof(szNew), "%u, %u, %u, %u", fv1, fv2, fv3, fv4);
|
||
s.replace(pValStart, pValEnd - pValStart, szNew);
|
||
}
|
||
}
|
||
}
|
||
// 更新 prodvers 元组
|
||
{
|
||
const std::string key = "prodvers=(";
|
||
auto p = s.find(key);
|
||
if (p != std::string::npos) {
|
||
auto pValStart = p + key.size();
|
||
auto pValEnd = s.find(')', pValStart);
|
||
if (pValEnd != std::string::npos) {
|
||
snprintf(szNew, sizeof(szNew), "%u, %u, %u, %u", pv1, pv2, pv3, pv4);
|
||
s.replace(pValStart, pValEnd - pValStart, szNew);
|
||
}
|
||
}
|
||
}
|
||
// 更新 FileVersion 字符串值
|
||
{
|
||
const std::string key = "u'FileVersion', u'";
|
||
auto p = s.find(key);
|
||
if (p != std::string::npos) {
|
||
auto pValStart = p + key.size();
|
||
auto pValEnd = s.find('\'', pValStart);
|
||
if (pValEnd != std::string::npos)
|
||
s.replace(pValStart, pValEnd - pValStart, szFileVer);
|
||
}
|
||
}
|
||
// 更新 ProductVersion 字符串值
|
||
{
|
||
const std::string key = "u'ProductVersion', u'";
|
||
auto p = s.find(key);
|
||
if (p != std::string::npos) {
|
||
auto pValStart = p + key.size();
|
||
auto pValEnd = s.find('\'', pValStart);
|
||
if (pValEnd != std::string::npos)
|
||
s.replace(pValStart, pValEnd - pValStart, szProdVer);
|
||
}
|
||
}
|
||
|
||
if (!myFile.Open(lpPath, CFile::modeCreate | CFile::modeWrite, &fileEx)) return FALSE;
|
||
myFile.Write(s.c_str(), (UINT)s.size());
|
||
myFile.Close();
|
||
return TRUE;
|
||
}
|
||
|
||
int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
||
{
|
||
#ifdef _DEBUG
|
||
Sleep(15000);
|
||
#endif
|
||
// 解析 pid(内嵌在 argv[1] 中,如 "pyinstaller=5")
|
||
// "pyinstaller=" 为 12 个字符
|
||
UINT nPid = 0;
|
||
CString strPid = CString(argv[1]).Mid(12);
|
||
if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid))
|
||
{
|
||
_tprintf(_T("错误: pyinstaller= 后的 pid 无效:%s,应为 0-65535 范围的整数。\n"), strPid.GetString());
|
||
return 41;
|
||
}
|
||
|
||
LPCTSTR lpRepoPath = NULL;
|
||
CString strExtraArgs;
|
||
BOOL bTestMode = FALSE;
|
||
int nRepoArgRet = ParsePyinstallerOptions(argc, argv, lpRepoPath, strExtraArgs, bTestMode);
|
||
if (nRepoArgRet != 0)
|
||
{
|
||
return nRepoArgRet;
|
||
}
|
||
|
||
CString strProductVersion;
|
||
CString strFileVersion;
|
||
VersionBuildErrorCodes errorCodes = { 42, 43, 44 };
|
||
int nVersionRet = BuildVersionsFromRepo(
|
||
lpRepoPath,
|
||
nPid,
|
||
errorCodes,
|
||
strProductVersion,
|
||
strFileVersion,
|
||
DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER,
|
||
DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER);
|
||
|
||
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] 测试版本号: ProductVersion=%s\n"), strProductVersion.GetString());
|
||
}
|
||
|
||
// 检测是否为 spec 模式,若是则生成 version_info.txt 并注入/更新 spec
|
||
CString strFirstToken = ExtractFirstToken(strExtraArgs);
|
||
BOOL bIsSpec = (strFirstToken.GetLength() >= 5 && strFirstToken.Right(5).CompareNoCase(_T(".spec")) == 0);
|
||
if (bIsSpec)
|
||
{
|
||
// 解析 spec 文件完整路径
|
||
CString strSpecPath;
|
||
if (PathIsRelative(strFirstToken))
|
||
strSpecPath.Format(_T("%s\\%s"), lpRepoPath, strFirstToken.GetString());
|
||
else
|
||
strSpecPath = strFirstToken;
|
||
|
||
// 获取 spec 所在目录
|
||
TCHAR szSpecDir[MAX_PATH] = {};
|
||
_tcscpy_s(szSpecDir, strSpecPath.GetString());
|
||
PathRemoveFileSpec(szSpecDir);
|
||
|
||
// 检查 spec 是否已指定版本信息文件
|
||
CString strExistingVersionPath;
|
||
if (ReadVersionPathFromSpec(strSpecPath, strExistingVersionPath))
|
||
{
|
||
// spec 已有 version=,直接更新所指向的文件(不存在则创建)
|
||
CString strVersionInfoFullPath;
|
||
if (PathIsRelative(strExistingVersionPath))
|
||
strVersionInfoFullPath.Format(_T("%s\\%s"), szSpecDir, strExistingVersionPath.GetString());
|
||
else
|
||
strVersionInfoFullPath = strExistingVersionPath;
|
||
|
||
if (!UpdateVersionInfoFile(strVersionInfoFullPath, strProductVersion, strFileVersion))
|
||
{
|
||
_tprintf(_T("错误: 无法更新版本信息文件: %s。\n"), strVersionInfoFullPath.GetString());
|
||
return 45;
|
||
}
|
||
_tprintf(_T("版本信息文件已更新: %s\n"), strVersionInfoFullPath.GetString());
|
||
}
|
||
else
|
||
{
|
||
// spec 未指定 version=,生成 version_info.txt 并注入 spec
|
||
CString strVersionInfoPath;
|
||
if (!WriteVersionInfoFile(szSpecDir, strProductVersion, strFileVersion, strVersionInfoPath))
|
||
{
|
||
_tprintf(_T("错误: 无法生成 version_info.txt(目录: %s)。\n"), szSpecDir);
|
||
return 45;
|
||
}
|
||
_tprintf(_T("版本信息文件已生成: %s\n"), strVersionInfoPath.GetString());
|
||
|
||
if (!InjectVersionIntoSpec(strSpecPath))
|
||
{
|
||
_tprintf(_T("错误: 无法修改 spec 文件: %s。\n"), strSpecPath.GetString());
|
||
return 46;
|
||
}
|
||
}
|
||
}
|
||
|
||
_tprintf(_T("PyInstaller 打包开始..\n"));
|
||
_tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString());
|
||
_tprintf(_T("FileVersion=%s\n"), strFileVersion.GetString());
|
||
|
||
CString strCmd;
|
||
strCmd.Format(_T("cmd /c python -m PyInstaller %s"),strExtraArgs.GetString());
|
||
|
||
CString strBuildResult = StartProcess(NULL, strCmd.GetBuffer(), lpRepoPath);
|
||
strCmd.ReleaseBuffer();
|
||
|
||
if (strBuildResult.IsEmpty())
|
||
{
|
||
_tprintf(_T("错误: PyInstaller 打包失败。\n"));
|
||
}
|
||
|
||
return 0;
|
||
}
|