Python常用脚本工具

工欲善其事,必先利其器。

脚本可解放劳动力,自觉学习一门脚本开发很是重要。以下是为工作过程中通过 Python 脚本减少手动工作量的场景以及工具实现代码。后续还会继续更新。

批量clone项目以及更新远程项目地址

场景:因为项目中用到了模块化开发(安卓),整个项目分成了十几个子模块,然后前端时间公司 git 要进行迁移,这么多模块手动一个个更新、切换分支以及更换远程地址肯定是很麻烦,使用脚本批量操作就是一件很方便的事,还可以将脚本分享给其他同事使用。当然 shell 脚本更容易,选择 python 主要是熟并且我司电脑均是自带 python 环境。比较废话,以下是为实现代码:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 一键clone所有模块工程、批量修改仓库地址

# 使用说明:
# 1)配置 REPO_CONFIGS 包括项目路径,老仓库地址(可不进行配置),新仓库地址(注意配置项一一对应);
# 2)将本脚本放到项目同级目录下;
# 3)执行脚本:python git_repo.py ;
# 4) 也可用 shell 脚本,更方便。
# 5) python 2.7 或 3 均可使用。
# 6) 最好所有的模块都放在同一目录,不在同一目录,dir 配置则需使用相对或绝对路径。
# 7) 执行脚本前,先 stash 或 commit 当前分支修改。因为脚本会直接先切到 develop 进行操作。

import re
import os

# Python通过prettytable模块将输出内容如表格方式整齐输出,python本身并不内置,需要独立安装该第三方库。
from prettytable import PrettyTable

OLD_REPO = 'gitAddr:gitGroup/%s.git' # 这里修改为旧的 gitAddr 和 gitGroup 名
NEW_REPO = 'gitAddr:gitGroup/%s.git' # 这里修改为新的 gitAddr 和 gitGroup 名

PROJECT_DIRS = [
         'module1', 'module2', 'module3'
         ]                                 # 这里修改为自己的模块名列表

# 通过 prettytable 模块按表格样式输出内容。安装第三方库:pip3 install PrettyTable
def printProjectDir(projectDirs):
    x = PrettyTable(["olderRepo", "projectName", "newerRepo"])
    x.align["projectName"] = "1"
    x.padding_width = 1  # 填充宽度
    for projectDir in projectDirs:
        oldRepo = NAPOS_OLD_REPO % (projectDir)
        newRepo = NAPOS_NEW_REPO % (projectDir)
        x.add_row([oldRepo, projectDir, newRepo])
        # print(projectDir, oldRepo, newRepo)    

    print(x)    
    
def addNewBranch(branchName, projectDirs):
    for projectDir in projectDirs:
        existed = os.path.exists(projectDir)
        print(projectDir, existed)
        if (existed):
            os.chdir(projectDir)
            executeCmd('git checkout -b %s' % (branchName))
            executeCmd('git push origin %s' % (branchName))
            os.chdir('..')

def executeCmd(cmd):
    return os.system(cmd) # 返回值为0,执行命令成功

# clone 所有模块项目
def batchCloneRepo(repoAddr, projectDirs):
    for projectDir in projectDirs:
        # 当前目录不存在才clone
        if (os.path.exists(projectDir)):
            print('%s project has existed !' % (projectDir))
        else:
            repo = repoAddr % (projectDir)
            clone_res = executeCmd('git clone ' + repo)
            if (clone_res != 0):
                print('%s clone failed !' % (projectDir))
            else:
                print('%s clone successed !' % (projectDir))                
            
# 批量修改所有模块仓库地址(适用于不同group下的仓库迁移,需配置dir, newRepo字典数据)
# def batchSetRemoteUrl(configs):
#   for repoDict in configs:
#       setRemoteUrl(repoDict['dir'], repoDict['newRepo'])

# 批量更新所有模块 develop 分支代码
def batchFetch(repoAddr, projectDirs):
    for projectDir in projectDirs:
        existed = os.path.exists(projectDir)
        # print(projectDir, existed)
        if (existed):
            newRepo = repoAddr % (projectDir) 
            print(newRepo)
            os.chdir(projectDir)
            executeCmd('git checkout develop')
            executeCmd('git fetch')
            executeCmd('git merge')
            executeCmd('git branch --set-upstream-to origin/develop develop')
            os.chdir('..')
        else:
            print('%s project not existed !' % (projectDir))


# 批量修改所有模块仓库地址(适用于属于同一个group下的仓库迁移,只需配置 NEW_GROUP)
def batchSetSameGroupRemoteUrl(repoAddr, projectDirs):
    for projectDir in projectDirs:
        existed = os.path.exists(projectDir)
        # print(projectDir, existed)
        if (existed):
            newRepo = repoAddr % (projectDir) 
            print(newRepo)
            setRemoteUrl(projectDir, newRepo)
        else:
            print('%s project not existed !' % (projectDir))

def setRemoteUrl(projectDir, newRepo):
    if (newRepo != ''):
        # 进入到指定目录,执行cd命令无法改变命令行当前目录
        os.chdir(projectDir)

        # 先暂存当前分支修改,再执行切分支等命令
        # 恢复暂存,切换到之前的分支,执行命名:
        # 1)git stash list 查看所有暂存;2)git stash apply stash@{pos} 运用第pos条暂存内容,pos为你之前暂存的内容。
        stash_res = executeCmd('git stash')
        if (stash_res != 0):
            print('%s stash failed !' % (projectDir))

        checkout_res = executeCmd('git checkout develop')
        if (checkout_res != 0):
            print('%s checkout develop failed !' % (projectDir))

        executeCmd('git remote remove origin')
        executeCmd('git remote add origin %s' % (newRepo))
        # 查看远程仓库地址
        # executeCmd('git remote -v')
    
        executeCmd('git fetch')
        upstream_res = executeCmd('git branch --set-upstream-to origin/develop develop')
        if (upstream_res != 0):
            print('%s set-upstream failed !' % (projectDir))
        #  回到上级目录
        os.chdir('..')  

def printRemoteUrl(projectDirs):
    for projectDir in projectDirs:
        existed = os.path.exists(projectDir)
        if (existed):
            os.chdir(projectDir)
            executeCmd('git remote -v')
            os.chdir('..')

if __name__ == '__main__':
    # 批量克隆项目
    # batchCloneRepo(REPO_ADDR, PROJECT_DIRS)

    # 拉老版本的功能代码
    # batchFetch(OLD_REPO, PROJECT_DIRS)

    # 设置老远程仓库地址
    # batchSetSameGroupRemoteUrl(NEW_REPO, MY_DIRS)
    
    # 设置新仓库地址
    # batchSetSameGroupRemoteUrl(NEW_REPO, PROJECT_DIRS)

    # addNewBranch('testBranch', MY_DIRS)

    # 打印远程仓库地址
    # printRemoteUrl(PROJECT_DIRS)

    batchSetSameGroupRemoteUrl(repo, dirs)
查找某个目录下给定的后缀名文件名
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import re
import os

def findFileNamesWithSuffix(myDir, suffix):
    os.chdir(myDir)
    arr = [x for x in os.listdir(myDir) if os.path.isfile(x) 
            and os.path.splitext(x)[1] == suffix]
    new_arr = []        
    for filename in arr:
        name = os.path.splitext(filename)
        new_arr.append(name[0])

    print(new_arr)      

findFileNamesWithSuffix('.', '.podSpec')
筛选json文件中多余键值

场景:一般随着迭代的更新换代,后台肯定保留了很多冗余字段或者兼容字段当前版本没有用到,若后台返回的json串过大,而客户端并不需要这么多字段,造成多余的Json解析时间,有些不好了。以下是为以客户端用到的对象字段生成的 json 串和后台返回的大 json 串对比,筛选出后台多余的字段。

# encoding:utf-8

import json

def readFile(file_path):
    f = open(file_path, 'r')
    content = f.read()
    f.close()
    return content

def readJsonFromFile(filename):
      jsonStr = readFile(filename)   
      return json.loads(jsonStr) 

def excludeAFromB(list_a, list_b):    
    return list(set(list_b).difference(set(list_a)))  # b中有而a中没有的

def excludeDictAFromB(dict_a, dict_b):
    a_keys = list(dict_a.keys())
    b_keys = list(dict_b.keys())    
    return list(set(b_keys).difference(set(a_keys)))  # b中有而a中没有的

def unionList(list_a, list_b):
    return list(set(list_a).union(set(list_b)))

def unionDictKeys(dict_a, dict_b, dict_c):
    a_keys = list(dict_a.keys())
    b_keys = list(dict_b.keys())
    c_keys = list(dict_c.keys())
    return unionList(a_keys, unionList(b_keys, c_keys))
        
def getResult():
    s_json = readJsonFromFile('./server.json')  # 同级目录服务端json文件
    a_json = readJsonFromFile('./android.json') # 同级目录安卓本地json文件
    # i_json = readJsonFromFile('./ios.json')
    # p_json = readJsonFromFile('./pc.json')

    # 求服务器中存在各段不存在的字段
    s_exc_a = excludeDictAFromB(a_json, s_json)
    # s_exc_i = excludeDictAFromB(i_json, s_json)
    # s_exc_p = excludeDictAFromB(p_json, s_json)
    print('server exclude android: ', s_exc_a)
    # print('server exclude ios: ', s_exc_i)
    # print('server exclude pc: ', s_exc_p)

    # 方案二:取三段使用字段取并集对比,缩小范围 
    # # 1. 求三段本地json数据并集
    # union_list = unionDictKeys(a_json, i_json, p_json)
    # print('Union client datas: ', union_list)
    # # 2. 从server json串中排除三端并集数据,为服务器参考字段
    # exclude_list = excludeAFromB(union_list, s_json.keys())
    # print('Server datas: ', exclude_list)

    output = open('./diff.txt', 'w')
    for data in s_exc_a:
        print(data)
        output.write(data + '\n')

getResult()

未完待续。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352