zoukankan      html  css  js  c++  java
  • git submodule python实现

    概述

    Git 原生的sumodules 功能无法实现将子模块存放在父级目录, 而放入子目录时候会存在多份代码,交叉依赖的问题。所以需要搭建一个脚本工具来解决多个模块之间的依赖关系。

    解决模块依赖

    • 通过配置文件指定git 仓库url、名称、分支、版本

    • 支持解析原生的.gitmodules 文件 (优先解析)

    [submodule "modules/my-module-base"]
    	path = modules/my-module-base
    	url = http://gitlab.xxx.com/my-project/my-module-base.git
    [submodule "modules/my-module-config"]
    	path = modules/my-module-config
    	url = http://gitlab.xxx.com/my-project/my-module-config.git
    
    • 支持dependent.jsong格式配置, 第一次自动生成模板json文件,需要手动再修改成项目所依赖的子模块

      {
          "my-module-base": {
              "url": "http://gitlab.xxx.com/my-project/my-module-base.git",
              "path": "../base",
              "branch": "master",
              "version": ""
          },
          "my-module-config": {
              "url": "http://gitlab.xxx.com/my-project/my-module-config.git",
              "path": "../config",
              "branch": "master",
              "version": ""
          }
      }
      

      .gitmodules 和 depentent.json 二选一,前者 优先解析

    • 日志文件git_multi_module.log

      2021-04-16 16:48:25,347 MainThread   INFO   151: Git multi-modules checkout
      2021-04-16 16:48:25,347 MainThread   INFO    53: No search `.gitmodules` file, sik to git submodules parser.
      2021-04-16 16:48:25,347 MainThread   INFO    90: Load ./dependent.json file.
      2021-04-16 16:48:25,347 MainThread   INFO   111: Clone http://gitlab.xxx.com/my-project/my-module-base.git master to ../base
      2021-04-16 16:48:27,936 MainThread   INFO   114: Done
      2021-04-16 16:48:27,936 MainThread   INFO   111: Clone http://gitlab.xxx.com/my-project/my-module-config.git master to ../config
      2021-04-16 16:48:29,477 MainThread   INFO   114: Done
      

    使用步骤

    • 打包脚本 pyinstaller git_multi_module.py -F 生的Exe;
    • 拷贝git_multi_module.exe文件到工程目录;
    • 双击exe文件运行直接解析.submodule 文件,如果存在则解析并跳过后面步骤,否则检测并生产dependent.json 文件;
    • 修改dependent.json 成指定模块地址;
    • 再次运行git_multi_module.exe文件拉取子模块代码;

    Visual stdio 配置

    • 拉取 developer-manual 工程仓:http://gitlab.xxx.com/my-project/developer-manual.git
    • 同记录拉取开发工程如: my-module-config, 配置依赖模块, 如:
    {
        "my-module-base": {
            "url": "http://gitlab.xxx.com/my-project/my-module-base.git",
            "path": "my-module-base",
            "branch": "master",
            "version": ""
        }
    }
    
    • 打开VS 中的 项目 -》 属性 -》 配置属性 -》 生成事件 -》 预先生成事件 -》 命令行 填写入:

    $(RootDir)developer-manual oolsgit_submodulesgit_multi_module.exe $(SolutionDir)dependent.json $(RootDir) 1

    • 编译前自动拉取依赖仓
    1>------ 已启动生成:  项目: my_module_config, 配置: Debug Win32 ------
    1>  2021-04-19 14:49:11,670 MainThread   INFO   156: Git multi-modules checkout
    1>  2021-04-19 14:49:11,670 MainThread   INFO    40: Root path: D:xxx_workplacemy-module-config..
    1>  2021-04-19 14:49:11,670 MainThread   INFO    41: Config file: D:xxx_workplacemy-module-configdependent.json
    1>  2021-04-19 14:49:11,671 MainThread   INFO    42: Reset before pull: True
    1>  2021-04-19 14:49:11,671 MainThread   INFO    58: No search `.gitmodules` file, skip git submodules parser.
    1>  2021-04-19 14:49:11,672 MainThread   INFO    95: Load D:xxx_workplacemy-module-configdependent.json file.
    1>  2021-04-19 14:49:11,672 MainThread   INFO   103: Pull http://gitlab.xxx.com/my-project/my-module-base.git master to D:xxx_workplacemy-module-base
    1>  2021-04-19 14:49:12,542 MainThread   INFO   109: Done
    1>  my_module_config.vcxproj -> D:xxx_workplacexxx-module-config..inDebugmy_module_config.dll
    

    工具脚本源码

    git_multi_module.py

    
    from logging.handlers import RotatingFileHandler
    
    import os
    import json
    import logging
    from git import Repo
    
    
    class GitMultiModule(object):
        dependent_file = "./dependent.json"
        git_modules_file = ".gitmodules"
    
        dependent_template = {
            "pos-module-base": {
                "url": "https://github.com/xxx/xxx.git",
                "path": "",
                "branch": "master",
                "version": ""
            }
        }
    
        _dependents_ = dict()
    
        def __init__(self, file_name="", root_path_="./",  reset_before_pull_=False):
            if file_name:
                self.dependent_file = file_name
            self.root_path = root_path_
            self.reset_before_pull = reset_before_pull_
            logging.info("Root path: {}".format(self.root_path))
            logging.info("Config file: {}".format(self.dependent_file))
            logging.info("Reset before pull: {}".format(self.reset_before_pull))
    
            if not self.load_git_modules_file():
                self.load_file()
    
        def make_dependent_template(self) -> bool:
            logging.info("Make dependent template json file...")
            with open(self.dependent_file, "w", encoding="utf-8") as f:
                json.dump(self.dependent_template, f, ensure_ascii=False, indent=4)
            logging.info("Done")
            msg = "Please configure the `{}` file with your project and restart this tools"
            logging.info(msg.format(self.dependent_file))
            return False
    
        def load_git_modules_file(self) -> bool:
            if not os.path.exists(self.git_modules_file):
                logging.info("No search `{}` file, skip git submodules parser.".format(self.git_modules_file))
                return False
    
            logging.info("Loading `{}` file...".format(self.git_modules_file))
            from configparser import ConfigParser
            cf = ConfigParser()
            cf.read(self.git_modules_file)
            modules = cf.sections()
            git_submodules = dict()
    
            for section in modules:
                try:
                    _, name, _ = section.split('"')
                    m_path = cf.get(section, "path")
                    m_url = cf.get(section, "url")
                    m_version = cf.has_option(section, "version") and cf.get(section, "version") or ""
                    m_branch = cf.has_option(section, "branch") and cf.get(section, "branch") or "master"
                    git_submodules[name] = dict(path=m_path, url=m_url, branch=m_branch, version=m_version)
                except Exception as err:
                    logging.error("Load submodules section error:{}".format(err))
            self._dependents_ = git_submodules
    
            if git_submodules:
                return True
            else:
                return False
    
        def load_file(self) -> bool:
            if not os.path.exists(self.dependent_file):
                logging.error("No search `{}` file!".format(self.dependent_file))
                return self.make_dependent_template()
    
            try:
                with open(self.dependent_file, encoding="utf-8") as f:
                    json_obj = json.load(f)
                    if isinstance(json_obj, dict):
                        self._dependents_ = json_obj
                        logging.info("Load {} file.".format(self.dependent_file))
                        return True
            except Exception as err:
                logging.error("Load dependent file error:{}".format(err))
            return False
    
        def pull(self, m_url, m_branch, m_path, m_version):
            try:
                logging.info("Pull {} {} to {}".format(m_url, m_branch, m_path))
                r = Repo(m_path)
                self.reset_before_pull and r.git.execute("git reset HEAD --hard")
                if r.active_branch.name != m_branch:
                    r.git.checkout(m_branch)
                r.remote().pull()
                logging.info("Done")
            except Exception as err:
                _ = self
                logging.error("Pull error:{}".format(err))
    
        def clone(self, m_url, m_branch, m_path, m_version):
            try:
                logging.info("Clone {} {} to {}".format(m_url, m_branch, m_path))
                r = Repo.clone_from(m_url, m_path)  # 拉取远程代码
                r.git.checkout(m_branch)
                logging.info("Done")
            except Exception as err:
                _ = self
                logging.error("Pull clone {}".format(err))
    
        def clone_or_pull(self, m_url, m_branch, m_path, m_version):
            m_path = os.path.abspath(self.root_path + m_path)
            git_path = os.path.join(m_path, ".git")
            if os.path.isdir(git_path):
                self.pull(m_url, m_branch, m_path, m_version)
            else:
                self.clone(m_url, m_branch, m_path, m_version)
    
        def check_modules(self):
            if not self._dependents_:
                logging.error("Dependent configuration error!")
                return
    
            for module_name, config in self._dependents_.items():
                m_url = config.get("url")
                m_path = config.get("path")
                m_version = config.get("version") or ""
                m_branch = config.get("branch") or "master"
                self.clone_or_pull(m_url, m_branch, m_path, m_version)
    
    
    if __name__ == '__main__':
        log_fmt = r"%(asctime)s %(threadName)s %(levelname)6s %(lineno)5d: %(message)s"
        log_file = "git_multi_module.log"
        log_size = 1024 * 124 * 5
        handlers = [
            logging.StreamHandler(),
            RotatingFileHandler(log_file, maxBytes=log_size, backupCount=5, encoding="utf-8")
        ]
        log_param = dict(level=logging.INFO, handlers=handlers, format=log_fmt)
        logging.basicConfig(**log_param)
    
        logging.info("Git multi-modules checkout")
    
        import sys
        argv_len = len(sys.argv)
        config_file = argv_len > 1 and sys.argv[1] or ""
        root_path = argv_len > 2 and sys.argv[2] or "./"
        reset = argv_len > 3 and sys.argv[3] == "1" or False
    
        g = GitMultiModule(config_file, root_path, reset)
        g.check_modules()
    
    
  • 相关阅读:
    拒绝服务攻击
    通过混合编程分析的方法和机器学习预测Web应用程序的漏洞
    防火墙与入侵防护系统
    恶意软件
    密码学
    纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
    C++调用DLL方法
    QQ IP 地址查询相关
    【C/C++】概念: VC虚函数布局引发的问题
    DLL/EXE查看工具Dumpbin
  • 原文地址:https://www.cnblogs.com/onsunsl/p/14888186.html
Copyright © 2011-2022 走看看