利用gitee的代码仓的功能进行软件的OTA升级
0 简介
需要实现exe文件发行后,需要进行版本升级,文件复制工作不方便,需要通过服务器的方式对软件进行更新。
因此本文通过gitee的代码仓作为服务器,实现exe的OTA升级。
1 配置文件
需要创建一个如下的ini文件,做一个本地化信息部署,以及避免后续升级产生不必要的问题。
[Version]
major = ****
owner = ****
repo = *****
issue_number = *****
access_token = *****
path = *****
model = 1
model 表示调用方式
path 文件地址
major 代表版本号,通过这个与gitee上的信息交互。
ower 、repo 以及 issue_numer 根据gitee的API网址的要求获取。
access_token 通过个人设置里面的私人令牌获取
2. 获取代码仓的压缩包
2.1 获取配置文件
获取软件地址
config = configparser.ConfigParser()
# 读取INI文件
config.read('./lib/version.ini')
self.softPath = config.get('Version', 'path')
self.modelStart = config.get('Version', 'model')
if self.modelStart == 2: # 更新软件自己启用,非调用
current_path = os.getcwd()
self.softPath = os.path.dirname(current_path)
获取其他配置信息
"""版本信息,版本号及gitee上用户名"""
# 创建ConfigParser对象
self.config = configparser.ConfigParser()
# 读取INI文件
self.config.read(f'{self.softPath}/lib/version.ini')
# 获取gitee的账户名及token
owner = self.config.get('Version', 'owner')
repo = self.config.get('Version', 'repo')
access_token = self.config.get('Version', 'access_token')
2.2 下载代码仓的压缩包
# 设置全局变量,headers 和 access_token
headers = {'Content-Type': 'application/json;charset=utf-8'}
zipball_url = f"https://gitee.com/api/v5/repos/{owner}/{repo}/zipball?access_token={access_token}"
response = requests.get(zipball_url, headers=headers, stream=True)
if response.status_code == 200:
# 处理二进制流,例如保存到文件
with open(f'{self.softPath}/upGrade/upGrade.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=1024):
f.write(chunk)
print("Zipball downloaded successfully.")
print(f"Failed to download zipball. Status code: {response.status_code}")
2.3 解压压缩包
解压下载的代码仓的压缩包
def extract_zipfile(self):
# ZIP文件路径
zip_file_path = f'{self.softPath}/upGrade/upGrade.zip'
# 解压目标目录
extract_to_path = f'{self.softPath}/upGrade/upGrade'
# 使用with语句确保文件正确关闭
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
# 解压所有文件
zip_ref.extractall(extract_to_path)
print(f"Files extracted to: {extract_to_path}")
return extract_to_path # 返回解压文件的路径
因为代码仓的文件在线上传要求文件小于10MB,因此对文件进行了分卷压缩,以下为分卷解压的方式,只需要调用函数 sort_main 即可。
"""
解压分卷的zip文件。
"""
def sort_files_by_extension(self, files):
"""根据文件扩展名排序文件"""
def key_function(file_path):
# 获取文件路径的后缀名,以数字作为排序键
return int(file_path.split('.')[-1].replace('z', ''))
# 使用自定义的排序函数进行排序
sorted_files = sorted(files, key=key_function)
return sorted_files
def get_files_with_order(self, folder_path):
"""获取分卷文件列表,并排序"""
files = []
for file_name in os.listdir(folder_path):
if re.match(r'.+\.zip\.\d{3}$', file_name):
files.append(os.path.join(folder_path, file_name))
return self.sort_files_by_extension(files)
def merge_files(self, input_files, output_file):
# self.message.emit(str(input_files))
"""合并分卷文件"""
with open(output_file, 'wb') as merged_file:
i = 0
for input_file in input_files:
with open(input_file, 'rb') as f:
# self.message.emit(str(f.read()))
merged_file.write(f.read())
i += 1
# self.newText.emit([f"解压文件进度:{int(50 + i/len(input_file)*20)} %", 50 + i/len(input_file)*20]) # 进度条
def extract_zip(self, zip_file, extract_dir):
"""解压ZIP文件"""
# 确保目标目录存在
os.makedirs(extract_dir, exist_ok=True)
# 获取ZIP文件中的文件总数
with zipfile.ZipFile(zip_file) as zip_ref:
total_files = len(zip_ref.infolist())
for file in zip_ref.infolist():
zip_ref.extract(file, extract_dir)
# pbar.update(1)
def sort_main(self, extract_to_path):
self.newText.emit([f"解压文件进度:40 %", 40]) # 进度条
# 设置包含分卷文件的文件夹路径和解压目标目录
input_dir = f'{extract_to_path}/chat-ai-master' # 这个根据压缩包名称设置
output_dir = self.softPath
# 合并分卷文件
tmp_file = f'{self.softPath}/upGrade/merged.zip'
input_files = self.get_files_with_order(input_dir)
self.merge_files(input_files, tmp_file)
# 解压合并后的ZIP文件
self.extract_zip(tmp_file, output_dir)