亲宝软件园·资讯

展开

python自动更新

烟花散尽13141 人气:0

前言

项目越来越多,版本管理越来越麻烦,在项目上我使用 maven version 来进行版本管理。主要还是在分布式项目中模块众多的场景中使用,毕竟各个模块对外的版本需要保持统一。

关于这个插件如何使用呢?也是非常的简单。只需要在maven视图中进行设置版本号即可将分模块项目的版本进行升级了。

除了idea插件外,maven本身也提供了一个版本管理工具 versions-maven-plugin 。 具体用法以后有机会在赘述。

自定义实现版本更新

SHELL 实现

之前用SHELL 实现了自动更新置顶项目的版本号为最新日期后缀。虽然使用起来没发现有什么BUG, 但是感觉代码实现上还是很弱智的。

# 该脚本主要用来升级发包期间修改各服务版本
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 "未知参数"
        exit 1;;
    esac
done
echo "开始修改版本号"
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 具体行号:$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}

为什么使用SHELL

python实现

文件思考

常见的 XML 编程接口有 DOM 和 SAX,这两种接口处理 XML 文件的方式不同,当然使用场合也不同。

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

### 1.SAX (simple API for XML )
Python 标准库包含 SAX 解析器,SAX 用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。
### 2.DOM(Document Object Model)
将 XML 数据在内存中解析成一个树,通过对树的操作来操作XML。
### 3.ElementTree(元素树)

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

xml.etree.ElementTree

官网直通车

基于事件和基于文档的APID来解析XML,可以使用XPath表达式搜索已解析的文件,具有对文档的增删改查的功能,该方式需要注意大xml文件,因为是一次性加载到内存,所以如果是大xml文件,不推荐使用该模块解析,应该使用sax方式

不能说最好只能说他是合适的工具,因为 pom.xml 文件不会很大的。ElementTree 通过 XPath 进行节点选择,所以关于xml 节点查找我们可以参考 xpath 语法即可。

<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提供了针对stirng bean list 等判断的操作。不用我们在详细的判断了 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>
        <!-- 提供了针对list 等判断的操作。不用我们在详细的判断了 -->
        <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>
        <!-- 通过反射获取标有注解的类 -->
        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.10</version>
        </dependency>
    </dependencies>   
</project>

上面的 pom.xml 摘自于 com.github.zxhTom 的 bottom 项目中。里面的恰好出现了注释,方便我们后期测试。

解析xml

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

print(tree)

查看pom.xml所有节点标签名称

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.iter():
    print(node.tag)

读取xml中dependency我想看下所有的 dependency 标签,只有这样我才能够匹配是否是我需要的那个maven坐标。

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)
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 的版本号

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)

保存xml

说了这么多,还记得我们一开始的任务吗,没错就是修改掉pom.xml 中指定jar的版本号。这里就将 com.alibaba.fastjson的版本号升级为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')

API追踪

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

上述提到了三个问题都是很常见的问题,因为我们打开 /Lib/xml/etree/ElementTree.py 源码就能够看到在写会 xml 文件的时候我们一共有7个参数可选,其中第一个self 没啥好说的。

属性作用
file_or_filename文件
encoding输出的编码格式;默认US-ASCII
xml_declaration将XML声明添加到文件中: True添加;False不添加;None在非US-ASCII 或 UTF-8 或 Unicode时添加; 默认None
default_namespace默认的命名空间
methodxml、 html 、 text。默认 xml
short_empty_elements空内容的标签时的处理

修改xml后节点多了

前缀ns0很明显是我们没有指定输出的默认命名空间导致程序自动生成一个前缀。

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

当我们指定了命名空间,这个时候再查看下文件节点的前缀问题就解决了。

中文乱码

中文乱码就是我们没有指定编码格式。大家都知道默认的 US-ASCII 都是人家老外的东西,我们国内想正常使用肯定还是需要 UTF-8 的。

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

这里我也就不截图了,笔者亲测是可以解决中文乱码的问题的。

标准化xml

这不算个问题,不知道你有没有发现上面我提供的 pom.xml 严格意义上来说不是一个标准的 xml 文件,就好比你上学不带红领巾就不是一个标准学生一样,上面的pom.xml 确实了xml的标准开头申明。不过没关系我们在wirte的时候注意到有一个参数 xml_declaration 就是控制是否生成标准申明的。

修改xml后原来的注释丢了

关于注释丢了这种问题,怎么说呢?无关紧要吧但是往往注释是进行解释说明的,为了追求完美我还是希望能够将注释保留下来。关于注释的问题我们还得简单查看下源码说明。

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

parse 对应的就是 ElementTree 的源码中 parse 中。

到了这里我们应该不难看出,在渲染的时候主要是通过 TreeBuilder 进行渲染的,其中 CommentHandler 就是 TreeBuilder.comment 进行的。那么我们继续查看下 TreeBuilder 的源码来查看为什么默认的 parser 没有保留下注释。

class CommentedTreeBuilder (ET.TreeBuilder):
    def comment(self,data):
        self.start(ET.Comment,{})
        self.data(data)
        self.end(ET.Comment)
parser = ET.XMLParser(target=CommentedTreeBuilder())
tree = ET.parse(xml_path,parser=parser)

获取不到子节点

就的版本是 getchildren , 但是在新版本中直接废弃了这个方法。而在新版本中是通过 iter(tag) 进行创建迭代器的。但tag=None或者 * 表示所有子孙节点,其他的情况就只查找指定tag 名称的集合。

优雅解析带命名空间的xml

还记得我们是如何解析获取到 pom.xml 中的标签的。

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

这种方式我只想说NO , 每次在通过xpath 定位节点都需要添加前缀,这简直是个噩梦。

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)

总结

文件dependency数量
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

其他说明

参考文章

python3去除注释

elementtree中文文档

加载全部内容

相关教程
猜你喜欢
用户评论