Todo: 集成多平台 解决因SaiNiu线程抢占资源问题 本地提交测试环境打包 和 正式打包脚本与正式环境打包bat 提交Python32环境包 改进多日志文件生成情况修改打包日志细节

This commit is contained in:
2025-09-18 15:52:03 +08:00
parent 8b9fc925fa
commit 7cfc0c22b7
7608 changed files with 2424791 additions and 25 deletions

View File

@@ -0,0 +1,97 @@
# BrandProject.py
#
# Brand a VSS project with a "build number", then optionally
# stamp DLL/EXE files with version information.
import getopt
import os
import sys
import bulkstamp
import vssutil
import win32api
def BrandProject(
vssProjectName,
descFile,
stampPath,
filesToSubstitute,
buildDesc=None,
auto=0,
bRebrand=0,
):
# vssProjectName -- The name of the VSS project to brand.
# descFile -- A test file containing descriptions of the files in the release.
# stampPath -- The full path to where the files referenced in descFile can be found.
path = win32api.GetFullPathName(stampPath)
build = vssutil.MakeNewBuildNo(vssProjectName, buildDesc, auto, bRebrand)
if build is None:
print("Cancelled")
return
bulkstamp.scan(build, stampPath, descFile)
for infile, outfile in filesToSubstitute:
vssutil.SubstituteVSSInFile(vssProjectName, infile, outfile)
return 1
def usage(msg):
print(msg)
print(
f"""\
{os.path.basename(sys.argv[0])} Usage:
{os.path.basename(sys.argv[0])} [options] vssProject descFile stampPath
Automatically brand a VSS project with an automatically incremented
build number, and stamp DLL/EXE files with the build number.
Checks that no files are checked out in the project, and finds the last
build number, and suggests the next number.
Options:
-a - Auto increment the build number, and brand (otherwise prompt
for the build number after looking for the previous)
-r - Restamp the files with the existing build number.
-d - A description for the VSS Label.
-f infile=outfile - Substitute special VSS labels in the specified text
file with the text extracted from VSS.
"""
)
sys.exit(1)
if __name__ == "__main__":
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "af:d:r")
except getopt.GetoptError as msg:
usage(msg)
bAuto = bRebrand = 0
stampFiles = []
desc = None
for opt, val in opts:
if opt == "-a":
bAuto = 1
if opt == "-f":
infile, outfile = val.split("=", 2)
stampFiles.append((infile, outfile))
if opt == "-d":
desc = val
if opt == "-r":
bRebrand = 1
if len(args) < 3:
usage("You must specify the required arguments")
vssProjectName = "$\\" + args[0]
descFile = args[1]
path = args[2]
try:
os.stat(descFile)
except OSError:
usage("The description file '%s' can not be found" % (descFile))
if not os.path.isdir(path):
usage("The path to the files to stamp '%s' does not exist" % (path))
BrandProject(vssProjectName, descFile, path, stampFiles, desc, bAuto, bRebrand)

View File

@@ -0,0 +1,156 @@
#
# bulkstamp.py:
# Stamp versions on all files that can be found in a given tree.
#
# USAGE: python bulkstamp.py <version> <root directory> <descriptions>
#
# Example: python bulkstamp.py 103 ..\win32\Build\ desc.txt
#
# <version> corresponds to the build number. It will be concatenated with
# the major and minor version numbers found in the description file.
#
# Description information is pulled from an input text file with lines of
# the form:
#
# <basename> <white space> <description>
#
# For example:
#
# PyWinTypes.dll Common types for Python on Win32
# etc
#
# The product's name, major, and minor versions are specified as:
#
# name <white space> <value>
# major <white space> <value>
# minor <white space> <value>
#
# The tags are case-sensitive.
#
# Any line beginning with "#" will be ignored. Empty lines are okay.
#
import fnmatch
import os
import sys
from collections.abc import Mapping
from optparse import Values
try:
import win32verstamp
except ModuleNotFoundError:
# If run with pywin32 not already installed
sys.path.append(os.path.abspath(__file__ + "/../../../Lib"))
import win32verstamp
g_patterns = [
"*.dll",
"*.pyd",
"*.exe",
"*.ocx",
]
def walk(vars: Mapping[str, str], debug, descriptions, dirname, names) -> int:
"""Returns the number of stamped files."""
numStamped = 0
for name in names:
for pat in g_patterns:
if fnmatch.fnmatch(name, pat):
# Handle the "_d" thing.
pathname = os.path.join(dirname, name)
base, ext = os.path.splitext(name)
if base.endswith("_d"):
name = base[:-2] + ext
is_dll = ext.lower() != ".exe"
if os.path.normcase(name) in descriptions:
description = descriptions[os.path.normcase(name)]
try:
options = Values(
{**vars, "description": description, "dll": is_dll}
)
win32verstamp.stamp(pathname, options)
numStamped += 1
except OSError as exc:
print(
"Could not stamp",
pathname,
"Error",
exc.winerror,
"-",
exc.strerror,
)
else:
print("WARNING: description not provided for:", name)
# skip branding this - assume already branded or handled elsewhere
return numStamped
# print("Stamped", pathname)
def load_descriptions(fname, vars):
retvars: dict[str, str] = {}
descriptions = {}
lines = open(fname, "r").readlines()
for i in range(len(lines)):
line = lines[i].strip()
if line != "" and line[0] != "#":
idx1 = line.find(" ")
idx2 = line.find("\t")
if idx1 == -1 or idx2 < idx1:
idx1 = idx2
if idx1 == -1:
print("ERROR: bad syntax in description file at line %d." % (i + 1))
sys.exit(1)
key = line[:idx1]
val = line[idx1:].strip()
if key in vars:
retvars[key] = val
else:
descriptions[key] = val
if "product" not in retvars:
print("ERROR: description file is missing the product name.")
sys.exit(1)
if "major" not in retvars:
print("ERROR: description file is missing the major version number.")
sys.exit(1)
if "minor" not in retvars:
print("ERROR: description file is missing the minor version number.")
sys.exit(1)
return retvars, descriptions
def scan(build, root: str, desc, **custom_vars):
try:
build = int(build)
except ValueError:
print("ERROR: build number is not a number: %s" % build)
sys.exit(1)
debug = 0 ### maybe fix this one day
varList = ["major", "minor", "sub", "company", "copyright", "trademarks", "product"]
vars, descriptions = load_descriptions(desc, varList)
vars["build"] = build
vars.update(custom_vars)
numStamped = 0
for directory, dirnames, filenames in os.walk(root):
numStamped += walk(vars, debug, descriptions, directory, filenames)
print(f"Stamped {numStamped} files.")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("ERROR: incorrect invocation. See script's header comments.")
sys.exit(1)
scan(*sys.argv[1:])

View File

@@ -0,0 +1,201 @@
import time
import traceback
import pythoncom
import win32com.client
import win32com.client.gencache
import win32con
constants = win32com.client.constants
win32com.client.gencache.EnsureModule("{783CD4E0-9D54-11CF-B8EE-00608CC9A71F}", 0, 5, 0)
def GetSS():
ss = win32com.client.Dispatch("SourceSafe")
# SS seems a bit weird. It defaults the arguments as empty strings, but
# then complains when they are used - so we pass "Missing"
ss.Open(pythoncom.Missing, pythoncom.Missing, pythoncom.Missing)
return ss
def test(projectName):
ss = GetSS()
project = ss.VSSItem(projectName)
for item in project.GetVersions(constants.VSSFLAG_RECURSYES):
print(item.VSSItem.Name, item.VersionNumber, item.Action)
# item=i.Versions[0].VSSItem
# for h in i.Versions:
# print("h.Comment", h.Action, h.VSSItem.Name)
def SubstituteInString(inString, evalEnv):
substChar = "$"
fields = inString.split(substChar)
newFields = []
for i in range(len(fields)):
didSubst = 0
strVal = fields[i]
if i % 2 != 0:
try:
strVal = eval(strVal, evalEnv[0], evalEnv[1])
newFields.append(strVal)
didSubst = 1
except:
traceback.print_exc()
print("Could not substitute", strVal)
if not didSubst:
newFields.append(strVal)
return "".join(map(str, newFields))
def SubstituteInFile(inName, outName, evalEnv):
inFile = open(inName, "r")
try:
outFile = open(outName, "w")
try:
while 1:
line = inFile.read()
if not line:
break
outFile.write(SubstituteInString(line, evalEnv))
finally:
outFile.close()
finally:
inFile.close()
def VssLog(project, linePrefix="", noLabels=5, maxItems=150):
lines = []
num = 0
labelNum = 0
for i in project.GetVersions(constants.VSSFLAG_RECURSYES):
num += 1
if num > maxItems:
break
commentDesc = itemDesc = ""
if i.Action[:5] == "Added":
continue
if len(i.Label):
labelNum += 1
itemDesc = i.Action
else:
itemDesc = i.VSSItem.Name
if str(itemDesc[-4:]) == ".dsp":
continue
if i.Comment:
commentDesc = f"\n{linePrefix}\t{i.Comment}"
lines.append(
"{}{}\t{}{}".format(
linePrefix,
time.asctime(time.localtime(int(i.Date))),
itemDesc,
commentDesc,
)
)
if labelNum > noLabels:
break
return "\n".join(lines)
def SubstituteVSSInFile(projectName, inName, outName):
import win32api
if win32api.GetFullPathName(inName) == win32api.GetFullPathName(outName):
raise RuntimeError("The input and output filenames can not be the same")
sourceSafe = GetSS()
project = sourceSafe.VSSItem(projectName)
# Find the last label
label = None
for version in project.Versions:
if version.Label:
break
else:
print("Couldn't find a label in the sourcesafe project!")
return
# Setup some local helpers for the conversion strings.
vss_label = version.Label
vss_date = time.asctime(time.localtime(int(version.Date)))
now = time.asctime(time.localtime(time.time()))
SubstituteInFile(inName, outName, (locals(), globals()))
def CountCheckouts(item):
num = 0
if item.Type == constants.VSSITEM_PROJECT:
for sub in item.Items:
num += CountCheckouts(sub)
else:
if item.IsCheckedOut:
num += 1
return num
def GetLastBuildNo(project):
i = GetSS().VSSItem(project)
# Find the last label
lab = None
for version in i.Versions:
lab = str(version.Label)
if lab:
return lab
return None
def MakeNewBuildNo(project, buildDesc=None, auto=0, bRebrand=0):
if buildDesc is None:
buildDesc = "Created by Python"
ss = GetSS()
i = ss.VSSItem(project)
num = CountCheckouts(i)
if num > 0:
msg = (
"This project has %d items checked out\r\n\r\nDo you still want to continue?"
% num
)
import win32ui
if win32ui.MessageBox(msg, project, win32con.MB_YESNO) != win32con.IDYES:
return
oldBuild = buildNo = GetLastBuildNo(project)
if buildNo is None:
buildNo = "1"
oldBuild = "<None>"
else:
try:
buildNo = int(buildNo)
if not bRebrand:
buildNo += 1
buildNo = str(buildNo)
except ValueError as error:
raise ValueError(
f"The previous label could not be incremented: {oldBuild}"
) from error
if not auto:
from pywin.mfc import dialog
buildNo = dialog.GetSimpleInput(
"Enter new build number", buildNo, f"{project} - Prev: {oldBuild}"
)
if buildNo is None:
return
i.Label(buildNo, f"Build {buildNo}: {buildDesc}")
if auto:
print(f"Branded project {project} with label {buildNo}")
return buildNo
if __name__ == "__main__":
# UpdateWiseExeName("PyWiseTest.wse", "PyWiseTest-10.exe")
# MakeVersion()
# test(tp)
# MakeNewBuildNo(tp)
tp = "\\Python\\Python Win32 Extensions"
SubstituteVSSInFile(
tp, "d:\\src\\pythonex\\win32\\win32.txt", "d:\\temp\\win32.txt"
)