数据工厂系列(16)项目管理模块-初始化项目上篇

105 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

大家好~我是小方,欢迎大家关注笋货测试笔记体完记得俾个like

回顾

上一期,我们完成了权限控制的引入,数据工厂上的一些操作、查看、数据权限有了更好的把控,接着我们今天来进行项目的初始化操作

需求

我们的设想是数据工厂的脚本与平台进行解耦,在平台上可以创建多个脚本项目,然后脚本项目的所有代码都存放在git上,通过配置项目相关的信息,拉取git上的项目,再···可以回顾下之前的流程图~ 那我们要怎么初始化项目呢?脚本项目都存放在git上,那肯定是git命令呀~

引入subprocess模块

git命令其实就是shell命令,那Python是如何执行shell命令呢?

-system方法 这里最简单的方法就是直接调用os.system,执行shell命令

import os
os.system('ls')

但是这里会存在一个问题,无法获取shell命令的输出,也无法进行输入,没有超时设置,如果命令挂死,直接导致当前进程挂死

  • subprocess模块

subprocess模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值,简单来说就是,帮你启动新的进程来执行shell命令,并不会对当前进程造成影响

这里最常见的用法就是subprocess.run,先来看一下源码,可以看到run方法内部也调用了Popen

说几个比较常用的参数:

  • args: 表示要执行的命令,必须为字符串或者字符串列表
  • timeout: 设置命令超时时间,如果超时,子进程就会被杀死,并抛出TimeoutExpired异常
  • check: 如果设置为True,进程退出码不为0,则抛出CalledProcessError异常

先来个demo试试

  • 执行成功
ret_success = subprocess.run('ls', shell=True, timeout=1, check=True)
print(f'输出成功对象:{ret_success}')
print(ret_success.returncode)

  • 执行失败
ret_error = subprocess.run('cat a.txt', shell=True, check=True, timeout=1)
print(f'输出失败对象:{ret_error}')
print(ret_error.returncode)

  • 执行超时
ret_timeout =  subprocess.run(['sleep 2s', 'ls'], timeout=1, shell=True, check=True)
print(f'输出超时对象:{ret_timeout}')
print(ret_timeout.returncode)

subprocess.Popen方法,Popen是subprocess的核心功能,子进程的创建、管理都由它来处理,刚上面也看到了subprocess.run底层实现是由Popen类实现的,两者的用法大致相同,区别点是,subprocess.Popen是异步,subprocess.run是同步,执行下面这两段代码,你就知道差异了如果我们需要等子进程执行完才进行下一步操作,直接使用wait即可,这里先不介绍subprocess.Popen方法啦,有兴趣的同学可自行了解

sub = subprocess.Popen('sleep 5s;echo hello,this is async!!!', shell=True)
print('不用等待')
# 等待子进程终止
# sub.wait()
ret_success = subprocess.run('sleep 1s;echo hello,this is sync!!!', shell=True, timeout=2, check=True)

接下来我们来进行简单封装 新建app/utils/cmd_utils.py,新增如下代码,代码比较简单,大家自己体会一下~

import subprocess
from app.utils.logger import Log

class CmdUtils(object):

    log = Log("CmdUtils")

    @staticmethod
    def cmd(cmd_str: str, timeout: int = 10):
        """
        执行shell命令
        :param cmd_str: 字符串命令
        :param timeout: 超时时间
        :return:
        """
        try:
            subprocess.run(cmd_str, shell=True, check=True, timeout=timeout)
        except Exception as e:
            CmdUtils.log.error(f"{cmd_str} 命令执行失败, 错误信息: {str(e)}")
            raise Exception(f"命令执行失败!!! ")

git clone逻辑

上面已经编写了CmdUtils工具类,那我们来编写核心逻辑吧,先来回顾一下git的clone命令

git clone url
# 拉取指定分支代码
git clone -b branch url
# 通过账号密码拉取
git clone http://username:password@url
# 通过账号密码拉取指定分支
git clone -b branch http://username:password@url

新建app/core/git.py,添加如下代码:

from config import FilePath
from app.utils.logger import Log
from app.utils.cmd_utils import CmdUtils
from urllib.parse import quote

class Git(object):

    log = Log("git")

    @staticmethod
    def git_url(url, user, pwd):
        git_url_list = url.split('/')
        git_url_list[2] = f"{quote(user)}:{pwd}@" + git_url_list[2]
        return '/'.join(git_url_list)

    @staticmethod
    def git_clone_http(git_branch, git_url, user, password):
        """
        http克隆
        :param git_branch: 分支名
        :param git_url: 代码地址
        :param user: git账号
        :param password: git密码
        :return:
        """
        Git.log.info("开始克隆, 方式为http")
        command_str = f"cd {FilePath.BASE_DIR}\n" \
                      f"git clone -b {git_branch} {Git.git_url(git_url, user, password)}\n"
        CmdUtils.cmd(command_str)
        Git.log.info("克隆结束")

这里要注意的是,我们拉下来的项目统一放在项目的根目录;邮箱中的@要使用%40代替,这里用了quote方法进行编码

测试一下代码=。=

总结

今天讲了subprocess模块相关的用法,目前就编写了http克隆的逻辑,还有ssh克隆的逻辑暂未编写,下一遍我们来讲讲ssh克隆代码,大家敬请期待~