From ac530f70d20abafa508833bad18542ecd0060552 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Mon, 6 Jul 2020 13:15:59 -0400 Subject: [PATCH] [ADD] Support manifest default.staged.xml - Stage is a version between dev and prod, to update future prod with dev - Add doc how to generate default.staged.xml - Fix generate manifest when missing default remote - Fix generate manifest path --- doc/GIT_REPO.md | 12 ++++++ script/fork_project_ERPLibre.py | 3 +- script/git_merge_repo_manifest.py | 68 +++++++++++++++++++++++++++++++ script/git_repo_manifest.py | 7 ++-- script/git_tool.py | 51 +++++++++++++++++------ 5 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 script/git_merge_repo_manifest.py diff --git a/doc/GIT_REPO.md b/doc/GIT_REPO.md index 743a5c5..c58348b 100644 --- a/doc/GIT_REPO.md +++ b/doc/GIT_REPO.md @@ -43,7 +43,19 @@ Do your commit. ```bash git commit -am "[#ticket] subject: short sentence" ``` +### Mix prod and dev to do a stage +When dev contain specific revision with default revision, you want to replace default revision by prod revision and keep specific version, do: +```bash +./venv/bin/python ./script/git_merge_repo_manifest.py --input1 ./manifest/default.dev.xml --input2 ./default.xml --output ./manifest/default.staged.xml +git commit -am "Updated manifest/default.staged.xml" +git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose & + +./venv/repo init -u git://127.0.0.1:9418/ -b $(git rev-parse --abbrev-ref HEAD) -m ./manifest/default.staged.xml +./venv/repo sync -m ./manifest/default.staged.xml + +./venv/repo manifest -r -o ./default.xml +``` ## Create a dev version ```bash ./venv/repo manifest -o ./manifest/default.dev.xml diff --git a/script/fork_project_ERPLibre.py b/script/fork_project_ERPLibre.py index fb25b19..ee22908 100644 --- a/script/fork_project_ERPLibre.py +++ b/script/fork_project_ERPLibre.py @@ -127,7 +127,8 @@ def main(): # Update origin to new repo # git_tool.generate_git_modules(lst_repo_organization, repo_path=config.dir) - git_tool.generate_repo_manifest(lst_repo_organization, repo_path=config.dir) + git_tool.generate_repo_manifest(lst_repo_organization, + output=f"{config.dir}manifest/default.dev.xml") git_tool.generate_install_locally() diff --git a/script/git_merge_repo_manifest.py b/script/git_merge_repo_manifest.py new file mode 100644 index 0000000..8db3d12 --- /dev/null +++ b/script/git_merge_repo_manifest.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +import os +import sys +import argparse +import logging +import copy + +new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.append(new_path) + +from script.git_tool import GitTool + +_logger = logging.getLogger(__name__) + + +def get_config(): + """Parse command line arguments, extracting the config file name, + returning the union of config file and command line arguments + + :return: dict of config file settings and command line arguments + """ + # TODO update description + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Replace revision field in input2 from input1 if existing, create an output of new manifest.""", + epilog='''\ +''' + ) + parser.add_argument('--input1', required=True, + help="First manifest to merge into input2.") + parser.add_argument('--input2', required=True, + help="Second manifest, overwrite by input1.") + parser.add_argument('--output', required=True, + help="Output of new manifest") + # parser.add_argument('--clear', action="store_true", + # help="Create a new manifest and clear old configuration.") + args = parser.parse_args() + return args + + +def main(): + config = get_config() + git_tool = GitTool() + + dct_remote_1, dct_project_1, default_remote_1 = git_tool.get_manifest_xml_info( + filename=config.input1, add_root=True) + dct_remote_2, dct_project_2, default_remote_2 = git_tool.get_manifest_xml_info( + filename=config.input2, add_root=True) + + dct_remote_3 = copy.deepcopy(dct_remote_2) + dct_project_3 = copy.deepcopy(dct_project_2) + + for key, value in dct_project_1.items(): + revision = value.get("@revision") + if revision: + dct_project_3[key]["@revision"] = revision + else: + dct_project_3[key]["@upstream"] = "12.0" + dct_project_3[key]["@dest-branch"] = "12.0" + + # Update origin to new repo + git_tool.generate_repo_manifest(dct_remote=dct_remote_3, dct_project=dct_project_3, + output=config.output, + default_remote=default_remote_2) + + +if __name__ == '__main__': + main() diff --git a/script/git_repo_manifest.py b/script/git_repo_manifest.py index e2b634a..87c7daa 100644 --- a/script/git_repo_manifest.py +++ b/script/git_repo_manifest.py @@ -47,12 +47,13 @@ def main(): # Update origin to new repo if not config.clear: - dct_remote, dct_project = git_tool.get_manifest_xml_info(repo_path=config.dir, - add_root=True) + dct_remote, dct_project, _ = git_tool.get_manifest_xml_info( + repo_path=config.dir, add_root=True) else: dct_remote = {} dct_project = {} - git_tool.generate_repo_manifest(lst_repo_organization, repo_path=config.dir, + git_tool.generate_repo_manifest(lst_repo_organization, + output=f"{config.dir}manifest/default.dev.xml", dct_remote=dct_remote, dct_project=dct_project) git_tool.generate_install_locally() diff --git a/script/git_tool.py b/script/git_tool.py index 8bec5d2..07cc7f0 100644 --- a/script/git_tool.py +++ b/script/git_tool.py @@ -269,17 +269,19 @@ class GitTool: lst_repo = sorted(lst_repo, key=lambda k: k.get("name")) return lst_repo - def get_manifest_xml_info(self, repo_path: str = "./", + def get_manifest_xml_info(self, repo_path: str = "./", filename=None, add_root: bool = False) -> list: """ Get contain of manifest :param repo_path: path of repo to get information about submodule + :param filename: manifest filename. Default none, or use this instead use repo_path :param add_root: add information about root repository - :return: dct_remote, dct_project + :return: dct_remote, dct_project, default_remote """ - manifest_file = self.get_manifest_file(repo_path=repo_path) - filename = f"{repo_path}/manifest/{manifest_file}" + if filename is None: + manifest_file = self.get_manifest_file(repo_path=repo_path) + filename = f"{repo_path}/{manifest_file}" with open(filename) as xml: xml_as_string = xml.read() xml_dict = xmltodict.parse(xml_as_string, dict_constructor=dict) @@ -289,7 +291,7 @@ class GitTool: lst_project = dct_manifest.get("project") dct_remote = {a.get("@name"): a for a in lst_remote} dct_project = {a.get("@name"): a for a in lst_project} - return dct_remote, dct_project + return dct_remote, dct_project, default_remote @staticmethod def get_project_config(repo_path="./"): @@ -362,8 +364,19 @@ class GitTool: def str_insert(source_str, insert_str, pos): return source_str[:pos] + insert_str + source_str[pos:] - def generate_repo_manifest(self, lst_repo: List[Struct], repo_path: str = "./", - dct_remote={}, dct_project={}): + def generate_repo_manifest(self, lst_repo: List[Struct] = [], output: str = "", + dct_remote={}, dct_project={}, default_remote=None): + """ + Generate repo manifest + :param lst_repo: optional, update manifest with list_repo + :param output: filename to write output + :param dct_remote: dict of remote information + :param dct_project: dict of project information + :param default_remote: name of default remote, optional + :return: + """ + if not output: + raise Exception("Cannot generate manifest with missing output filename.") lst_remote = [] lst_remote_name = [] lst_project = [] @@ -381,14 +394,20 @@ class GitTool: lst_project_info = [ ('@name', dct_value.get("@name")), ('@path', dct_value.get("@path")), - ('@remote', dct_value.get("@remote")) ] + if "@remote" in dct_value.keys(): + lst_project_info.append(('@remote', dct_value.get("@remote"))) if "@revision" in dct_value.keys(): lst_project_info.append(('@revision', dct_value.get("@revision"))) if "@clone-depth" in dct_value.keys(): lst_project_info.append(('@clone-depth', dct_value.get("@clone-depth"))) if "@groups" in dct_value.keys(): lst_project_info.append(('@groups', dct_value.get("@groups"))) + if "@upstream" in dct_value.keys(): + lst_project_info.append(('@upstream', dct_value.get("@upstream"))) + if "@dest-branch" in dct_value.keys(): + lst_project_info.append(('@dest-branch', dct_value.get("@dest-branch"))) + lst_project.append(OrderedDict(lst_project_info)) lst_project_name.append(dct_value.get("@name")) @@ -430,6 +449,14 @@ class GitTool: lst_project_info.append(('@groups', "odoo")) lst_project.append(OrderedDict(lst_project_info)) + if default_remote and not lst_default: + lst_default.append(OrderedDict([ + ('@remote', default_remote), + ('@revision', "12.0"), + ('@sync-j', "4"), + ('@sync-c', "true"), + ])) + # Order in alphabetic lst_order_remote = sorted(lst_remote, key=lambda key: key.get("@name")) lst_order_default = sorted(lst_default, key=lambda key: key.get("@remote")) @@ -444,14 +471,14 @@ class GitTool: str_xml_text = xmltodict.unparse(dct_repo, pretty=True) pos_insert = str_xml_text.rfind("") - if pos_insert: + if pos_insert >= 0: pos_insert += len("") str_xml_text = self.str_insert(str_xml_text, "\n ", pos_insert) pos_insert = str_xml_text.rfind("") - if pos_insert: + if pos_insert >= 0: pos_insert += len("") - str_xml_text = self.str_insert(str_xml_text, "\n ", pos_insert) + str_xml_text = self.str_insert(str_xml_text, "\n ", pos_insert) # pos_insert = str_xml_text.rfind("") # if pos_insert: @@ -465,7 +492,7 @@ class GitTool: str_xml_text = str_xml_text.replace("\t", " ") # create file - with open(f"{repo_path}manifest/default.dev.xml", mode="w") as file: + with open(output, mode="w") as file: file.writelines(str_xml_text + "\n") def generate_git_modules(self, lst_repo: List[Struct], repo_path: str = "./"):