欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python自動(dòng)更新pom文件的方法

 更新時(shí)間:2022年09月20日 09:18:54   作者:煙花散盡13141  
這篇文章主要介紹了python自動(dòng)更新pom文件的方法,本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

項(xiàng)目越來(lái)越多,版本管理越來(lái)越麻煩,在項(xiàng)目上我使用 maven version 來(lái)進(jìn)行版本管理。主要還是在分布式項(xiàng)目中模塊眾多的場(chǎng)景中使用,畢竟各個(gè)模塊對(duì)外的版本需要保持統(tǒng)一。

關(guān)于這個(gè)插件如何使用呢?也是非常的簡(jiǎn)單。只需要在maven視圖中進(jìn)行設(shè)置版本號(hào)即可將分模塊項(xiàng)目的版本進(jìn)行升級(jí)了。

除了idea插件外,maven本身也提供了一個(gè)版本管理工具 versions-maven-plugin 。 具體用法以后有機(jī)會(huì)在贅述。

自定義實(shí)現(xiàn)版本更新

  • 作為一個(gè)專業(yè)懶人,我還是覺(jué)得idea的插件不夠智能,確切的說(shuō)還不夠自動(dòng)化。之前我已經(jīng)動(dòng)手實(shí)現(xiàn)了防 jenkins 自動(dòng)打包上傳啟動(dòng)服務(wù)的腳本的功能了,難道提交合并代碼這種簡(jiǎn)單的事情還需要我自己處理嗎。不得不承認(rèn)代碼沖突了的確還是需要認(rèn)為干涉的,但是在平時(shí)開發(fā)中有多少概率會(huì)發(fā)生代碼沖突呢?我們都是分工合作基本上代碼沖突概率很低。
  • 關(guān)于代碼提交,自己分支如何合并到dev, 如何保證自己分支代碼最新等等這些場(chǎng)景我們只需要通過(guò)腳本來(lái)進(jìn)行自動(dòng)化操作就行了。針對(duì)這些功能場(chǎng)景我大概寫了兩個(gè)腳本 batfhmerge.shbatchgrade.sh 就搞定了。
  • 然而我想說(shuō)的是關(guān)于項(xiàng)目的版本如何升級(jí)。上面也提到了我們分工合作就必然涉及到別人使用你的jar的場(chǎng)景了。你可以使用 SNAPSHOT 版本來(lái)保證別人拉取到你最新的功能代碼,但是有些公司會(huì)要求使用非 SNAPSHOT 版本進(jìn)行管理也就是正式版本,這樣做的好處就是容易找到之前的版本代碼功能。

SHELL 實(shí)現(xiàn)

之前用SHELL 實(shí)現(xiàn)了自動(dòng)更新置頂項(xiàng)目的版本號(hào)為最新日期后綴。雖然使用起來(lái)沒(méi)發(fā)現(xiàn)有什么BUG, 但是感覺(jué)代碼實(shí)現(xiàn)上還是很弱智的。

# 該腳本主要用來(lái)升級(jí)發(fā)包期間修改各服務(wù)版本
FILEPATH=$1
GROUPID=$2
ARTIFACTID=$3
FILENAME=$4
while getopts ":f:g:a:" opt
do
    case $opt in
        f)
        FILENAME=$OPTARG
        echo "您輸入的文件配置:$FILENAME"
        ;;
        g)
        GROUPID=$OPTARG
        echo "您輸入的groupid配置:$GROUPID"
        ;;
        a)
        ARTIFACTID=$OPTARG
        echo "您輸入的artifactid配置:$ARTIFACTID"
        ;;
        ff)
        FILENAME=$OPTARG
        echo "您輸入的帶修改文件為:$FILENAME"
        ;;
        ?)
        echo "未知參數(shù)"
        exit 1;;
    esac
done
echo "開始修改版本號(hào)"
NEWCONTENT=1.2.5.$(date +%Y%m%d)
LINE=`cat ${FILENAME} | grep -n -A 1 '<groupId>'"${GROUPID}"'<\/groupId>'| grep -n '<artifactId>'"${ARTIFACTID}"'<\/artifactId>' | awk -F "[:-]+" '{print $2}'`
echo 具體行號(hào):$LINE
if [[ -z $LINE  ]]
then
    echo 未匹配
    exit
fi
VERSIONOLDCONTENT=`sed -n ''"$((LINE+1))"'p' ${FILENAME}| grep '[0-9a-zA-Z\.-]+' -Eo | sed -n '2p'`
echo ${VERSIONOLDCONTENT}
#gsed -i  ''"$((LINE+1))"'c\'"${NEWCONTENT}"'' pom.xml
sed -i "" ''"$((LINE+1))"'s/'"${VERSIONOLDCONTENT}"'/'"${NEWCONTENT}"'/' ${FILENAME}
  • 其實(shí)邏輯很簡(jiǎn)單,主要就是尋找 groupIdartifactId ,最后確定好 version 對(duì)應(yīng)的行號(hào)將最新的日期后綴版本進(jìn)行填充進(jìn)去。
  • 填充呢肯定需要三劍客中的 SED 進(jìn)行操作,那就需要先獲取到以前的舊版本,然后進(jìn)行替換操作。

為什么使用SHELL

  • shell腳本作為后端程序猿必備技能選擇他進(jìn)行實(shí)現(xiàn)也是為了溫故下shell的知識(shí)。基本上腳本離不開三劍客,換句話說(shuō)會(huì)了三劍客你就可以做好半個(gè)運(yùn)維工作了。
  • 有了這個(gè)腳本我每次在功能開發(fā)完成之后,會(huì)通過(guò)SHELL腳本進(jìn)行版本升級(jí)以及自己分支合并到dev分支,這樣方便別人獲取到最新的代碼。

python實(shí)現(xiàn)

  • SHELL腳本定制度很高,很難做到自動(dòng)的兼容功能。比如上面我們?cè)诙ㄎ话臅r(shí)候是通過(guò)grep進(jìn)行定位的,正常情況下應(yīng)該是沒(méi)什么問(wèn)題的,但是當(dāng)pom.xml 出現(xiàn)被注釋的同名坐標(biāo)時(shí)或者說(shuō)名稱存在其他相似度的情況下很難保證SHELl腳本還能夠正確的解析出來(lái)。
  • 除此之外還有一個(gè)重要的原因就是SHELL腳本很難在windows 運(yùn)行,為了能夠兼顧到windows電腦我決定用python 進(jìn)行重新實(shí)現(xiàn)該功能。

文件思考

  • 與SHELL不同的是 python處理需要考慮文件格式的問(wèn)題。SHELL中不管什么格式都是通過(guò)三劍客進(jìn)行定位處理,這是他的優(yōu)點(diǎn)也是他的缺點(diǎn)。
  • 首先我們得知道 pom.xml 文件他是一個(gè) XML 格式的文件, XML=eXtensible Markup Language 。即是一種可擴(kuò)展的標(biāo)記語(yǔ)言。它與 JSON 一樣主要用來(lái)存儲(chǔ)和傳輸數(shù)據(jù)。在之前的Springboot章節(jié)中我們也實(shí)現(xiàn)了如何實(shí)現(xiàn)接口傳遞 XML 數(shù)據(jù)結(jié)構(gòu)。

常見(jiàn)的 XML 編程接口有 DOM 和 SAX,這兩種接口處理 XML 文件的方式不同,當(dāng)然使用場(chǎng)合也不同。

Python 有三種方法解析 XML,SAX,DOM,以及 ElementTree:

### 1.SAX (simple API for XML )
Python 標(biāo)準(zhǔn)庫(kù)包含 SAX 解析器,SAX 用事件驅(qū)動(dòng)模型,通過(guò)在解析XML的過(guò)程中觸發(fā)一個(gè)個(gè)的事件并調(diào)用用戶定義的回調(diào)函數(shù)來(lái)處理XML文件。
### 2.DOM(Document Object Model)
將 XML 數(shù)據(jù)在內(nèi)存中解析成一個(gè)樹,通過(guò)對(duì)樹的操作來(lái)操作XML。
### 3.ElementTree(元素樹)

而我所采用的就是最后一種方式 ElementTree 。

xml.etree.ElementTree

官網(wǎng)直通車

  • ElementTree 在 python3中已經(jīng)作為標(biāo)準(zhǔn)庫(kù)存在了,所以這里不需要我們額外的安裝。

基于事件和基于文檔的APID來(lái)解析XML,可以使用XPath表達(dá)式搜索已解析的文件,具有對(duì)文檔的增刪改查的功能,該方式需要注意大xml文件,因?yàn)槭且淮涡约虞d到內(nèi)存,所以如果是大xml文件,不推薦使用該模塊解析,應(yīng)該使用sax方式

不能說(shuō)最好只能說(shuō)他是合適的工具,因?yàn)?pom.xml 文件不會(huì)很大的。ElementTree 通過(guò) XPath 進(jìn)行節(jié)點(diǎn)選擇,所以關(guān)于xml 節(jié)點(diǎn)查找我們可以參考 xpath 語(yǔ)法即可。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.github.zxhTom</groupId>
    <artifactId>bottom</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>bottom</name>
    <url>http://maven.apache.org</url>
    <description>最底層的繁瑣封裝</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <log4j2.version>2.10.0</log4j2.version>
    </properties>

    <dependencies>
        <!-- 20180927提供了針對(duì)stirng bean list 等判斷的操作。不用我們?cè)谠敿?xì)的判斷了 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>
        <!-- 提供了針對(duì)list 等判斷的操作。不用我們?cè)谠敿?xì)的判斷了 -->
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
        <!-- jsonobeject jar包依賴 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>
        <!-- 日志記錄 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <!-- 通過(guò)反射獲取標(biāo)有注解的類 -->
        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.10</version>
        </dependency>
    </dependencies>   
</project>

上面的 pom.xml 摘自于 com.github.zxhTom 的 bottom 項(xiàng)目中。里面的恰好出現(xiàn)了注釋,方便我們后期測(cè)試。

解析xml

import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)

print(tree)

  • 實(shí)際有效的內(nèi)容就是 ET.parse 即可解析出來(lái) xml 。

查看pom.xml所有節(jié)點(diǎn)標(biāo)簽名稱

import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)
# 根據(jù)tree進(jìn)行遍歷
for node in tree.iter():
    print(node.tag)

讀取xml中dependency我想看下所有的 dependency 標(biāo)簽,只有這樣我才能夠匹配是否是我需要的那個(gè)maven坐標(biāo)。

import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)
# tree遍歷
for node in tree.findall('.//dependency'):
    print(node.tag)
  • 上述代碼很明顯是錯(cuò)誤的,因?yàn)槲覀儓?zhí)行腳本后沒(méi)有任何的輸出,至于為什么是這樣呢?你可以翻到上一節(jié)就可以看到我們?cè)诖蛴∷泄?jié)點(diǎn)標(biāo)簽名稱的時(shí)候前面好像都多了一串地址。
  • 這個(gè)地址就是 pom.xml 中的命名空間,在跟節(jié)點(diǎn) project 標(biāo)簽中設(shè)置的xmlns 屬性。至于為什么需要這個(gè)呢?每個(gè)xml 標(biāo)簽內(nèi)容都是自定義的,比如你可以將dependency用來(lái)做版本號(hào)的作用,只要你自己解析的時(shí)候注意就行了。而maven中將dependency作為引入坐標(biāo)的概念,每個(gè)人的想法不一,所以引入命名空間,在指定的命名空間中標(biāo)簽的作用是唯一的,這就是 xmlns 存在的意義。
import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)
# tree遍歷
for node in tree.findall('.//{http://maven.apache.org/POM/4.0.0}dependency'):
    print(node.tag)

讀取com.alibaba.fastjson 的版本號(hào)

  • 通過(guò)上面的內(nèi)容我們知道在定位節(jié)點(diǎn)時(shí)候需要加入命名空間。
  • 首先我們知道 com.alibaba.fastjson 的版本號(hào)是 1.2.28
import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)
# tree遍歷
for node in tree.findall('.//{http://maven.apache.org/POM/4.0.0}dependency'):
    groupIdNode=node.find('.{http://maven.apache.org/POM/4.0.0}groupId')
    artifactNode=node.find('.{http://maven.apache.org/POM/4.0.0}artifactId')
    if(artifactNode.text=='fastjson' and groupIdNode.text=='com.alibaba'):
        print(node.find('.{http://maven.apache.org/POM/4.0.0}version').text)
  • 通過(guò) python3 upgrade.py 即可打印出 1.2.28 。

保存xml

說(shuō)了這么多,還記得我們一開始的任務(wù)嗎,沒(méi)錯(cuò)就是修改掉pom.xml 中指定jar的版本號(hào)。這里就將 com.alibaba.fastjson的版本號(hào)升級(jí)為1.2.29 吧。

import xml.etree.ElementTree as ET
with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)
# tree遍歷
for node in tree.findall('.//{http://maven.apache.org/POM/4.0.0}dependency'):
    groupIdNode=node.find('.{http://maven.apache.org/POM/4.0.0}groupId')
    artifactNode=node.find('.{http://maven.apache.org/POM/4.0.0}artifactId')
    if(artifactNode.text=='fastjson' and groupIdNode.text=='com.alibaba'):
        node.find('.{http://maven.apache.org/POM/4.0.0}version').text='1.2.29'
tree.write('pom.xml')
  • 修改還是很容易的,我們只需要將node.text進(jìn)行重新賦值就行了。但是經(jīng)過(guò)對(duì)比我發(fā)現(xiàn)保存后的 pom.xml 好像并不是只改了version標(biāo)簽的內(nèi)容。
    • 標(biāo)簽多了ns0前綴。
    • 中文亂碼
    • 注釋丟失

API追蹤

def write(self, file_or_filename,
              encoding=None,
              xml_declaration=None,
              default_namespace=None,
              method=None, *,
              short_empty_elements=True):

上述提到了三個(gè)問(wèn)題都是很常見(jiàn)的問(wèn)題,因?yàn)槲覀兇蜷_ /Lib/xml/etree/ElementTree.py 源碼就能夠看到在寫會(huì) xml 文件的時(shí)候我們一共有7個(gè)參數(shù)可選,其中第一個(gè)self 沒(méi)啥好說(shuō)的。

屬性作用
file_or_filename文件
encoding輸出的編碼格式;默認(rèn)US-ASCII
xml_declaration將XML聲明添加到文件中: True添加;False不添加;None在非US-ASCII 或 UTF-8 或 Unicode時(shí)添加; 默認(rèn)None
default_namespace默認(rèn)的命名空間
methodxml、 html 、 text。默認(rèn) xml
short_empty_elements空內(nèi)容的標(biāo)簽時(shí)的處理

修改xml后節(jié)點(diǎn)多了

前綴ns0很明顯是我們沒(méi)有指定輸出的默認(rèn)命名空間導(dǎo)致程序自動(dòng)生成一個(gè)前綴。

tree.write('pom.xml',default_namespace='http://maven.apache.org/POM/4.0.0')

當(dāng)我們指定了命名空間,這個(gè)時(shí)候再查看下文件節(jié)點(diǎn)的前綴問(wèn)題就解決了。

中文亂碼

中文亂碼就是我們沒(méi)有指定編碼格式。大家都知道默認(rèn)的 US-ASCII 都是人家老外的東西,我們國(guó)內(nèi)想正常使用肯定還是需要 UTF-8 的。

tree.write('pom.xml',default_namespace='http://maven.apache.org/POM/4.0.0',encoding='UTF-8')

這里我也就不截圖了,筆者親測(cè)是可以解決中文亂碼的問(wèn)題的。

標(biāo)準(zhǔn)化xml

這不算個(gè)問(wèn)題,不知道你有沒(méi)有發(fā)現(xiàn)上面我提供的 pom.xml 嚴(yán)格意義上來(lái)說(shuō)不是一個(gè)標(biāo)準(zhǔn)的 xml 文件,就好比你上學(xué)不帶紅領(lǐng)巾就不是一個(gè)標(biāo)準(zhǔn)學(xué)生一樣,上面的pom.xml 確實(shí)了xml的標(biāo)準(zhǔn)開頭申明。不過(guò)沒(méi)關(guān)系我們?cè)趙irte的時(shí)候注意到有一個(gè)參數(shù) xml_declaration 就是控制是否生成標(biāo)準(zhǔn)申明的。

修改xml后原來(lái)的注釋丟了

關(guān)于注釋丟了這種問(wèn)題,怎么說(shuō)呢?無(wú)關(guān)緊要吧但是往往注釋是進(jìn)行解釋說(shuō)明的,為了追求完美我還是希望能夠?qū)⒆⑨尡A粝聛?lái)。關(guān)于注釋的問(wèn)題我們還得簡(jiǎn)單查看下源碼說(shuō)明。

with open('pom.xml', 'tr', encoding='utf-8') as rf:
    tree = ET.parse(rf)

parse 對(duì)應(yīng)的就是 ElementTree 的源碼中 parse 中。

到了這里我們應(yīng)該不難看出,在渲染的時(shí)候主要是通過(guò) TreeBuilder 進(jìn)行渲染的,其中 CommentHandler 就是 TreeBuilder.comment 進(jìn)行的。那么我們繼續(xù)查看下 TreeBuilder 的源碼來(lái)查看為什么默認(rèn)的 parser 沒(méi)有保留下注釋。

  • 最終就是 _handle_single 方法進(jìn)行創(chuàng)建節(jié)點(diǎn)的,comment中創(chuàng)建節(jié)點(diǎn)的工廠類是_comment_factory , 而這個(gè)類就是產(chǎn)生 Comment 。 因?yàn)閕nsert_comments=False , 所以默認(rèn)的TreeBuilder對(duì)于注釋只會(huì)產(chǎn)生一個(gè)空的Comment對(duì)象,所以我們通過(guò)ET.write出來(lái)的pom.xml中關(guān)于注釋部分就是空白代替,就是因?yàn)檫@個(gè)原因。
  • 到了這里想要保留注釋也就變得非常簡(jiǎn)單了,那么我們只需要修改TreeBuilder就可以了。
class CommentedTreeBuilder (ET.TreeBuilder):
    def comment(self,data):
        self.start(ET.Comment,{})
        self.data(data)
        self.end(ET.Comment)
  • 上述代碼類似于 Java中繼承了 TreeBuilder 并且重寫了 comment方法。主要的邏輯就是開頭一個(gè)注釋標(biāo)簽屬性為空,結(jié)尾是一個(gè)注釋標(biāo)簽結(jié)尾,中間的內(nèi)容是我們注釋的內(nèi)容,所以綜上就是保留下來(lái)注釋。
  • 重寫了類之后我們還需要在ET中指定我們自定義的TreeBuilder 。
parser = ET.XMLParser(target=CommentedTreeBuilder())
tree = ET.parse(xml_path,parser=parser)
  • 構(gòu)建好tree之后其他就是一樣的操作,最終倒出來(lái)的文件就是我們保留注釋的xml 了。

獲取不到子節(jié)點(diǎn)

就的版本是 getchildren , 但是在新版本中直接廢棄了這個(gè)方法。而在新版本中是通過(guò) iter(tag) 進(jìn)行創(chuàng)建迭代器的。但tag=None或者 * 表示所有子孫節(jié)點(diǎn),其他的情況就只查找指定tag 名稱的集合。

優(yōu)雅解析帶命名空間的xml

還記得我們是如何解析獲取到 pom.xml 中的標(biāo)簽的。

# tree遍歷
for node in tree.findall('.//{http://maven.apache.org/POM/4.0.0}dependency'):
    print(node.tag)

這種方式我只想說(shuō)NO , 每次在通過(guò)xpath 定位節(jié)點(diǎn)都需要添加前綴,這簡(jiǎn)直是個(gè)噩夢(mèng)。

ns = {'real_mvn': 'http://maven.apache.org/POM/4.0.0',
      'vistual': 'http://characters.zxhtom.com'}
# tree遍歷
for node in tree.findall('.//real_mvn:dependency',ns):
    print(node.tag)

總結(jié)

  • 本文主要是通過(guò)腳本實(shí)現(xiàn)pom.xml 的版本升級(jí)功能。SHELL通過(guò)三劍客定位到指定坐標(biāo)進(jìn)行版本更新,缺點(diǎn)是可能不兼容注釋同內(nèi)容的坐標(biāo),優(yōu)點(diǎn)是修改內(nèi)容范圍小,不會(huì)造成大影響
  • 而python實(shí)現(xiàn)的xml文件修改。他的優(yōu)點(diǎn)是能夠精準(zhǔn)定位不會(huì)產(chǎn)生錯(cuò)誤定位問(wèn)題且支持注釋內(nèi)容保留,缺點(diǎn)是不適合操作大文件。
文件dependency數(shù)量
knife4j-spring-ui-1.9.6.pom0
spring-context-support-1.0.6.pom3
spring-core-5.1.7.RELEASE.pom10
springfox-swagger-common-3.0.0.pom11

其他說(shuō)明

參考文章

python3去除注釋

elementtree中文文檔

到此這篇關(guān)于python自動(dòng)更新pom文件的文章就介紹到這了,更多相關(guān)python自動(dòng)更新內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論