async def simple_download(url): err = None for i in range(3): try: r = requests.get(url) with open(str(pathlib("./dist", "libs", pathlib(url).name)), "wb") as code: code.write(r.content) return except Exception as e: print("重试下载:"+url) err = e raise Exception(f"重试3次,无法下载{url}, 最后一次失败原因:{err}")
async def simple_download(url): err = None for i in range(3): try: r = requests.get(url, timeout=(5, 30)) with open(str(dist_pl.joinpath("libs", pathlib(url).name)), "wb") as code: code.write(r.content) return except Exception as e: print(f"重试下载({i+1}):{url}。遇到错误{e}") err = e raise Exception(f"重试3次,无法下载{url}, 最后一次失败原因:{err}")
async def run(): del_file(str(dist_pl.resolve())) console = None tasks = [] try: """ 构造一个用于发送命令和接收返回的嵌套事件协程,目标是在一个虚拟环境中执行pip install,并且搜集Downlaoding和Using cached的结果 """ xwin = "cmd" if is_win() else "/bin/bash" console = subprocess.Popen(xwin, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # # 定义搜集器 __default_collector = lambda res: print(f"get [resp]: {res.strip()}") class __error_collector: err = [] error_comming = False error_end = True def collect(self, resp): strip = resp.strip() if strip.lower().find("invalid") >= 0 or strip.lower().find( "error") >= 0: print(f"get [error]: {strip}") self.err.append(resp) else: # 收到异常信息 if strip.startswith("Traceback"): self.error_comming = True # 如果没有异常信息,直接结束 if not self.error_comming: return print(f"get [error]: {strip}") # 当error_comming开关打开后,采集异常 self.err.append(resp) # 采集结束,设置comming为false if not resp.startswith(" "): self.err.append(resp.strip()) # 最后一行一般是ERROR信息 self.error_comming = False # 定义处理方法 async def process_command(cmd_list): for i in range(len(cmd_list)): cmd, command_over_signal, info_collecotr = cmd_list[i][ "cmd"], cmd_list[i]["confirm"], cmd_list[i].get( "info_collectors") console.stdin.write( (cmd + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() # 发送特殊的echo,目的是给一个“结束”信号 console.stdin.write((f"echo {command_over_signal}" + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() while True: resp = await loop.run_in_executor(None, console.stdout.readline) try: resp = resp.decode("UTF-8") except UnicodeDecodeError: resp = resp.decode("GBK") [collect(resp) for collect in info_collecotr] if resp.strip() == command_over_signal: # 说明上一个命令已经发送,并且执行成功 break # region: 打包 print("执行打包....") commands = [ # 执行setup.py { "cmd": f"cd {work_space}", "confirm": "___cd_workspace_over", "info_collectors": [__default_collector] }, { "cmd": f"{py} setup.py bdist_wheel", "confirm": "___setup_bdist_over", "info_collectors": [__default_collector] } ] task = asyncio.ensure_future(process_command(commands)) tasks.append(task) await asyncio.wait_for(task, timeout=None) print("执行打包完成.") # endregion # region: 复制requirements.txt print("复制requirements.txt到dist目录....") temp_requirements_txt = str( dist_pl.joinpath("temp_requirements.txt").resolve()) with open(temp_requirements_txt, "w+") as output: with open(str(work_pl.joinpath("./requirements.txt").resolve()), "r") as read: for line in read.readlines(): output.write(line) print("复制requirements.txt到打包目录完成.") # endregion # region: 构建虚拟环境 print("virtualenv..") out, err = await exec_shell([ py, "-m", "virtualenv", str(dist_pl.joinpath("temp_env").resolve()) ]) if err: raise Exception("执行构建虚拟环境错误", err) print("virtualenv....ok") # endregion # region: 进入虚拟环境,并安装twine task = asyncio.ensure_future(process_command([ # 打开venv {"cmd": str(dist_pl.joinpath('temp_env', "Scripts", "activate").resolve()) if is_win() \ else f"source {str(dist_pl.joinpath('temp_env', 'bin', 'activate').resolve())}", "confirm": "___open_venv_over", "info_collectors": [__default_collector]} ])) tasks.append(task) await asyncio.wait_for(task, timeout=None) error_collector = __error_collector() # 安装twine task = asyncio.ensure_future( process_command([ # 执行pip install twine { "cmd": f"python -m pip install -i {pip_source} twine", "confirm": "___install_twine_over", "info_collectors": [__default_collector] }, ])) tasks.append(task) await asyncio.wait_for(task, timeout=None) if len(error_collector.err) > 0: raise Exception(f"虚拟环境安装twine出现异常:{error_collector.err}") # 检查twine twineok = [] __checktwine_collector = lambda resp: twineok.append( resp) if resp.strip().startswith("twine") else None task = asyncio.ensure_future( process_command([ # 执行pip install twine { "cmd": f"python -m pip list", "confirm": "___pip_list_twine_over", "info_collectors": [__default_collector, __checktwine_collector] }, ])) tasks.append(task) await asyncio.wait_for(task, timeout=None) if len(twineok) == 0: raise Exception(f"虚拟环境没有正确安装twine,请检查控制台输出") # endregion # region: 执行python -m pip wheel -r requirements.txt -w ./dist/libs -b ./dist/libs_build error_collector = __error_collector() task = asyncio.ensure_future( process_command([ { "cmd": f"python -m pip wheel -r {temp_requirements_txt} -i {pip_source} -w {libs_dir} -b {libs_build_dir}", "confirm": "___pip_wheel_over", "info_collectors": [__default_collector, error_collector.collect] }, ])) tasks.append(task) await asyncio.wait_for(task, timeout=None) if len(error_collector.err) > 0: raise Exception(f"虚拟环境执行pip wheel出现异常:{error_collector.err}") # endregion # 把下载好的依赖和打包目标整理好 wheels = [ str(dist_pl.joinpath(whl).resolve()) for whl in os.listdir(str(dist_pl.resolve())) if whl.endswith(".whl") ] wheels.extend([ str(pathlib(libs_dir, whl).resolve()) for whl in os.listdir(libs_dir) if whl.endswith(".whl") ]) # 删除builds_lib del_file(libs_build_dir) # region 生成命令,twine upload access = "" if nexus_user and nexus_pwd: access = f"-u {nexus_user} -p {nexus_pwd}" if gen_file: with open(str(dist_pl.joinpath("upload.sh").resolve()), "a+") as code: # 把下载好的依赖加入上传列表 for whl in wheels: cmd = f"python -m twine upload --repository-url {nexus} {access} {whl}" code.write(cmd + "\n") else: # 目前直接覆盖上传,按道理,应该查询一下,然后再上传 print("上传到nexus....") for whl in wheels: for i in range(2): try: # 把任务启动起来 error_collector = __error_collector() task = asyncio.ensure_future( process_command([ { "cmd": f"python -m twine upload --repository-url {nexus} {access} {whl} --disable-progress-bar", "confirm": "___twine_upload_over", "info_collectors": [ __default_collector, error_collector.collect ] }, ])) tasks.append(task) await asyncio.wait_for(task, timeout=None) if len(error_collector.err) > 0: raise Exception( f"虚拟环境执行twine upload出现异常:{error_collector.err}" ) break except Exception as e: if i < 1: print(f"重试上传({i+1}):{whl}。 遇到错误:{e}") continue err = e raise Exception(f"重试2次,无法上传{whl}到{nexus}, 最后一次失败原因:{err}") print("上传到nexus完成.") # endregion except Exception as e: print("出现错误:", e) print(traceback.format_exc()) finally: import signal try: for task in tasks: try: console.send_signal( signal.CTRL_C_EVENT if is_win() else signal.SIGKILL) except Exception as e: print(f"[WARING]关闭虚拟控制台遇到问题,{e}") # while not task.cancelled() and not task.done(): # print(f"task.cancelled {task.cancelled()}, task.done {task.done()}") task.cancel() try: await task except asyncio.CancelledError: print(f"{task} is cancelled now") except Exception as e: print(f"[WARING]停止task遇到问题,{e}") try: print("关闭虚拟控制台....") console.kill() os.kill(console.pid, 9 if is_win() else signal.SIGKILL) os.killpg(os.getpgid(console.pid), 9 if is_win() else signal.SIGKILL) except Exception as e: pass loop.stop()
if arg == "-w": work_space = val if arg == "-f": gen_file = True if arg == "--python-bin": if not os.path.exists(val): raise Exception(f"{val} 不存在") py = val if arg == "--upload-timeout": upload_timeout = int(val) if not work_space: raise Exception(f"-w [workspace] must specified") if not os.path.exists(work_space): raise Exception(f"指定的项目{work_space} 不存在") work_pl = pathlib(work_space) dist_pl = work_pl.joinpath("dist") # setup.py的目标目录 if not os.path.exists(str(work_pl.joinpath("setup.py").resolve())): raise Exception(f"项目{arg} 中没有setup.py") libs_dir = str(dist_pl.joinpath('libs').resolve()) libs_build_dir = str(dist_pl.joinpath('libs_build').resolve()) if nexus is None: raise Exception("-t [nexus url] must specified") loop = asyncio.get_event_loop() try: loop.run_until_complete(run()) loop.close() except Exception as e: print(f"[CATCHING INFO]{e}")
async def run(): maven_repo = None nexus = None nexus_user = None nexus_pwd = None maven_home = None java_home = None pom_path = None mvn_setting = None mvn_local_repository = None keep_result = True opts, args = getopt.getopt(sys.argv[1:], "i:t:m:j:u:p:s:k:", ["source=", "nexus=","maven-home=","java-home=", "pom-path=", "username="******"password="******"mvn-settings=", "mvn-local-repository=", "keep="]) for arg, val in opts: if arg in ("-i","--source"): maven_repo = val if arg in ("-t", "--nexus"): nexus = val if arg in ("-u", "--username"): nexus_user = val if arg in ("-p", "--password"): nexus_pwd = val if arg in ("-m", "--maven-home"): maven_home = val if arg in ("-j", "--java-home"): java_home = val if arg in ("-s", "--pom-path"): pom_path = val if arg=="--mvn-settings": mvn_setting = val if arg=="--mvn-local-repository": mvn_local_repository = val if arg in ("-k","--keep"): keep_result = val=="True" if pom_path is None or nexus is None: raise Exception("-s [maven module's pom path], -t [nexus url] must specify") if pathlib(pom_path).name.find(".xml")<0: raise Exception("-s [maven module's pom path] must a full '.xml' path") if not os.path.exists(pom_path): raise Exception(f"{pom_path} not exist") if nexus_user and nexus_pwd: username = "******" password = "******" from urllib import parse result = parse.urlparse(nexus) nexus = f"{result.scheme}://{username}:{password}@{result.netloc}{result.path}" nexus_poms = {} try: # 创建工作目录 work_dir = str(pathlib(pom_path, "../nexus_out", "target").resolve()) if os.path.exists(work_dir): await del_file(work_dir) else: os.makedirs(work_dir, exist_ok=True) # 检查maven、java java = str(pathlib(java_home, "java").resolve()) if java_home else "java" out, err = await exec_shell(f"{java} -version") if err and err.find("java version")<0: raise Exception(f"{java} is not a valid java") mvn = str(pathlib(maven_home, "mvn").resolve()) if maven_home else "mvn" out, err = await exec_shell(f"{mvn} -version") if err or out.find("Maven home:")<0: raise Exception(f"{mvn} is not a valid mvn") maven_home = out[out.find("Maven home:")+len("Maven home:"):out.find("\n", out.find("Maven home:"))].strip() maven_home = str(pathlib(maven_home).resolve()) if not mvn_setting: mvn_setting = str(pathlib(maven_home, 'conf', 'settings.xml').resolve()) if mvn_local_repository: mvn_local_repository = f"-Dmaven.repo.local={mvn_local_repository} " # 复制和处理pom print("在目标目录构建nexus_pom....") nexus_poms = process_source_pom(pom_path, repo=maven_repo, work_dir=work_dir) print("在目标目录构建nexus_pom完成.") print(nexus_poms) # 开始执行maven的动作 mvn = f"{java} -Dmaven.multiModuleProjectDirectory={str(pathlib(pom_path, '../').resolve())} " \ "-DarchetypeCatalog=internal -Dmaven.multiModuleProjectDirectory=$M2_HOME " \ f"-Dmaven.home={maven_home} -Dclassworlds.conf={str(pathlib(maven_home, 'bin', 'm2.conf').resolve())} " \ f"-Dfile.encoding=UTF-8 -classpath {str(pathlib(maven_home, 'boot', 'plexus-classworlds-2.5.2.jar').resolve())} " \ f"org.codehaus.classworlds.Launcher --errors -s {mvn_setting} " \ f"{mvn_local_repository} -DskipTests=true -f {nexus_poms.get(pom_path)} " mvn_package = f"{mvn} package dependency:copy-dependencies" mvn_clean = f"{mvn} clean dependency:list" # clean的时候,顺便搜集依赖jar的信息 # region: 执行maven print("开打虚拟控制台....") xwin = "cmd" if is_win() else "gnome-terminal -e '/bin/bash'" console = subprocess.Popen(xwin, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print("开打虚拟控制台完成.") # endregion """ 构造一个用于发送命令和接收返回的嵌套事件协程,目标是在一个虚拟环境中执行pip install,并且搜集Downlaoding和Using cached的结果 """ # 定义搜集器 __default_collector = lambda res: print(f"get resp: {res}") # 定义处理方法 async def process_command(cmd_list): for i in range(len(cmd_list)): cmd, command_over_signal, info_collecotr = cmd_list[i]["cmd"], cmd_list[i]["confirm"], cmd_list[i].get("info_collectors") console.stdin.write((cmd + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() print(f"{cmd} 已发送") # 发送特殊的echo,目的是给一个“结束”信号 console.stdin.write((f"echo {command_over_signal}" + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() while True: resp = console.stdout.readline() resp = resp.decode("GBK") [collect(resp) for collect in info_collecotr] if resp.strip() == command_over_signal: # 说明上一个命令已经发送,并且执行成功 break # region: 使用process_command执行构造好的mvn命令 print("执行mvn命令....") dependencies = [] m = re.compile(r".*:.*:jar:.*:compile", re.I) def __artifactlist_collector__(res): res = res.replace("[INFO]", "").strip() if m.match(res) and res not in dependencies: dependencies.append(res) commands = [ {"cmd": mvn_package, "confirm": "___mvn_package_over", "info_collectors": [__default_collector]}, {"cmd": mvn_clean, "confirm": "___mvn_clean_over", "info_collectors": [__default_collector, __artifactlist_collector__]} ] # 把任务启动起来 tasks = [asyncio.ensure_future(process_command(commands))] fetures, pendings = await asyncio.wait(tasks) for task in fetures: # 执行迭代,让任务在主事件循环中处理完 pass print("执行mvn命令打包完成.") # endregion # region: 为dependencies构造mvn deploy命令,同时,把target也包含进来 # 由于前面采用maven-jar-plugin输出了pom.properties到builds目录,因此这里就可以使用 mvn_deploys = [] pl = pathlib(work_dir) files = os.listdir(str(pl.joinpath("builds").resolve())) for file in files: if file.find(".properties")>0: version, groupId, artifactId = None, None, None with open(str(pl.joinpath("builds", file).resolve()), "r") as prop: line = prop.readline() while line: if line.find("version=")>0: version = line.replace("version=","") if line.find("groupId=")>0: groupId = line.replace("groupId=","") if line.find("artifactId=")>0: artifactId = line.replace("artifactId=","") line = prop.readline() if version and groupId and artifactId: mvn_deploys.append(f"mvn deploy:deploy-file -DgroupId={groupId} " f"-DartifactId={artifactId} -Dversion={version} " f"-DgeneratePom=true -Dpackaging=jar " f"-Durl={nexus} " f"-Dfile={str(pl.joinpath(artifactId+'-'+version+'.jar'))}") for item in dependencies: item = item.split(":") # org.springframework:spring-aop:jar:4.2.0.RELEASE:compile version, groupId, artifactId = item[3],item[0],item[1] command = (f"mvn deploy:deploy-file -DgroupId={groupId} " f"-DartifactId={artifactId} -Dversion={version} " f"-DgeneratePom=true -Dpackaging=jar " f"-Durl={nexus} " f"-Dfile={str(pl.joinpath('dependencies', artifactId+'-'+version+'.jar'))}") if command not in mvn_deploys: mvn_deploys.append(command) # endregion # region 重新进入虚拟环境,在虚拟环境中执行mvn deploy # 目前直接覆盖上传,按道理,应该查询一下,然后再上传 print("上传到nexus....") for mvn_deploy in mvn_deploys: out, err = await exec_shell(mvn_deploy) if err: raise Exception(err) print("上传到nexus完成.") # endregion except Exception as e: import traceback print("出现错误:", e) print(traceback.format_exc()) finally: if not keep_result: for key in nexus_poms: try:os.remove(nexus_poms.get(key)) except:pass await del_file(work_dir) print("所有处理完成.")
def process_module(pom, parent_pom=None): tree = ET.parse(pom) root = tree.getroot() # 针对传入的pom处理几个东西: # 1、判断package类型,如果是jar,则直接处理。如果是pom,则处理其module pkg_el = root.find(".//default:packaging", namespaces=namespaces) if not pkg_el or pkg_el.text=="pom" or pkg_el.text=="jar": cur_pom_modules = root.find(".//default:modules", namespaces=namespaces) if cur_pom_modules: for module_el in cur_pom_modules: # 这里的意思是——如果module写的是pom的路径,则直接使用。如果写的是模块名(目录),则加上pom.xml。 # 由于maven pom重module一般都是相对路径,因此这里通过pathlib可以很方便的就得到了全路径 module_pom = str(pathlib(module_el.text, "" if module_el.text.find(".xml")>0 else "pom.xml").resolve()) # 从当前pom所在的路径(pom/../)作为基准,找到module_pom的真实路径,处理module_pom process_module(str(pathlib(pom, "../", module_pom).resolve()), parent_pom=pom) # 将当前pom的module,修改为后面拷贝出来的nexus_pom的相对路径 module_el.text = module_pom.replace("pom.xml", "nexus_pom.xml") if parent_pom: # 设置每一个module_pom的parent到当前pom(最原始的除外) parent_el = root.find("./default:parent", namespaces=namespaces) if parent_el is not None: relativePath_el = parent_el.find("./default:relativePath", namespaces=namespaces) if relativePath_el is None: relativePath_el = ET.SubElement(parent_el, "relativePath") # 获取父pom.xml相对于当前pom所在目录的相对目录(在mvn的pom中,realativePath是相对于pom所在的目录,而不是pom.xml本身的) relativePath_el.text = os.path.relpath(parent_pom, str(pathlib(pom).parent.resolve())) else: raise Exception(f"无法处理{pom}的packaging类型:{pkg_el.text}") # 修改每一个pom的plugin、repositories build_el = root.find("./default:build", namespaces=namespaces) if build_el is None: build_el=ET.SubElement(root, "build") plugins_el = build_el.find("./default:plugins", namespaces=namespaces) if plugins_el is None: plugins_el=ET.SubElement(build_el, "plugins") # 2.1.构建maven-jar-plugin plugin_el = plugins_el.find("./default:plugin/[default:artifactId='maven-jar-plugin']", namespaces=namespaces) if plugin_el is None: plugin_el = ET.SubElement(plugins_el, "plugin") ET.SubElement(plugin_el, "artifactId").text = "maven-jar-plugin" configuration_el = plugin_el.find("./default:configuration", namespaces=namespaces) if configuration_el is None: configuration_el = ET.SubElement(plugin_el, "configuration") outputDirectory_el = configuration_el.find("./default:outputDirectory", namespaces=namespaces) if outputDirectory_el is None: outputDirectory_el = ET.SubElement(configuration_el, "outputDirectory") # 设置jar的output目录为work_dir outputDirectory_el.text = str(pathlib(work_dir, "builds").resolve()) archive_el = configuration_el.find("./default:archive", namespaces=namespaces) # 设置pom.properties的输出位置,便于后面使用 if archive_el is None: archive_el = ET.SubElement(configuration_el, "archive") pomPropertiesFile_el = archive_el.find("./default:pomPropertiesFile", namespaces=namespaces) if pomPropertiesFile_el is None: pomPropertiesFile_el = ET.SubElement(archive_el, "pomPropertiesFile") artifactId = root.find("./default:artifactId", namespaces=namespaces).text pomPropertiesFile_el.text = str(pathlib(work_dir, "builds", artifactId+".pom.properties").resolve()) # 2.2.构建maven-dependency-plugin plugin_el = plugins_el.find("./default:plugin/[default:artifactId='maven-dependency-plugin']", namespaces=namespaces) if plugin_el is None: plugin_el = ET.SubElement(plugins_el, "plugin") ET.SubElement(plugin_el, "artifactId").text = "maven-dependency-plugin" version_el = plugin_el.find("./default:version", namespaces=namespaces) if version_el is None: version_el = ET.SubElement(plugin_el, "version") version_el.text = "2.9" configuration_el = plugin_el.find("./default:configuration", namespaces=namespaces) if configuration_el is None: configuration_el = ET.SubElement(plugin_el, "configuration") outputDirectory_el = configuration_el.find("./default:outputDirectory", namespaces=namespaces) if outputDirectory_el is None: outputDirectory_el = ET.SubElement(configuration_el, "outputDirectory") # 设置jar的output目录为work_dir outputDirectory_el.text = str(pathlib(work_dir, "dependencies").resolve()) # 2.3.构建repositories if repo: repositories_el = root.find("./default:repositories", namespaces=namespaces) if repositories_el is None: repositories_el=ET.SubElement(root, "repositories") repository_el = repositories_el.find(f"./default:repository/[default:url='{repo}']", namespaces=namespaces) if repository_el is None: repository_el = ET.SubElement(repositories_el, "repository") ET.SubElement(repository_el, "id").text = "repo" ET.SubElement(repository_el, "name").text = "repo" ET.SubElement(repository_el, "layout").text = "default" ET.SubElement(repository_el, "url").text = repo # 3、将修改后的新pom输出到当前pom同级目录 [ET.register_namespace("" if key=="default" else key, namespaces.get(key)) for key in namespaces] nexus_pom = str(pathlib(pom, "../", "nexus_pom.xml").resolve()) tree.write(nexus_pom, encoding="utf-8") nexus_poms[pom] = nexus_pom
async def run(): print("[[[WARNING!!!!!]]]因为采用了virtualenv,所以不要使用IDE的运行按钮执行,否则将导致不可预料的问题!!!") pip_source = "https://pypi.tuna.tsinghua.edu.cn/simple" nexus = None keepwhl = True nexus_user = None nexus_pwd = None # 整体支持三个参数: pip源、nexus地址、是否保留打包好的内容 opts, args = getopt.getopt( sys.argv[1:], "i:t:k:u:p:", ["source=", "nexus=", "keep-whl=", "username="******"password="******"-i", "--source"): pip_source = val if arg in ("-t", "--nexus"): nexus = val if arg in ("-k", "--keep-whl"): keepwhl = val == "True" if arg in ("-u", "--username"): nexus_user = val if arg in ("-p", "--password"): nexus_pwd = val await del_file(str(pathlib("./dist").resolve())) try: # region: 打包 print("执行打包....") out, err = await exec_shell("python setup.py bdist_wheel") print(out) if err: raise Exception("执行打包出现错误", err) print("执行打包完成.") # endregion # region: 复制requirements.txt print("复制requirements.txt到打包目录....") temp_requirements_txt = str( pathlib("./dist", "temp_requirements.txt").resolve()) with open(temp_requirements_txt, "w+") as output: with open(str(pathlib("./requirements.txt").resolve()), "r") as read: for line in read.readlines(): output.write(line) print("复制requirements.txt到打包目录完成.") # endregion # region: 构建虚拟环境 print("构建虚拟环境并执行pip install....") print("virtualenv..") out, err = await exec_shell([ "python", "-m", "virtualenv", str(pathlib("./dist", "temp_env").resolve()) ]) if err: raise Exception("执行构建虚拟环境错误", err) print("virtualenv....ok") xwin = "cmd" if is_win() else "gnome-terminal -e '/bin/bash'" console = subprocess.Popen(xwin, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # endregion """ 构造一个用于发送命令和接收返回的嵌套事件协程,目标是在一个虚拟环境中执行pip install,并且搜集Downlaoding和Using cached的结果 """ # 定义搜集器 __default_collector = lambda res: print(f"get resp: {res}") # 定义处理方法 async def process_command(cmd_list): for i in range(len(cmd_list)): cmd, command_over_signal, info_collecotr = cmd_list[i][ "cmd"], cmd_list[i]["confirm"], cmd_list[i].get( "info_collectors") console.stdin.write( (cmd + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() print(f"{cmd} 已发送") # 发送特殊的echo,目的是给一个“结束”信号 console.stdin.write((f"echo {command_over_signal}" + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() while True: resp = console.stdout.readline() resp = resp.decode("GBK") [collect(resp) for collect in info_collecotr] if resp.strip() == command_over_signal: # 说明上一个命令已经发送,并且执行成功 break # region: 使用process_command在虚拟环境中执行pip """ 构造process_command任务的参数 """ wheels = [] # 用于缓存结果 # 定义搜集器 def __pip_collector_(res): res = res.strip() if res.find("Downloading") == 0: wheels.append(res.split(" ")[1]) if res.find("Using cached") == 0: wheels.append(res.split(" ")[2]) # 定义一组命令,以及命令返回的采集器 commands = [ # 打开venv {"cmd": str(pathlib('./dist', 'temp_env', "Scripts", "activate").resolve()) if is_win() \ else f"source {str(pathlib('./dist', 'temp_env', 'bin', 'activate').resolve())}", "confirm": "___onpen_venv_cover", "info_collectors": [__default_collector]}, # 执行pip install -r {"cmd": f"pip install -i {pip_source} -r {temp_requirements_txt}", "confirm": "___pip_install_over", "info_collectors": [__default_collector, __pip_collector_]} ] # 把任务启动起来 tasks = [asyncio.ensure_future(process_command(commands))] fetures, pendings = await asyncio.wait(tasks) for task in fetures: # 执行迭代,让任务在主事件循环中处理完 pass print("构建虚拟环境并执行pip install完成.") # endregion # region 执行一次下载,把所有的wheel下载到libs目录 # 经过上一步的pip处理,得到一个wheels的集合列表 if wheels: path = str(pathlib("./dist", "libs").resolve()) if not os.path.exists(path): os.mkdir(path) print("通过搜集到的whl列表进行下载....") tasks = [] [ tasks.append(asyncio.ensure_future(simple_download(whl))) for whl in wheels ] fetures, pendings = await asyncio.wait(tasks) for task in fetures: pass # 执行迭代,让任务在主事件循环中处理完 print("通过搜集到的whl列表进行下载完成.") # endregion # region 重新进入虚拟环境,在虚拟环境中执行twine upload # 上传到nexus,如果指定了nexus的话 if nexus: # 目前直接覆盖上传,按道理,应该查询一下,然后再上传 print("上传到nexus....") await exec_shell(f"python -m install -r {pip_source} twine") tasks = [] # 把下载好的依赖加入上传列表 for whl in wheels: target = str( pathlib("./dist", "libs", pathlib(whl).name).resolve()) tasks.append( asyncio.ensure_future( simple_twine2nexus(nexus, target, nexus_user, nexus_pwd))) # 把打包文件加入上传列表 tasks.append( asyncio.ensure_future( simple_twine2nexus( nexus, str(pathlib("./dist").resolve()) + os.path.sep + "*.whl", nexus_user, nexus_pwd))) fetures, pendings = await asyncio.wait(tasks) for task in fetures: pass # 执行迭代,让任务在主事件循环中处理完 print("上传到nexus完成.") # endregion except Exception as e: import traceback print("出现错误:", e) print(traceback.format_exc()) finally: # 清除env await del_file(str(pathlib("./dist", "temp_env").resolve())) if not keepwhl: print("清除dist....") await del_file(str(pathlib("./dist").resolve())) print("所有处理完成.")
def process_module(pom, parent_pom=None): print("processing " + pom) # 首先解析pom namespaces = dict( [node for _, node in ET.iterparse(pom, events=['start-ns'])]) namespaces = dict([(nskey if nskey else "default", namespaces.get(nskey)) for nskey in namespaces]) # 把默认命名空间命个名 tree = ET.parse(pom) root = tree.getroot() # 针对传入的pom处理几个东西: # 1、判断package类型,如果是jar,则直接处理。如果是pom,则处理其module skip_deploy = False # 用于指明maven-deploy-plugin是否设置了skip artifactId = "" # 用于引用pom的artifactid pkg_el = find_el(root, ".//default:packaging", "default", namespaces) if not pkg_el or pkg_el.text == "pom" or pkg_el.text == "jar": # 获取关键信息以及maven-deploy-plugin plugin_el = find_el( root, "./default:build/default:plugins/default:plugin/[default:artifactId='maven-deploy-plugin']", "default", namespaces) if plugin_el is not None: skip_el = find_el(plugin_el, "./default:configuration/default:skip", "default", namespaces) skip_deploy = skip_el is not None and skip_el.text == "true" artifactId = find_el(root, "./default:artifactId", "default", namespaces).text version_el = find_el(root, "./default:version", "default", namespaces) if version_el is None: version_el = find_el(root, "./default:parent/default:version", "default", namespaces) version = version_el.text if version.startswith("${"): version = properties_map.get( version.replace("${", "").replace("}", "")) groupId_el = find_el(root, "./default:groupId", "default", namespaces) if groupId_el is None: groupId_el = find_el(root, "./default:parent/default:groupId", "default", namespaces) groupId = groupId_el.text if parent_pom: # 设置每一个module_pom的parent到当前pom(最原始的除外) parent_el = find_el(root, "./default:parent", "default", namespaces) if parent_el is not None: relativePath_el = find_el(parent_el, "./default:relativePath", "default", namespaces) if relativePath_el is None: relativePath_el = ET.SubElement( parent_el, "relativePath") # 获取父pom.xml相对于当前pom所在目录的相对目录(在mvn的pom中,realativePath是相对于pom所在的目录,而不是pom.xml本身的) nexus_parent_pom = parent_pom.replace( "pom.xml", "nexus_pom.xml") relativePath_el.text = os.path.relpath( nexus_parent_pom, str(pathlib(pom).parent.resolve())) else: relativePath_el.text = relativePath_el.text.replace( "pom.xml", "nexus_pom.xml") else: # 获取最外层的properties properties_el = find_el(root, "./default:properties", "default", namespaces) if properties_el is not None: for child in properties_el: tag = child.tag if tag.startswith("{"): tag = tag[tag.index("}") + 1:len(tag)] properties_map[tag] = child.text # 在最外层构建插件。其他的都可以继承 build_el = find_el(root, "./default:build", "default", namespaces) if build_el is None: build_el = ET.SubElement(root, "build") plugins_el = find_el(build_el, "./default:plugins", "default", namespaces) if plugins_el is None: plugins_el = ET.SubElement(build_el, "plugins") # 2.1.构建maven-jar-plugin # plugin_el = find_el(plugins_el, "./default:plugin/[default:artifactId='maven-jar-plugin']", "default", namespaces) # if plugin_el is None: # plugin_el = ET.SubElement(plugins_el, "plugin") # ET.SubElement(plugin_el, "artifactId").text = "maven-jar-plugin" # configuration_el = find_el(plugin_el, "./default:configuration", "default", namespaces) # if configuration_el is None: configuration_el = ET.SubElement(plugin_el, "configuration") # outputDirectory_el = find_el(configuration_el, "./default:outputDirectory", "default", namespaces) # if outputDirectory_el is None: outputDirectory_el = ET.SubElement(configuration_el, "outputDirectory") # # 设置jar的output目录为work_dir # outputDirectory_el.text = str(pathlib(work_dir, "builds").resolve()) # archive_el = find_el(configuration_el, "./default:archive", "default", namespaces) # # 设置pom.properties的输出位置,便于后面使用 # if archive_el is None: archive_el = ET.SubElement(configuration_el, "archive") # pomPropertiesFile_el = find_el(archive_el, "./default:pomPropertiesFile", "default", namespaces) # if pomPropertiesFile_el is None: pomPropertiesFile_el = ET.SubElement(archive_el, "pomPropertiesFile") # addMavenDescriptor_el = find_el(archive_el, "./default:addMavenDescriptor", "default", namespaces) # if addMavenDescriptor_el is None: addMavenDescriptor_el = ET.SubElement(archive_el, "addMavenDescriptor") # addMavenDescriptor_el.text = 'true' # artifactid_el = find_el(root, "./default:artifactId", "default", namespaces) # if artifactid_el is None: # raise Exception(f"无法处理{pom},没有artifactId") # artifactId = artifactid_el.text # pomPropertiesFile_el.text = str(pathlib(work_dir, "builds", artifactId+".pom.properties").resolve()) # # 在mac上回出现maven-jar-plugin无法读取这个properties文件的异常,很奇怪,明明是创建,为什么会先读取??这里尝试主动先写一个 # os.makedirs(str(pathlib(work_dir, "builds").resolve()), exist_ok=True) # with open(pomPropertiesFile_el.text, "w"): # pass # 2.2.构建maven-resource-plugin用于拷贝pom plugin_el = find_el( plugins_el, "./default:plugin/[default:artifactId='maven-resources-plugin']", "default", namespaces) if plugin_el is None: plugin_el = ET.SubElement(plugins_el, "plugin") ET.SubElement(plugin_el, "artifactId").text = "maven-resources-plugin" executions_el = find_el(plugin_el, "./default:executions", "default", namespaces) if executions_el is None: executions_el = ET.SubElement(plugin_el, "executions") execution_el = ET.SubElement(executions_el, "execution") # 直接创建一个新的execution ET.SubElement(execution_el, "id").text = "copy-pom-nexus" ET.SubElement(execution_el, "phase").text = "package" ET.SubElement(ET.SubElement(execution_el, "goals"), "goal").text = "copy-resources" configuration_el = ET.SubElement(execution_el, "configuration") outputDirectory_el = ET.SubElement(configuration_el, "outputDirectory") outputDirectory_el.text = "${project.build.directory}" resources_el = ET.SubElement(configuration_el, "resources") resource_el = ET.SubElement(resources_el, "resource") directory_el = ET.SubElement(resource_el, "directory") directory_el.text = "${project.basedir}" includes_el = ET.SubElement(resource_el, "includes") include_el = ET.SubElement(includes_el, "include") include_el.text = "pom.xml" # 2.3.构建maven-dependency-plugin plugin_el = find_el( plugins_el, "./default:plugin/[default:artifactId='maven-dependency-plugin']", "default", namespaces) if plugin_el is None: plugin_el = ET.SubElement(plugins_el, "plugin") ET.SubElement( plugin_el, "artifactId").text = "maven-dependency-plugin" version_el = find_el(plugin_el, "./default:version", "default", namespaces) if version_el is None: version_el = ET.SubElement(plugin_el, "version") version_el.text = "2.9" configuration_el = find_el(plugin_el, "./default:configuration", "default", namespaces) if configuration_el is None: configuration_el = ET.SubElement(plugin_el, "configuration") outputDirectory_el = find_el(configuration_el, "./default:outputDirectory", "default", namespaces) if outputDirectory_el is None: outputDirectory_el = ET.SubElement(configuration_el, "outputDirectory") # 设置jar的output目录为work_dir outputDirectory_el.text = work_dir # 2.3.构建repositories if repo: repositories_el = find_el(root, "./default:repositories", "default", namespaces) if repositories_el is None: repositories_el = ET.SubElement(root, "repositories") repository_el = find_el( repositories_el, f"./default:repository/[default:url='{repo}']", "default", namespaces) if repository_el is None: repository_el = ET.SubElement(repositories_el, "repository") ET.SubElement(repository_el, "id").text = "repo" ET.SubElement(repository_el, "name").text = "repo" ET.SubElement(repository_el, "layout").text = "default" ET.SubElement(repository_el, "url").text = repo else: raise Exception(f"无法处理{pom}的packaging类型:{pkg_el.text}") # 获取modules(packaging为pom类型) cur_pom_modules = find_el(root, ".//default:modules", "default", namespaces) if cur_pom_modules is not None: for module_el in cur_pom_modules: # 这里的意思是——如果module写的是pom的路径,则直接使用。如果写的是模块名(目录),则加上pom.xml。 # 由于maven pom重module一般都是相对路径,因此这里通过pathlib可以很方便的就得到了全路径 module_pom = os.path.join( module_el.text, "" if module_el.text.find(".xml") > 0 else "pom.xml") # 从当前pom所在的路径(pom/../)作为基准,找到module_pom的真实路径,处理module_pom process_module(str(pathlib(pom, "../", module_pom).resolve()), parent_pom=pom) # 把pom类型引用起来 if parent_poms.get(artifactId) is None: parent_poms[artifactId] = { "groupId": groupId, "artifactId": artifactId, "version": version, "pom": pom } # 将当前pom的module,修改为后面拷贝出来的nexus_pom的相对路径 module_el.text = module_pom.replace("pom.xml", "nexus_pom.xml") # 3、将修改后的新pom输出到当前pom同级目录 [ ET.register_namespace("" if key == "default" else key, namespaces.get(key)) for key in namespaces ] nexus_pom = str(pathlib(pom, "../", "nexus_pom.xml").resolve()) tree.write(nexus_pom, encoding="utf-8") nexus_poms[artifactId] = { "nexus_pom": nexus_pom, "skipdeploy": skip_deploy, "parent_pom": parent_pom }
async def run(): maven_repo = None nexus = None nexus_user = None nexus_pwd = None maven_home = None java_home = None pom_path = None mvn_setting = None mvn_local_repository = None keep_result = True gen_file = False opts, args = getopt.getopt(sys.argv[1:], "i:t:m:j:u:p:s:k:f", [ "source=", "nexus=", "maven-home=", "java-home=", "pom-path=", "username="******"password="******"mvn-settings=", "mvn-local-repository=", "keep=" ]) for arg, val in opts: if arg in ("-i", "--source"): maven_repo = val if arg in ("-t", "--nexus"): nexus = val if arg in ("-u", "--username"): nexus_user = val if arg in ("-p", "--password"): nexus_pwd = val if arg in ("-m", "--maven-home"): maven_home = val if arg in ("-j", "--java-home"): java_home = val if arg in ("-s", "--pom-path"): pom_path = val if arg == "--mvn-settings": mvn_setting = val if arg == "--mvn-local-repository": mvn_local_repository = val if arg in ("-k", "--keep"): keep_result = val == "True" if arg == "-f": gen_file = True if pom_path is None or nexus is None: raise Exception( "-s [maven module's pom path], -t [nexus url] must specify") if pathlib(pom_path).name.find(".xml") < 0: raise Exception("-s [maven module's pom path] must a full '.xml' path") if not os.path.exists(pom_path): raise Exception(f"{pom_path} not exist") if nexus_user and nexus_pwd and nexus: from urllib import parse result = parse.urlparse(nexus) nexus = f"{result.scheme}://{nexus_user}:{nexus_pwd}@{result.netloc}{result.path}" nexus_poms = {} # 创建工作目录 work_dir = str(pathlib(pom_path, "../nexus_out", "target").resolve()) try: if os.path.exists(work_dir): await del_file(work_dir) else: os.makedirs(work_dir, exist_ok=True) # 检查maven、java java = str(pathlib(java_home, "java").resolve()) if java_home else "java" out, err = await exec_shell(f"{java} -version") if err and err.find("version") < 0: raise Exception(f"{java} is not a valid java") mvn = str(pathlib(maven_home, "mvn").resolve()) if maven_home else "mvn" out, err = await exec_shell(f"{mvn} -version") if out.find("Maven home:") < 0 and err.find("Maven home:") < 0: raise Exception(f"{mvn} is not a valid mvn") maven_home = out[out.find("Maven home:") + len("Maven home:"):out. find("\n", out.find("Maven home:"))].strip() maven_home = str(pathlib(maven_home).resolve()) if not mvn_setting: mvn_setting = str( pathlib(maven_home, 'conf', 'settings.xml').resolve()) if mvn_local_repository: mvn_local_repository = f"-Dmaven.repo.local={mvn_local_repository} " # 复制和处理pom print("在目标目录构建nexus_pom....") nexus_poms, origin_parent_poms = process_source_pom(pom_path, repo=maven_repo, work_dir=work_dir) print("在目标目录构建nexus_pom完成.") print(nexus_poms) # 开始执行maven的动作 files = os.listdir(str(pathlib(maven_home, 'boot').resolve())) exe_jar = str( pathlib(maven_home, 'boot', 'plexus-classworlds-2.6.0.jar').resolve()) for file in files: if file.startswith("plexus-classworlds"): exe_jar = str(pathlib(maven_home, 'boot', file).resolve()) mvn = f"{java} -Dmaven.multiModuleProjectDirectory={str(pathlib(pom_path, '../').resolve())} " \ "-DarchetypeCatalog=internal -Dmaven.multiModuleProjectDirectory=$M2_HOME " \ f"-Dmaven.home={maven_home} -Dclassworlds.conf={str(pathlib(maven_home, 'bin', 'm2.conf').resolve())} " \ f"-Dfile.encoding=UTF-8 -classpath {exe_jar} " \ f"org.codehaus.classworlds.Launcher --errors -s {mvn_setting} " \ f"{mvn_local_repository if mvn_local_repository is not None else ''} -DskipTests=true -f {pom_path.replace('pom.xml', 'nexus_pom.xml')} " mvn_package = f"{mvn} package -Dmdep.copyPom=true dependency:copy-dependencies" mvn_dependency_list = f"{mvn} dependency:list" # 搜集依赖jar的信息 mvn_clean = f"{mvn} clean" # region: 打开控制台 print("开打虚拟控制台....") xwin = "cmd" if is_win() else "/bin/bash" console = subprocess.Popen(xwin, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) print("开打虚拟控制台完成.") # endregion """ 构造一个用于发送命令和接收返回的嵌套事件协程,目标是在一个虚拟环境中执行pip install,并且搜集Downlaoding和Using cached的结果 """ # 定义搜集器 __default_collector = lambda res: print(f"get resp: {res.strip()}") errors = [] __err_collector = lambda res: errors.append(res.strip()) if res.strip( ).startswith("[ERROR]") else None # 定义处理方法 async def process_command(cmd_list): for i in range(len(cmd_list)): cmd, command_over_signal, info_collecotr = cmd_list[i][ "cmd"], cmd_list[i]["confirm"], cmd_list[i].get( "info_collectors") console.stdin.write( (cmd + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() print(f"{cmd} 已发送") # 发送特殊的echo,目的是给一个“结束”信号 console.stdin.write((f"echo {command_over_signal}" + ("\r\n" if is_win() else "\n")).encode()) console.stdin.flush() while True: resp = console.stdout.readline() try: resp = resp.decode("UTF-8") except UnicodeDecodeError: resp = resp.decode("GBK") [collect(resp) for collect in info_collecotr] if resp.strip() == command_over_signal: # 说明上一个命令已经发送,并且执行成功 break # region: 使用process_command执行构造好的mvn命令 print("执行mvn命令....") dependencies = [] m = re.compile(r".*:.*:jar:.*:compile", re.I) def __artifactlist_collector__(res): res = res.replace("[INFO]", "").strip() if m.match(res) and res not in dependencies: dependencies.append(res) build_targets = [] def __build_targets_collector__(res): res = res.replace("[INFO]", "").strip() if res.startswith("Building jar:"): res = res.replace("Building jar:", "").strip() if not res.endswith( "-sources.jar") and res not in build_targets: # \programing\WorkSpace\FoundationPlatform\SobeyHive-Flow\IMPL\target\sobeyhive-flow-impl-1.0.jar build_targets.append(res) commands = [{ "cmd": mvn_clean, "confirm": "___mvn_clean_over", "info_collectors": [__default_collector] }, { "cmd": mvn_package, "confirm": "___mvn_package_over", "info_collectors": [ __default_collector, __err_collector, __build_targets_collector__ ] }, { "cmd": mvn_dependency_list, "confirm": "___mvn_dependencylist_over", "info_collectors": [__default_collector, __artifactlist_collector__] }] # 把任务启动起来 tasks = [asyncio.ensure_future(process_command(commands))] fetures, pendings = await asyncio.wait( tasks, return_when=asyncio.tasks.FIRST_EXCEPTION) for task in fetures: # 执行迭代,让任务在主事件循环中处理完 pass print("执行mvn命令打包完成.") if len(errors) > 0: print("+++++++++++++++++++ERROR++++++++++++++++") for err in errors: print(f"+ {err}") print("++++++++++++++++++++++++++++++++++++++++") raise Exception("执行mvn打包出现错误,请检查控制台[ERROR]信息") # endregion # region: 为dependencies构造mvn deploy命令,同时,把target也包含进来 # 由于前面采用maven-jar-plugin输出了pom.properties到builds目录,因此这里就可以使用 # —— 这句话作废。因为新版本的jar-plugin在mac上没测试通过,其逻辑和官网描述完全不一致。pomPropertiesFile的设置完全变了逻辑 # 并且,在mac上测试的时候,只要自定义了jar-plugin,就会编译不通过。 # 因此构造nexux_pom的时候,不再构造jar-plugin,从package的信息中获取原始的target位置 mvn_deploys = [] # pl = pathlib(work_dir) # files = os.listdir(str(pl.joinpath("builds").resolve())) # for file in files: # if file.find(".properties")>0: # version, groupId, artifactId = None, None, None # with open(str(pl.joinpath("builds", file).resolve()), "r") as prop: # line = prop.readline() # while line: # if line.find("version=")>0: version = line.replace("version=","") # if line.find("groupId=")>0: groupId = line.replace("groupId=","") # if line.find("artifactId=")>0: artifactId = line.replace("artifactId=","") # line = prop.readline() # if version and groupId and artifactId: # mvn_deploys.append(f"mvn deploy:deploy-file -DgroupId={groupId} " # f"-DartifactId={artifactId} -Dversion={version} " # f"-DgeneratePom=true -Dpackaging=jar " # f"-Durl={nexus} " # f"-Dfile={str(pl.joinpath(artifactId+'-'+version+'.jar'))}") work_path = pathlib(work_dir) for item in build_targets: target_dir = str(pathlib(item, "../").resolve()) propertyfile = str( pathlib(target_dir, "maven-archiver", "pom.properties").resolve()) if not os.path.exists(propertyfile): raise Exception(f"错误,{target_dir}没有生成pom.properties") version, groupId, artifactId = None, None, None with open(propertyfile, "r") as prop: line = prop.readline() while line: if line.find("version=") >= 0: version = line.replace("version=", "").strip() if line.find("groupId=") >= 0: groupId = line.replace("groupId=", "").strip() if line.find("artifactId=") >= 0: artifactId = line.replace("artifactId=", "").strip() line = prop.readline() if version and groupId and artifactId: # 把mvn-jar-plugin打包的target,拷贝到dependencies里面(删除原来通过maven-dependency-plugin拷贝的,因为它拷贝的pom是nexus_pom) if os.path.exists( str( work_path.joinpath(artifactId + '-' + version + '.jar'))): os.remove( str( work_path.joinpath(artifactId + '-' + version + '.jar'))) if os.path.exists( str( work_path.joinpath(artifactId + '-' + version + '.pom'))): os.remove( str( work_path.joinpath(artifactId + '-' + version + '.pom'))) if os.path.exists(item) and os.path.exists( str(pathlib(item, '../', 'pom.xml').resolve())): shutil.copyfile( item, str( work_path.joinpath(artifactId + '-' + version + '.jar'))) shutil.copyfile( str(pathlib(item, '../', 'pom.xml').resolve()), str( work_path.joinpath(artifactId + '-' + version + '.pom'))) # 对于build的内容,看看是否是Skip if nexus_poms.get(artifactId) and nexus_poms.get( artifactId).get("skipdeploy") is False: command = ( f"mvn deploy:deploy-file -DgroupId={groupId} " f"-DartifactId={artifactId} -Dversion={version} " f"-DgeneratePom=false -Dpackaging=jar " f"-Durl={nexus} " f"-Dfile={str(work_path.joinpath(artifactId+'-'+version+'.jar'))} " f"-DpomFile={str(work_path.joinpath(artifactId+'-'+version+'.pom'))} " f"-DretryFailedDeploymentCount=3") else: command = f"echo \"根据maven-deploy-plugin配置,skip-deploy: {artifactId+'-'+version+'.jar'}\"" if command not in mvn_deploys: mvn_deploys.append(command) for item in dependencies: item = item.split(":") # org.springframework:spring-aop:jar:4.2.0.RELEASE:compile version, groupId, artifactId = item[3], item[0], item[1] command = ( f"mvn deploy:deploy-file -DgroupId={groupId} " f"-DartifactId={artifactId} -Dversion={version} " f"-DgeneratePom=false -Dpackaging=jar " f"-Durl={nexus} " f"-Dfile={str(work_path.joinpath(artifactId+'-'+version+'.jar'))} " f"-DpomFile={str(work_path.joinpath(artifactId+'-'+version+'.pom'))} " f"-DretryFailedDeploymentCount=3") if command not in mvn_deploys: mvn_deploys.append(command) # 把依赖的packaging为pom类型的pom也上传 for key in origin_parent_poms: # 拷贝原始pom到目标目录 artifactId = origin_parent_poms.get(key).get('artifactId') version = origin_parent_poms.get(key).get('version') source = origin_parent_poms.get(key).get('pom') target = str( work_path.joinpath(artifactId + "-" + version + "." + pathlib(source).name)) shutil.copyfile(source, target) command = ( f"mvn deploy:deploy-file -DgroupId={origin_parent_poms.get(key).get('groupId')} " f"-DartifactId={artifactId} -Dversion={version} " f"-DgeneratePom=false -Dpackaging=pom " f"-Durl={nexus} " f"-Dfile={target} " f"-DretryFailedDeploymentCount=3") if command not in mvn_deploys: mvn_deploys.append(command) # endregion # region 重新进入虚拟环境,在虚拟环境中执行mvn deploy # 目前直接覆盖上传,按道理,应该查询一下,然后再上传 if gen_file: try: os.remove(str(pathlib(work_dir, "../", "upload.sh").resolve())) except: pass with open(str(pathlib(work_dir, "../", "upload.sh").resolve()), "w") as code: # code.write(f'for pom in {str(pathlib(work_dir, "*.pom"))};'+ # f' do mvn deploy:deploy-file -Durl={nexus}' + # ' -Dfile="${pom%%.pom}.jar" -DgeneratePom=false -DpomFile="$pom"') for mvn in mvn_deploys: code.write(mvn + "\n") else: print("上传到nexus....") for mvn_deploy in mvn_deploys: out, err = await exec_shell(mvn_deploy) if err: raise Exception(err) print("上传到nexus完成.") # endregion except Exception as e: import traceback print("出现错误:", e) print(traceback.format_exc()) finally: if not keep_result: for key in nexus_poms: try: os.remove(nexus_poms.get(key).get("nexus_pom")) except: pass if not gen_file: await del_file(work_dir) print("所有处理完成.")