def f2f(self, args): """ 修复分支转修复分支,默认转到下个迭代 :param list args: :return: """ if '-n' not in args and '-s' not in args: args.append('-n') b_info = self.__branch_and_sprint(args) if not b_info['branch']: raise exception.FlowException(u'未指定分支名称') old_branch = igit.real_branch( b_info['branch'], iconfig.read_config('system', 'branch')['feature_prefix']) new_branch = igit.real_branch( '%s/%s' % (b_info['sprint'], b_info['branch'].split('/')[-1]), iconfig.read_config('system', 'branch')['feature_prefix']) if not old_branch or not new_branch: raise exception.FlowException(u'分支名称不合法') if old_branch not in igit.local_branches(): raise exception.FlowException(u'分支不存在:%s' % old_branch) if ihelper.confirm(u'确定将特性分支%s转为特性分支%s吗?' % (old_branch, new_branch)) == 'y': git.Git('rename', [old_branch, new_branch]).execute() ok() else: ok(u'取消操作')
def f2h(self, args): """ 本迭代的特性分支转修复分支 :return: """ branch = None while args: branch = args.pop(0) if not branch: raise exception.FlowException(u'未指定分支名称') old_branch = igit.real_branch( branch, iconfig.read_config('system', 'branch')['feature_prefix']) new_branch = igit.real_branch( branch.split('/')[-1], iconfig.read_config('system', 'branch')['hotfix_prefix']) if not old_branch or not new_branch: raise exception.FlowException(u'分支名称不合法') if old_branch not in igit.local_branches(): raise exception.FlowException(u'分支不存在:%s' % old_branch) if ihelper.confirm(u'确定将特性分支%s转为修复分支%s吗?' % (old_branch, new_branch)) == 'y': git.Git('rename', [old_branch, new_branch]).execute() ok() else: ok(u'取消操作')
def __resolve_branches(self, line_branches): """ 分支解析 vmember,member-center vmember:/weigao,membercenter:order order-manager :param list line_branches: :return:dict """ if not line_branches: # 所有项目 line_branches = map(lambda x: str(x) + ':*', ihelper.projects()) line_branches = map(lambda x: x.replace(':', ':'), line_branches) branches = {} only_this_sprint = True if self.cmd == iconfig.read_config( 'system', 'branch')['feature_prefix'] else False for br in line_branches: if ':' not in br: # 判断是项目名还是分支名 if br in ihelper.projects(): br += ':*' else: br = iglobal.PROJECT + ':' + br br = br.split(':') proj = br[0] branch = br[1] if branch == '*': # 同步该项目下的本地和远程分支 igit.sync(proj, self.cmd, only_this_sprint=self.cmd == iconfig.read_config( 'system', 'branch')['feature_prefix']) # 获取该项目下的所有相关分支 branch = igit.project_branches(self.cmd, proj, only_this_sprint) else: branch = [igit.real_branch(branch, self.cmd)] if not branches.has_key(proj): branches[proj] = [] branches[proj] += branch # 去重 for key, val in branches.items(): branches[key] = list(set(val)) return branches
def headline(): """ 页眉 """ print project = iglobal.PROJECT curr_proj_info = iconfig.read_config('project', project) branch = igit.current_branch() if project != 'global' else None real_path = os.getcwd() if (project == 'global' or not project or not curr_proj_info or not curr_proj_info.has_key('dir')) \ else curr_proj_info['dir'] if real_path.count('/') > 2: path_arr = real_path.split('/') real_path = '/'.join( [path_arr[0], path_arr[1], '...', path_arr[len(path_arr) - 1]]) iprint.green( iglobal.SPRINT), iprint.sky_blue('/'), iprint.yellow(project + '(' + real_path + ')') if branch: status = igit.workspace_status(text=True) iprint.sky_blue('[ ' + branch + ('(' + status + ')' if status else '') + ' ]') print sys.stdout.flush()
def required_check(): """ 必须进行的检查 """ iprint.info(u'正在进行工作环境检查...') #git版本检测 git_version = igit.git_version() if int(git_version[0]) < 2: raise exception.FlowException(u'git版本过低,请安装2.0.0以上版本') # 检查project.json有没有配置以及路径是否正确 proj_cfg = iconfig.read_config('project', use_cache=False) if not proj_cfg: raise exception.FlowException( u'请配置项目信息(config/project.json文件,具体格式参见readme.md文件)') for proj_name, info in proj_cfg.items(): if proj_name == 'global': raise exception.FlowException(u'项目名称不能叫global,请使用别的名称') if not info['dir'] or not os.path.exists( info['dir']) or not os.path.isdir(info['dir']): raise exception.FlowException(u'项目' + proj_name + u'的目录配置不正确') # 检测目录是否有效的git仓库 if not igit.dir_is_repository(info['dir']): raise exception.FlowException(u'目录' + info['dir'] + u'不是有效的git仓库') # sprint版本号检测 return isprint.check_sprint()
def real_cmd(cmd, raise_err=True, valid=True, top_cmd=None): """ valid=True时,如果不指定top_cmd,则认为cmd是一级指令,否则认为是top_cmd的二级指令 :param str top_cmd: :param cmd: :param raise_err: :param valid: :return: """ config = iconfig.read_config('system') alias = config['alias'] cmd = alias[cmd] if alias.has_key(cmd) else cmd if valid: error = False if top_cmd: top_cmd = alias[top_cmd] if top_cmd in alias else top_cmd cls = config['cmd_cls'][top_cmd] if top_cmd in config['cmd_cls'] else None if not cls: error = True else: if cmd not in dir(eval('%s.%s' % (cls.lower(), cls))): error = True elif not config['cmd_cls'].has_key(cmd): error = True if error: if raise_err: raise exception.FlowException(u'无效指令') else: return None return cmd
def match(text, match_text, startswitch=False): """ git文本匹配 :param bool startswitch: :param str text: :param str match_text: :return:bool """ match_dict = iconfig.read_config('system', 'git_match_text') if not match_dict or match_text not in match_dict: return False txts = match_dict[match_text] if type(txts) != list: txts = [txts] for txt in txts: if startswitch and text.startswith(txt): return True elif txt in text: return True return False
def test_branch(): """ 获取项目的测试分支 :return: """ project = iglobal.PROJECT if project != 'global': proj_cfg = iconfig.read_config('project', project) if proj_cfg.has_key('branch') and dict(proj_cfg['branch']).has_key('test'): return proj_cfg['branch']['test'] config = iconfig.read_config('system', 'branch') if config.has_key('test'): return config['test'] else: return 'sp-dev'
def top_cmd_list(): """ 获取所有的一级指令列表 返回:字典:指令->别名列表 :return: """ cmds = iconfig.read_config('system', 'cmd_cls').keys() alias = iconfig.read_config('system', 'alias') lst = {} for cmd in cmds: if cmd not in lst: lst[cmd] = [] for al, c in alias.items(): if cmd == c: lst[cmd].append(al) return lst
def check_sprint_format(sprint, loose=False): """ 迭代号格式检验 :param Bool loose: """ return re.compile( iconfig.read_config('system') ['sprint_format' if not loose else "sprint_format_loose"]).match( sprint)
def read_runtime(key=None): """ 读取运行时信息 :param key: """ info = iconfig.read_config(iglobal.BASE_DIR + '/runtime', use_cache=False) if key: return info[key] if info.has_key(key) else None else: return info
def match_transform(self, text, line_words): if text.startswith('-'): return self.match_parameter(None, command.Transform.parameters, text) else: branch_cfg = iconfig.read_config('system', 'branch') prefix = branch_cfg['feature_prefix'] if line_words[0].startswith( 'f') else branch_cfg['hotfix_prefix'] if prefix == branch_cfg['feature_prefix']: prefix += '/' + iglobal.SPRINT return self.match_branch(prefix, text)
def match_develop(self, text, line_words): if len(line_words) == 1: return self.top_cmd(text) elif len(line_words) == 2: # 二级指令 matches = None if not line_words[1].startswith('-'): matches = self.sub_cmd(command.Develop.sub_cmd_list, text) if not matches: # 没有匹配上二级指令 line_words.insert(1, 'checkout') return self.match_develop(text, line_words) return matches else: if line_words[1].startswith('-'): line_words.insert(1, 'checkout') # 分支或其他 top_cmd = icommand.real_cmd(line_words[0], raise_err=False) sub_cmd = icommand.real_cmd(line_words[1], raise_err=False, top_cmd=top_cmd) if not sub_cmd: return None if top_cmd == iconfig.read_config('system', 'branch')['feature_prefix']: branch_prefix = top_cmd + '/' + iglobal.SPRINT + '/' else: branch_prefix = top_cmd if text.startswith('-'): return self.match_parameter(sub_cmd, command.Develop.parameters, text) if sub_cmd == 'create': # 创建分支时,提示远程存在而本地不存在的分支 return self.match_remoteonly_branch(branch_prefix, text) elif sub_cmd == 'product': # 此时可能是项目或分支名 return self.match_project_branch(branch_prefix, text) elif sub_cmd == 'checkout': iglobal.SILENCE = True include_remote = '-r' in line_words or '--remote' in line_words match = self.match_branch(branch_prefix, text, include_remote) iglobal.SILENCE = False return match else: # 提示分支名 return self.match_branch(branch_prefix, text)
def exec_hook(flag, position, proj=None, branch=None): """ 执行钩子指令 :param flag: 标识,如product :param position: 位置,如post(主指令后),pre(主指令前) :param proj: 所在的项目 :param branch: 所在的分支 :return: None """ hook_cfg = iconfig.read_config('system', "hook") if not hook_cfg or not hook_cfg.has_key(flag) or not isinstance(hook_cfg[flag], dict): return None hook_cfg = hook_cfg[flag] if not hook_cfg.has_key(position) or not isinstance(hook_cfg[position], list) or not hook_cfg[position]: return None orig_dir = os.getcwd() orig_branch = igit.current_branch() for cfg in hook_cfg[position]: if not cfg or not isinstance(cfg, dict) or not cfg.has_key('cmd'): continue # 项目限制 if proj and cfg.has_key("proj") \ and isinstance(cfg["proj"], list) \ and cfg["proj"] \ and proj not in cfg["proj"]: continue # 分支限制 if branch and cfg.has_key("branch") \ and isinstance(cfg["branch"], list) \ and cfg["branch"] \ and branch not in cfg["branch"]: continue if not cfg.has_key("title") or not cfg["title"]: cfg["title"] = u"自定义脚本:%s" % cfg["cmd"] # 执行钩子 iprint.say(('green', u'执行'), ('yellow', cfg["title"]), ('green', '...')) ihelper.execute(cfg["cmd"]) iprint.say(('yellow', cfg["title"]), ('green', u'执行完成!')) if os.getcwd() != orig_dir: os.chdir(orig_dir) if igit.current_branch() != orig_branch: os.system('git checkout %s' % orig_branch)
def real_branch( branch, prefix): """ 获取完整的分支名 :param str prefix: :param str branch: :return: str """ if not branch: raise exception.FlowException(u'参数错误') if branch.find(':') != -1: branch = branch.split(':')[1] original_branch = branch branch = filter(lambda x:x != '', branch.split('/')) config = iconfig.read_config('system', 'branch') if len(branch) > 2 and branch[0] != config['feature_prefix']: raise exception.FlowException(u'分支格式不合法') if len(branch) == 3: branch[1] = isprint.get_sprint(branch[1]) if not branch[1]: raise exception.FlowException(u'分支格式不合法') return '/'.join(branch) if len(branch) == 2: if branch[0] == 'hotfix': return '/'.join(branch) elif isprint.check_sprint_format(branch[0], True): # 迭代号开始的,此时prefix只能是feature if prefix != config['feature_prefix']: raise exception.FlowException(u'分支格式不合法') branch[0] = isprint.get_sprint(branch[0]) branch.insert(0, config[prefix + '_prefix']) else: # 看是否以feature或hotfix开头 if branch[0] != config['feature_prefix'] and branch[0] != config['hotfix_prefix']: raise exception.FlowException(u'分支格式不合法') return '/'.join(branch) if original_branch.find('/') == 0: return config[prefix + '_prefix'] + original_branch else: return config[prefix + '_prefix'] + ('/' + iglobal.SPRINT if prefix == 'feature' else '') + '/' + branch[0]
def match_git(self, text, line_words): top_cmd = icommand.real_cmd(line_words[0], raise_err=False) if top_cmd in ['delete', 'commit'] and text.startswith('-'): return self.match_parameter(top_cmd, command.Git.parameters, text) elif top_cmd in ['delete', 'rename']: return self.match_branch(None, text) elif top_cmd == 'git': if not text: return None elif len(line_words) > 2: return self.match_branch(None, text) else: return [ele + ' ' for ele in iconfig.read_config('system', 'git_common_cmds') if ele.startswith(text)] \ or [ele + ' ' for ele in igit.sub_cmd_list() if ele.startswith(text)] return None
def write_runtime(key, val=None): """ 写入运行时信息 :param val: :param key: """ if not key and not val: return True info = iconfig.read_config(iglobal.BASE_DIR + '/runtime') if val: info[key] = val else: info.has_key(key) and info.pop(key) iconfig.write_config(iglobal.BASE_DIR + '/runtime', info) return True
def match(self, text): """ 一级指令 二级指令 参数1 参数2 ... :type text: str :return: """ line = re.compile('\s+').sub(' ', readline.get_line_buffer()) line_words = line.split(' ') if len(line_words) == 1: return self.top_cmd(text) else: cls = iconfig.read_config('system', 'cmd_cls') cmd = icommand.real_cmd(line_words[0], raise_err=False) if not cmd: return None return eval('self.match_%s' % str(cls[cmd]).lower())(text, line_words)
def init(): """ 初始化 """ # 检查必要目录 check_dir() # 进入项目目录 proj = read_runtime('project') iglobal.PROJECT = proj or 'global' if proj: pinfo = iconfig.read_config('project', proj) if pinfo.has_key('dir'): os.chdir(pinfo['dir']) iglobal.SPRINT = read_runtime('sprint') or 'none' # 设置Git参数 execute('git config --global push.default simple')
def cd(args): """ 进入项目目录 :param args: """ if not args: raise exception.FlowException(u'指令格式不正确,请键入help查看该指令使用方式') proj_name = args[0] proj = iconfig.read_config('project', proj_name) if not proj or not proj.has_key('dir'): raise exception.FlowException(u'未配置项目' + proj_name + u'信息,请进入config/project.json中正确配置') if not os.path.isdir(proj['dir']): raise exception.FlowException(u'该项目git根目录配置不正确,请进入config/project.json中正确配置') iglobal.PROJECT = proj_name ihelper.write_runtime('project', proj_name) os.chdir(proj['dir'])
def sub_cmd(self, sub_list, word=None): """ 二级指令 :type sub_list: list :type word: str :return: """ if not word: return list(sub_list) alias = iconfig.read_config('system', 'alias') matches = [] for sub in sub_list: if sub.startswith(word): matches.append(sub) else: for al, c in alias.items(): if c == sub and str(al).startswith(word): matches.append(al) matches = map(lambda x: x + ' ', matches) matches.sort() return matches
sys.exit(0) reload(sys) sys.setdefaultencoding('utf-8') if __name__ == '__main__': iglobal.BASE_DIR = os.getcwd().replace('\\', '/') # 初始化 try: ihelper.init() except Exception, e: print e.message.decode('utf-8').encode(iglobal.FROM_ENCODING) raw_input() cfg = iconfig.read_config('system') # 操作系统命令行编码 if 'console_encoding' in cfg: iglobal.FROM_ENCODING = cfg['console_encoding'] blue(u'=========================***=========================', True) blue(cfg['name'], True) blue(u'作者:' + cfg['author'], True) blue(cfg['desc'], True) blue(cfg['more_info'], True) blue(u'=========================***=========================', True) # tab键自动补全 icompleter.tab()
def alias(args=None): cfg = iconfig.read_config('system', 'alias') arr = [] for key, val in cfg.items(): if key != val: print "%3s%12s"%(key, val)
def projects(): """ 项目名称列表 :return: """ return dict(iconfig.read_config('project')).keys()
def sql(args=None): """ 获取项目下面的所有sql :param args: :return: """ dirs = [] old_proj = iglobal.PROJECT for proj, info in iconfig.read_config('project').items(): if 'ignore_sql_file' in info and info['ignore_sql_file']: continue # 需要先将项目切换到相应的分支 sql_branch = info['branch']['sql_branch'] \ if info.has_key('branch') and 'sql_branch' in info['branch'] \ else iconfig.read_config('system', 'branch')['sql_branch'] # 进入项目 if iglobal.PROJECT != proj: iprint.info(u'进入项目%s' % proj) Extra.cd([proj]) curr_branch = igit.current_branch() if curr_branch != sql_branch: if not igit.workspace_is_clean(): raise exception.FlowException(u'项目的工作空间有尚未保存的修改,请先执行git commit提交或git clean -fd丢弃。处理后请再次执行sql指令') # 切换分支 ihelper.system('git checkout %s' % sql_branch) # 拉取 igit.pull() base_dir = info['dir'] if 'sql_dir' in info: rel_dir = info['sql_dir'] else: rel_dir = iconfig.read_config('system', 'sql_dir') dirs.append((proj, ihelper.real_path(str(base_dir).rstrip('/') + '/' + rel_dir))) if iglobal.PROJECT != old_proj: Extra.cd([old_proj]) sql_file_suffixes = [ele.lstrip('.') for ele in str(iconfig.read_config('system', 'sql_file_suffix')).split('|')] if not dirs: return files = [] for proj, sql_path in dirs: if not sql_path or not os.path.exists(sql_path): continue # 获取文件夹下所有的sql文件 for f in os.listdir(sql_path): f = sql_path + f if not os.path.isfile(f): continue if f.split('.')[-1] in sql_file_suffixes: files.append(f) if not files: iprint.info(u'本次迭代没有sql需要执行') return # 排序 def __isort(x, y): """ :type x: str :type y: str :return: """ sp_date = isprint.get_date_from_sprint(iglobal.SPRINT).split('-') year = sp_date[0] month = sp_date[1] x = os.path.basename(x) y = os.path.basename(y) if month == '12' and x.startswith('01'): x = str(int(year) + 1) + x else: x = year + x if month == '12' and y.startswith('01'): y = str(int(year) + 1) + y else: y = year + y if x < y: return -1 return 1 if x > y else 0 files.sort(__isort) print iprint.warn(u'以下sql需要发布:') for f in files: iprint.info(' ' + os.path.basename(f)) print out_file = iglobal.BASE_DIR + '/runtime/' + iglobal.SPRINT + '.sql' if ihelper.confirm(u'是否导出sql?') == 'y': out_handler = open(out_file, 'w') out_handler.write('set names utf8;\n') for f_name in files: f_handler = open(f_name, 'r') out_handler.write('\n\n-- ----------------------------------- %s -----------------------------------\n' % os.path.basename(f_name)) out_handler.write(f_handler.read()) f_handler.close() out_handler.close() print iprint.ok(u'已写入到%s中' % out_file) else: return