1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (c) 2022 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import os 17import sys 18import re 19import argparse 20import subprocess 21import logging 22 23 24def add2dict(diff_dict: dict, path: str, line_num: str, content): 25 key = path 26 value = [line_num, content] 27 28 if key in diff_dict: 29 value_list = diff_dict.pop(key) 30 value_list.append(value) 31 else: 32 value_list = [value] 33 34 diff_dict.update({key: value_list}) 35 36 37def __diff_match_file_start(control_block: dict, line: str): 38 pattern = "diff --git" 39 if not line.startswith(pattern): 40 return False 41 42 control_block["line_num"] = 0 43 control_block["fullpath"] = "" 44 control_block["match_flag"] = False 45 control_block["curr_key"] = "" 46 control_block["is_new_file"] = False 47 48 return True 49 50 51def __diff_match_is_newfile(control_block: dict, line: str): 52 pattern = "new file" 53 if not line.startswith(pattern): 54 return False 55 56 control_block["is_new_file"] = True 57 return True 58 59 60def __diff_match_filename_with_minus(control_block: dict, line: str): 61 pattern = "---\ (a/)?.*" 62 if re.match(pattern, line) is None: 63 return False 64 65 control_block["match_flag"] = False 66 return True 67 68 69def __diff_match_filename_with_plus(control_block: dict, line: str): 70 pattern = "\+\+\+\ b/(.*)" 71 if re.match(pattern, line) is None: 72 return False 73 74 for key in control_block["diff_dict"]: 75 if re.search(key, line) is not None: 76 control_block["curr_key"] = key 77 res = re.match(pattern, line) 78 control_block["fullpath"] = ( 79 "{}, {}".format(control_block["pull_request_url"], res.group(1).strip()) 80 ) 81 if control_block['is_new_file'] is True: 82 control_block["fullpath"] = "%s%s" % ( 83 control_block["fullpath"], "(new file)") 84 control_block["match_flag"] = True 85 return True 86 87 88def __diff_match_start_linenum(control_block: dict, line: str): 89 pattern = "@@\ -[0-9]+,[0-9]+\ \+([0-9]+)(,[0-9]+)?\ @@.*" 90 if control_block["match_flag"] is False or re.match(pattern, line) is None: 91 return False 92 93 res = re.match(pattern, line) 94 control_block["line_num"] = int(res.group(1)) 95 return True 96 97 98def __diff_match_code_line(control_block: dict, line: str): 99 diff_dict = control_block["diff_dict"] 100 pattern1 = "[\ +-](.*)" 101 pattern2 = "([\ +-])?(.*)" 102 if control_block["match_flag"] is False or re.match(pattern1, line) is None: 103 return False 104 105 res = re.match(pattern2, line) 106 if res.group(1) == "+": 107 add2dict( 108 diff_dict[control_block["curr_key"]], 109 control_block["fullpath"], 110 control_block["line_num"], 111 res.group(2), 112 ) 113 if res.group(1) != "-": 114 control_block["line_num"] = control_block["line_num"] + 1 115 return True 116 117 118def strip_diff(diff_dict: dict, pull_request_url: str, gitee_pr_diff: str): 119 control_block = { 120 "line_num": 0, 121 "fullpath": "", 122 "match_flag": False, 123 "curr_key": "", 124 "diff_dict": diff_dict, 125 "pull_request_url": pull_request_url, 126 "is_new_file": False, 127 } 128 129 strip_diff_handlers = [ 130 __diff_match_file_start, 131 __diff_match_is_newfile, 132 __diff_match_filename_with_minus, 133 __diff_match_filename_with_plus, 134 __diff_match_start_linenum, 135 __diff_match_code_line, 136 ] 137 138 for line in gitee_pr_diff.splitlines(): 139 for handler in strip_diff_handlers: 140 if handler(control_block, line) is True: 141 break 142 143 144def get_diff_by_repo_pr_num(repo_url: str, pr_num: int): 145 diff_url = "%spulls/%s.diff" % (repo_url, str(pr_num)) 146 cmd = "curl -L -s " + diff_url 147 gitee_pr_diff = "" 148 try: 149 ret = subprocess.Popen( 150 ["/usr/bin/curl", "-L", "-s", diff_url], 151 stdout=subprocess.PIPE, 152 stderr=subprocess.PIPE, 153 errors="replace", 154 ) 155 gitee_pr_diff, errorout = ret.communicate() 156 if len(errorout) != 0: 157 logging.error("Popen error: ", errorout) 158 except Exception as err: 159 logging.error("error %s", err, cmd) 160 161 return gitee_pr_diff 162 163 164class GiteeCsctPrehandler: 165 def __init__(self, pr_list: str, *patterns): 166 self.diff_dict = {} 167 for pattern in patterns: 168 pattern_dict = {pattern: {}} 169 self.diff_dict.update(pattern_dict) 170 171 repo_pr_num_list = pr_list.split(";") 172 for pr_item in repo_pr_num_list: 173 pr_split_group = pr_item.split("pulls/") 174 repo_url = pr_split_group[0].strip() 175 pr_num = pr_split_group[1].strip("/") 176 177 gitee_pr_diff = get_diff_by_repo_pr_num(repo_url, pr_num) 178 strip_diff(self.diff_dict, pr_item, gitee_pr_diff) 179 180 def clear_repo_num_file(self): 181 self.diff_dict.clear() 182 183 def get_diff_dict(self, pattern): 184 ret_diff = {} 185 if pattern in self.diff_dict.keys(): 186 ret_diff = self.diff_dict[pattern] 187 return ret_diff 188 189 190def test(): 191 if len(sys.argv) == 1: 192 sys.stderr.write("test error: pr_list is empty.\n") 193 return 194 195 pr_list = sys.argv[1] 196 csct_prehandler = GiteeCsctPrehandler( 197 pr_list, "BUILD.gn", "bundle.json", ".gni") 198 199 print("==================start get diff====================") 200 print(csct_prehandler.get_diff_dict("BUILD.gn")) 201 print("==================start get diff====================") 202 print(csct_prehandler.get_diff_dict("bundle.json")) 203 print("========================end=========================") 204 205 206if __name__ == "__main__": 207 sys.exit(test()) 208