前段時間,獨自接手公司另一個項目組的App(該產(chǎn)品僅存的唯一的一個小伙伴離職了)映屋,本來心里很不情愿苟鸯。因為代碼實在是太古老了,而且經(jīng)過了n手的像我這樣的斷代接收棚点,長期處于半維護狀態(tài)早处,所以我都是一邊看代碼一邊吐槽。并不是說前面的小伙伴的技術(shù)不好瘫析,而是經(jīng)過多年多次流轉(zhuǎn)砌梆,每一代都風(fēng)格迥異就形成了現(xiàn)在這副冗余不堪的樣子默责。
我們自己的App是用當(dāng)前最流行的Jenkins+Git+Gradle持續(xù)集成,但這個App就慘了咸包,你不得不自己打包發(fā)到群里桃序,可想而知多少麻煩,就想著接入接入我們的Jenkins服務(wù)器烂瘫,自動打包媒熊。但是被權(quán)限問題折騰過后,而且這段時間大家都忙著一個超高優(yōu)先級的項目忱反,就先擱置了泛释。
前天就想著為什么不自己寫一套呢。反正有免費的服務(wù)器用温算,那就物盡其用怜校。
首先要實現(xiàn)的功能:
1,自動打包-Python實現(xiàn)
2注竿,文件上傳下載服務(wù)器-Python實現(xiàn)
3茄茁,包列表前端展示-HTML
4,包列表展示和下載移動端實現(xiàn)
經(jīng)過兩天的加班加點巩割,終于實現(xiàn)啦裙顽,先看效果:
移動端apk列表:
前端apk列表:
后端文件服務(wù)核心代碼:
import os
from flask import request, jsonify
from flask import send_from_directory, abort
from flask_restful import Resource, reqparse
from werkzeug.utils import secure_filename
from modules.APKRecord import APKRecordModel
from support.CHelper import get_millisecond, get_file_name
basedir = os.path.abspath(os.path.dirname(__file__))
# set(['jpeg', 'apk'])
ALLOWED_EXTENSIONS = {'apk'}
# 用于判斷文件后綴
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
class APKRecord(Resource):
@staticmethod
def get():
return {"You should have a file_name": 404}, 403
# @staticmethod
# def get(file_name):
# if os.path.isfile(os.path.join('uploadApk', file_name)):
# return send_from_directory('uploadApk', file_name, as_attachment=True)
# abort(404)
@staticmethod
def get(file_name):
if os.path.isfile(os.path.join(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name)):
return send_from_directory(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name, as_attachment=True)
else:
abort(404)
class APKRecordList(Resource):
parser = reqparse.RequestParser()
@staticmethod
def get():
file_dir = os.path.join(basedir, "uploadApk")
if not os.path.exists(file_dir):
os.makedirs(file_dir)
apkList = []
if os.path.exists(file_dir):
for root, dirs, files in os.walk(file_dir):
for file in files:
item = APKRecordModel(file)
apkList.append(item.json())
return jsonify(result='success', data=apkList)
def post(self):
file_dir = os.path.join(basedir, "uploadApk")
if not os.path.exists(file_dir):
os.makedirs(file_dir)
f = request.files['apk_name'] # 從表單的file字段獲取文件,apk_name為該表單的name值
if f and allowed_file(f.filename): # 判斷是否是允許上傳的文件類型
fname = secure_filename(f.filename)
ext = fname.rsplit('.', 1)[1] # 獲取文件后綴
name = get_file_name(fname)
timestamp = get_millisecond()
new_filename = name + '_' + str(timestamp) + '.' + ext # 修改了上傳的文件名加上了 _時間戳
f.save(os.path.join(file_dir, new_filename)) # 保存文件到uploadApk目錄
return {"code": 0, "msg": "upload success", "fileName": new_filename, "fileTime": timestamp}, 201
else:
return {"code": 1001, "msg": "file not allowed"}
這里要注意的一點的是:不同的環(huán)境(比如Mac環(huán)境和Windows環(huán)境)宣谈,這個地址也要改變:
Mac環(huán)境下:
@staticmethod
def get(file_name):
if os.path.isfile(os.path.join('uploadApk', file_name)):
return send_from_directory('uploadApk', file_name, as_attachment=True)
abort(404)
Windows環(huán)境下:
@staticmethod
def get(file_name):
if os.path.isfile(os.path.join(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name)):
return send_from_directory(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name, as_attachment=True)
else:
abort(404)
前端展示:還是用的最簡單jquery
<script>
$.ajax({
url: "/apk/records",
dataType: 'json',
success: function (res) {
res.data.map(item => {
let liNode = document.createElement("li");
liNode.className = "my_record_list_li"
let labelNode = document.createElement("label")
labelNode.className = "my_record_list_label"
let spanNode = document.createElement("span")
spanNode.innerHTML = item.fileTime
labelNode.append(spanNode)
let delNode = document.createElement("a");
delNode.className = "delete_record"
delNode.href = item.downloadUrl
delNode.innerHTML = "下載"
labelNode.append(delNode)
let aNode = document.createElement("a");
aNode.className = "my_record_list_a"
aNode.href = item.downloadUrl
aNode.innerHTML = item.fileName
liNode.append(aNode)
liNode.append(labelNode)
$("#record_list_container").append(liNode)
})
document.getElementById('record_num_value').innerHTML = "共" + res.data.length + "個包"
}
})
</script>
同樣實現(xiàn)了愈犹,通過網(wǎng)頁上傳代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上傳</title>
</head>
<body>
<form id="form1" method="post" action="http://xx.xxxx.xxxx.xxxx:5000/apk/records" enctype="multipart/form-data">
<div>
<input id="file1" type="file" name="apk_name"/>
<input type="submit">提交</input>
</div>
</form>
</body>
</html>
當(dāng)然打包,上傳腳本核心代碼:
# 請求服務(wù)器
def request_url(url, params):
cookies = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler.MultipartPostHandler)
try:
print('request url:' + url)
print('request params:' + str(params))
response = opener.open(url, params)
return response.read()
except Exception as e:
print(str(e))
# 上傳文件到服務(wù)器
def upload_file(url, apkpath):
params = {'username': reinforce_username, 'password': reinforce_password, 'apk': open(apkpath, 'rb'),
'tactics_id': reinforce_tactics_id}
response = request_url(url, params)
data = json.loads(response)
return data
搞定這些東西還是有點成就感的漩怎,感覺應(yīng)該可以寫成gradle腳本嗦嗡,甚至生成gradle插件,這樣服務(wù)器就沒必要配置Python環(huán)境侥祭,稍后有時間寫成插件。