Python脚本更新项目依赖


有一个python项目是用poetry管理依赖的 在构建docker镜像部署的时候也是poetry去管理依赖 但是现在部分业务切到函数计算来用
函数计算则是要给一个函数配置对应的层 所以在开始都是手动去更新层信息 在CI/CD自动话之前 想要一个脚本来自动更新层信息

因为会涉及很多正则操作 所以打算用python来做脚本文件。 python 做脚本文件有一个很好用的库 fire

监控最新的依赖

依赖信息都安装在 backend/pyproject.toml 且规定用一个注释 # fc build start来作为分割 标记最新的依赖有哪些

...
alibabacloud-darabonba-stream = "^0.0.1"
aliyun-python-sdk-sts = "^3.1.2"
# fc build start
fire = "^0.5.0"

通过正则和字符串来匹配最新的依赖信息。最新的库和版本号

def list_new_packages():
    """找到最新安装的依赖."""
    packages = []
    with open("backend/pyproject.toml") as f:
        lines = f.readlines()
        new_package_flag = False
        for line in lines:
            if not line.strip():
                continue
            if "[tool.poetry.dev-dependencies]" in line:
                break
            if new_package_flag:
                if line.startswith("#"):
                    continue

                if "#" in line:
                    line = line.split("#")[0]

                package = ""
                version = ""
                extras = ""
                result = tuple(line.split("=", 1))
                package, description = result
                if description.strip().startswith("{"):
                    description = description.replace("extras", '"extras"')
                    description = description.replace("version", '"version"')
                    description = description.replace("python", '"python"')
                    description = description.replace("=", ":")
                    print(description)
                    infos = json.loads(description)
                    version = infos.get("version", "").strip("^")
                    extras = infos.get("extras")
                    new_package = (
                        (f"{package.strip()}[{'|'.join(extras)}]=={version}")
                        if extras
                        else f"{package.strip()}=={version}"
                    )

                    packages.append(new_package)
                else:
                    version = description.strip().strip('"').strip("^")
                    new_package = f"{package.strip()}=={version}"
                    packages.append(new_package)
            if "# fc build start" in line:
                new_package_flag = True
    stdout("以下为新增依赖")
    stdout(">>>>>>>>>>>>", StdoutType.INFO)
    for package in packages:
        stdout(f"{package}")
    stdout(">>>>>>>>>>>>", StdoutType.INFO)

将最新的依赖 追加写入 requirements.txt

import json
import os
import subprocess
import sys
from enum import Enum

import fire


class StdoutType(str, Enum):
    DEFAULT = "default"
    INFO = "info"
    ERROR = "error"
    WARNING = "warning"
    DEBUG = "debug"


def list_new_packages() -> list[str]:
    """找到最新安装的依赖."""
    packages = []
    with open("backend/pyproject.toml") as f:
        lines = f.readlines()
        new_package_flag = False
        for line in lines:
            if not line.strip():
                continue
            if "[tool.poetry.dev-dependencies]" in line:
                break
            if new_package_flag:
                if line.startswith("#"):
                    continue

                if "#" in line:
                    line = line.split("#")[0]

                package = ""
                version = ""
                extras = ""
                result = tuple(line.split("=", 1))
                package, description = result
                if description.strip().startswith("{"):
                    description = description.replace("extras", '"extras"')
                    description = description.replace("version", '"version"')
                    description = description.replace("python", '"python"')
                    description = description.replace("=", ":")
                    print(description)
                    infos = json.loads(description)
                    version = infos.get("version", "").strip("^")
                    extras = infos.get("extras")
                    new_package = (
                        (f"{package.strip()}[{'|'.join(extras)}]=={version}")
                        if extras
                        else f"{package.strip()}=={version}"
                    )

                    packages.append(new_package)
                else:
                    version = description.strip().strip('"').strip("^")
                    new_package = f"{package.strip()}=={version}"
                    packages.append(new_package)
            if "# fc build start" in line:
                new_package_flag = True
    stdout("以下为新增依赖")
    stdout(">>>>>>>>>>>>", StdoutType.DEBUG)
    for package in packages:
        stdout(package)
    stdout(">>>>>>>>>>>>", StdoutType.DEBUG)
    return packages


def write_requirements(packages: list[str]):
    """将新的依赖写入 requirements."""
    with open("backend/requirements.txt", "a") as f:
        f.writelines([f"{package}\n" for package in packages])


def stdout(info: str, out_type: StdoutType = StdoutType.DEFAULT):
    match out_type:
        case StdoutType.DEFAULT:
            pass
        case StdoutType.ERROR:
            info = "\033[91m" + info + "\033[0m"
        case StdoutType.INFO:
            info = "\033[92m" + info + "\033[0m"
        case StdoutType.WARNING:
            info = "\033[93m" + info + "\033[0m"
        case StdoutType.DEBUG:
            info = "\033[94m" + info + "\033[0m"
    sys.stdout.write(info)
    sys.stdout.write(os.linesep)
    sys.stdout.flush()


class FcLayerUpdater:
    def update(self):
        try:
            stdout("step1 -> 匹配最新的依赖包", StdoutType.INFO)
            packages = list_new_packages()
            stdout("step2 -> 将新的依赖写入 requirements", StdoutType.INFO)
            write_requirements(packages)
            stdout("step3 -> 安装requirements", StdoutType.INFO)
            subprocess.Popen(
                "pip install -r backend/requirements.txt -t ./fc_layer", shell=True
            ).wait()
            stdout("step4 -> 将文件夹打包为 zip", StdoutType.INFO)
            os.system("sudo apt-get install zip")
            subprocess.Popen("zip -r fc_layer.zip fc_layer", shell=True).wait()
            stdout("step5 -> 上传 zip 到 OSS", StdoutType.INFO)
            stdout("step6 -> 通过OSS更新层", StdoutType.INFO)
        except Exception as e:
            stdout(f"更新失败. 错误原因 {e.__str__()}", StdoutType.ERROR)
            sys.exit(1)
        except KeyboardInterrupt:
            stdout("更新停止", StdoutType.ERROR)
            sys.exit(1)


if __name__ == "__main__":
    try:
        fire.Fire(FcLayerUpdater)
    except SystemExit as e:
        if e.code != 0:
            sys.exit(e.code)

… 没时间接着写了 先撸代码 有缘再见


文章作者: Wanheng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Wanheng !
评论
  目录