可变系统更新方式保持不变且引入不可变系统的系统更新方式,软件包:kylin-system-updater-immutable
This commit is contained in:
parent
d0a8aac6f0
commit
8c788e68f0
|
@ -0,0 +1,38 @@
|
|||
# Python
|
||||
*venv*
|
||||
__pycache__
|
||||
|
||||
.vscode
|
||||
.pybuild
|
||||
build
|
||||
debian/.debhelper
|
||||
debian/kylin-system-updater
|
||||
debian/kylin-system-updater.debhelper.log
|
||||
debian/kylin-system-updater.postinst.debhelper
|
||||
debian/kylin-system-updater.prerm.debhelper
|
||||
debian/kylin-system-updater.substvars
|
||||
backend/po/kylin-system-updater.pot
|
||||
system-updater.session.sql
|
||||
build/scripts-3.8/
|
||||
debian/files
|
||||
plugin/libupgrade.so
|
||||
plugin/*.o
|
||||
plugin/moc*
|
||||
# Misc
|
||||
.*cache
|
||||
plugin/.qmake.stash
|
||||
plugin/Makefile
|
||||
backend/po/kylin-system-updater.pot
|
||||
plugin/upgrade.pro.user
|
||||
#plugin
|
||||
plugin/qrc_img.cpp
|
||||
plugin/translations/bo.qm
|
||||
plugin/translations/en_US.qm
|
||||
plugin/translations/tr.qm
|
||||
plugin/translations/zh_CN.qm
|
||||
#notification
|
||||
kylin-updatefinish-notify
|
||||
notification/CMakeCache.txt
|
||||
notification/CMakeFiles/
|
||||
notification/Makefile
|
||||
notification/cmake_install.cmake
|
5
Makefile
5
Makefile
|
@ -1,4 +1,7 @@
|
|||
all:updater
|
||||
all:updater updater-immutable
|
||||
|
||||
updater:
|
||||
cd backend && ./setup.py build
|
||||
|
||||
updater-immutable:
|
||||
cd backend-immutable && ./setup.py build
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
# AlertWatcher.py
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2010 Mohamed Amine IL Idrissi
|
||||
#
|
||||
# Author: Mohamed Amine IL Idrissi <ilidrissiamine@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
from gi.repository import GObject
|
||||
import dbus
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
|
||||
|
||||
class AlertWatcher(GObject.GObject):
|
||||
""" a class that checks for alerts and reports them, like a battery
|
||||
or network warning """
|
||||
|
||||
__gsignals__ = {"network-alert": (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
(GObject.TYPE_INT,)),
|
||||
"battery-alert": (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
(GObject.TYPE_BOOLEAN,)),
|
||||
"network-3g-alert": (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
(GObject.TYPE_BOOLEAN,
|
||||
GObject.TYPE_BOOLEAN,)),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
GObject.GObject.__init__(self)
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
self.bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
|
||||
# make it always connected if NM isn't available
|
||||
self.network_state = 3
|
||||
|
||||
def check_alert_state(self):
|
||||
try:
|
||||
#network
|
||||
obj = self.bus.get_object("org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager")
|
||||
obj.connect_to_signal(
|
||||
"StateChanged",
|
||||
self._on_network_state_changed,
|
||||
dbus_interface="org.freedesktop.NetworkManager")
|
||||
interface = dbus.Interface(obj, "org.freedesktop.DBus.Properties")
|
||||
self.network_state = interface.Get(
|
||||
"org.freedesktop.NetworkManager", "State")
|
||||
self._network_alert(self.network_state)
|
||||
|
||||
# power
|
||||
# obj = self.bus.get_object('org.freedesktop.UPower',
|
||||
# '/org/freedesktop/UPower')
|
||||
# obj.connect_to_signal("Changed", self._power_changed,
|
||||
# dbus_interface="org.freedesktop.UPower")
|
||||
# self._power_changed()
|
||||
# 3g
|
||||
# self._update_3g_state()
|
||||
except dbus.exceptions.DBusException as e:
|
||||
logging.error(str(e))
|
||||
pass
|
||||
|
||||
def _on_network_state_changed(self, state):
|
||||
self._network_alert(state)
|
||||
# self._update_3g_state()
|
||||
|
||||
# def _update_3g_state(self):
|
||||
# from .roam import NetworkManagerHelper
|
||||
# nm = NetworkManagerHelper()
|
||||
# on_3g = nm.is_active_connection_gsm_or_cdma()
|
||||
# is_roaming = nm.is_active_connection_gsm_or_cdma_roaming()
|
||||
# self._network_3g_alert(on_3g, is_roaming)
|
||||
|
||||
# def _network_3g_alert(self, on_3g, is_roaming):
|
||||
# self.emit("network-3g-alert", on_3g, is_roaming)
|
||||
|
||||
def _network_alert(self, state):
|
||||
self.network_state = state
|
||||
self.emit("network-alert", state)
|
||||
|
||||
# def _power_changed(self):
|
||||
# obj = self.bus.get_object("org.freedesktop.UPower",
|
||||
# "/org/freedesktop/UPower")
|
||||
# interface = dbus.Interface(obj, "org.freedesktop.DBus.Properties")
|
||||
# on_battery = interface.Get("org.freedesktop.UPower", "OnBattery")
|
||||
# self.emit("battery-alert", on_battery)
|
|
@ -0,0 +1,753 @@
|
|||
# DataAcquisition.py
|
||||
# supervisory control and data acquisition
|
||||
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import json
|
||||
import dbus
|
||||
import uuid
|
||||
import time
|
||||
import socket
|
||||
import base64
|
||||
import shutil
|
||||
import hashlib
|
||||
import logging
|
||||
import tarfile
|
||||
import requests
|
||||
import datetime
|
||||
import threading
|
||||
import subprocess
|
||||
|
||||
from email import message
|
||||
from datetime import datetime
|
||||
from binascii import a2b_hex
|
||||
from Crypto.PublicKey import RSA
|
||||
from urllib import parse, request
|
||||
from SystemUpdater.Core import enums
|
||||
from Crypto.Cipher import PKCS1_OAEP
|
||||
from json.decoder import JSONDecodeError
|
||||
from dbus.exceptions import DBusException
|
||||
from SystemUpdater.Core.UpdaterConfigParser import UpgradeConfig
|
||||
|
||||
LOCALTIDDIR = "/var/lib/kylin-system-updater/"
|
||||
LOCALTIDFILE = "tidfile.conf"
|
||||
MSGSNDDIR = "/var/lib/kylin-system-updater/sendinfos/"
|
||||
SERVERID = "/var/lib/kylin-software-properties/config/serverID.conf"
|
||||
|
||||
SOURCE_PKGNAME = {
|
||||
'Kylin System Updater': 'kylin-system-updater',
|
||||
'Kylin Unattended Upgrade': 'unattended-upgrades'
|
||||
}
|
||||
|
||||
class UpdateMsgCollector():
|
||||
ACTION_DEFUALT_STATUS = -1
|
||||
ACTION_UPDATE = 0
|
||||
ACTION_INSTALL = 1
|
||||
ACTION_INSTALL_DEB = 2
|
||||
ACTION_CHECK_RESOLVER = 3
|
||||
ACTION_DOWNLOADONLY = 4
|
||||
ACTION_FIX_BROKEN = 5
|
||||
ACTION_REMOVE_PACKAGES = 6
|
||||
ACTION_FIX_INCOMPLETE = 7
|
||||
ACTION_CLEAN = 8
|
||||
ACTION_INSTALL_SHUTDOWN = 9
|
||||
|
||||
MODE_DEFAULT_STATUS = -1
|
||||
|
||||
#1、ACTION_INSTALL 安装的子类
|
||||
#部分升级
|
||||
MODE_INSTALL_PARTIAL = 0
|
||||
#全部升级
|
||||
MODE_INSTALL_ALL = 1
|
||||
#系统全盘升级
|
||||
MODE_INSTALL_SYSTEM = 2
|
||||
|
||||
#2、更新的子类
|
||||
MODE_UPDATE_CACHE = 0
|
||||
MODE_UPDATE_ALL = 1
|
||||
|
||||
mode_map = {
|
||||
MODE_INSTALL_PARTIAL:"upgrade_system",
|
||||
MODE_INSTALL_ALL:"upgrade_all",
|
||||
MODE_INSTALL_PARTIAL:"upgrade_partial"
|
||||
}
|
||||
action_map = {
|
||||
ACTION_CHECK_RESOLVER:enums.MONIT_DEPRESOLUT,
|
||||
ACTION_INSTALL:enums.MONIT_INSTALL,
|
||||
ACTION_INSTALL_DEB:enums.MONIT_INSTALLDEB,
|
||||
10:enums.MONIT_FINISH,
|
||||
"finish-updatedetect":enums.MONIT_DETECT,
|
||||
"finish-download":enums.MONIT_DOWNLOAD,
|
||||
"finish-downfinish":enums.MONIT_DOWNLOAD,
|
||||
"finish-update":enums.MONIT_FINISH,
|
||||
"finish-install":enums.MONIT_FINISH
|
||||
}
|
||||
messageType_map = {
|
||||
"finish-updatedetect":"UpdateDetect",
|
||||
ACTION_CHECK_RESOLVER:"DepResolution",
|
||||
"finish-downfinish":"Downloaded",
|
||||
ACTION_INSTALL:"Installing",
|
||||
# InstallBackend.ACTION_CHECK_RESOLVER:"UpgradeFinish",
|
||||
ACTION_INSTALL_DEB:"InstallerInfo",
|
||||
10:"Background-Upgrade",
|
||||
"finish-update":"UpdateInfos",
|
||||
"finish-install":"InstallInfos"
|
||||
}
|
||||
|
||||
def __init__(self, manager=None):
|
||||
self.uuid = ''
|
||||
self.status = ''
|
||||
self.upgrade_mode = ''
|
||||
self.upgrade_action = ''
|
||||
self.UploadMessage = {}
|
||||
self.PackageInfo = {}
|
||||
self.UpdateInfos = {}
|
||||
self.background_version = {}
|
||||
self.background_upgradable = []
|
||||
self.background_list = []
|
||||
self.upgrade_list = []
|
||||
self.waitSendList = []
|
||||
self.cache = None
|
||||
self.updateManager = manager
|
||||
# 转换 & 加密
|
||||
self.convertor = FormatConvert(self)
|
||||
# 发送器
|
||||
self.sender = MessageSend(self)
|
||||
logging.info("Initialize Update MessageSend Collector to success...")
|
||||
|
||||
def GenUploadMessage(self, dict_message, local_uuid = ''):
|
||||
UploadMessage = {}
|
||||
# 获取将要上传的数据,获取东八区时间
|
||||
UploadMessage['createTimeStamp'] = get_east_8_time()
|
||||
try:
|
||||
if "packageName" in dict_message.keys():
|
||||
dict_message.pop("packageName")
|
||||
for key in dict_message.keys():
|
||||
UploadMessage[key] = dict_message[key]
|
||||
if local_uuid != '':
|
||||
UploadMessage['UUID'] = str(local_uuid)
|
||||
else:
|
||||
UploadMessage['UUID'] = str(uuid.uuid1())
|
||||
serverid_configs = UpgradeConfig(datadir = "/var/lib/kylin-system-updater/json/", name = "serverID.conf")
|
||||
tans_id = serverid_configs.getWithDefault("ID", "pushID", " ")
|
||||
UploadMessage['transactionID'] = tans_id
|
||||
logging.debug('Get current transactionID: %s.',tans_id)
|
||||
|
||||
snobj = dbus.SystemBus().get_object('org.freedesktop.activation', '/org/freedesktop/activation')
|
||||
sninterface = dbus.Interface(snobj, dbus_interface='org.freedesktop.activation.interface')
|
||||
retval,retid = sninterface.serial_number()
|
||||
if(retid==0):
|
||||
UploadMessage['serialNumber'] = str(retval)
|
||||
else:
|
||||
UploadMessage['serialNumber'] = ''
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
json_UploadMessage = self.convertor.dictConvertJson(UploadMessage)
|
||||
|
||||
logging.debug('Generate UploadMessage: %s.',json_UploadMessage)
|
||||
self.UploadMessage = UploadMessage.copy()
|
||||
UploadMessage.clear()
|
||||
|
||||
def GenPackageInfo(self, messageType, packageName):
|
||||
PackageInfo = {}
|
||||
PackageInfo['messageType'] = str(messageType)
|
||||
PackageInfo['packageName'] = str(packageName)
|
||||
key = str(packageName)+'_'+str(messageType)
|
||||
# 获取本地tid
|
||||
self.sender.GetLocalTid(key)
|
||||
PackageInfo["tid"] = str(self.sender.localtid)
|
||||
|
||||
json_PackageInfo = self.convertor.dictConvertJson(PackageInfo)
|
||||
|
||||
logging.debug('Generate PackageInfo: %s.',json_PackageInfo)
|
||||
self.PackageInfo = PackageInfo.copy()
|
||||
PackageInfo.clear()
|
||||
|
||||
def setUploadMessage(self, KeyValue):
|
||||
pass
|
||||
|
||||
def UpdateMsg(self, messageType, json_message, uuid = ''):
|
||||
# para: messageType(消息类型): "UpdateInfos"、 "InstallInfos"、 "RemoveInfo"
|
||||
# para: dict_message(数据内容): 必须包含 "packageName"、"source"", 采集器会进行检测
|
||||
dict_message = self.convertor.JsonConvertDict(json_message)
|
||||
if messageType == "":
|
||||
messageType = "SystemUpdate"
|
||||
if type(dict_message) != type(dict) and "appname" not in dict_message.keys():
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % ("dict message", "appname"))
|
||||
|
||||
# 生成UploadMessage与PackageInfo
|
||||
try:
|
||||
self.GenPackageInfo(messageType, "kylin-system-updater")
|
||||
self.GenUploadMessage(dict_message, local_uuid = uuid)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
# sha256
|
||||
json_UploadMessage = self.convertor.dictConvertJson(self.UploadMessage)
|
||||
json_PackageInfo = self.convertor.dictConvertJson(self.PackageInfo)
|
||||
shaValue = self.convertor.Sha256Value(json_UploadMessage)
|
||||
encodeMsg = self.convertor.EncodeRSAtoBase64(shaValue)
|
||||
try:
|
||||
self.sender.MsgSendToServer(json_UploadMessage, json_PackageInfo, encodeMsg)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
try:
|
||||
if messageType == "UpdateInfos":
|
||||
# 获取系统激活码
|
||||
Activation_code = GetActivationCode()
|
||||
dict_message['RegisterNumber'] = Activation_code
|
||||
if "appname" in self.UploadMessage.keys():
|
||||
self.UploadMessage["packageName"] = self.UploadMessage["appname"]
|
||||
self.UploadMessage.pop("appname")
|
||||
|
||||
json_UploadMessage = self.convertor.dictConvertJson(self.UploadMessage)
|
||||
json_PackageInfo = self.convertor.dictConvertJson(self.PackageInfo)
|
||||
shaValue = self.convertor.Sha256Value(json_UploadMessage)
|
||||
encodeMsg = self.convertor.EncodeRSAtoBase64(shaValue)
|
||||
self.sender.MsgSendToLogTransmit(json_UploadMessage, json_PackageInfo, encodeMsg)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def Generate_Msg(self, upgrade_list, mode):
|
||||
try:
|
||||
self.upgrade_list = upgrade_list
|
||||
self.upgrade_mode = mode
|
||||
self.UpdateInfos.update({"upgradeMode":self.mode_map.get(self.upgrade_mode, "default-mode")})
|
||||
except DBusException as e:
|
||||
logging.error(e)
|
||||
|
||||
def Upgrade_Process_Msg(self, action, dict_msg = {}):
|
||||
if self.updateManager.configs_uncover.getWithDefault("SystemStatus", "upload_upgrade_log", False) == True:
|
||||
tmp_dict = {}
|
||||
tmp_dict.update(dict_msg)
|
||||
try:
|
||||
self.Init_UUID()
|
||||
if 'error_string' in tmp_dict.keys() and 'error_desc' in tmp_dict.keys():
|
||||
if tmp_dict['error_string'] == "下载失败" and tmp_dict['error_desc'] == "取消升级":
|
||||
tmp_dict.update({"error_string":str(tmp_dict['error_string']+","+tmp_dict['error_desc'])})
|
||||
tmp_dict.update({"error_desc":str(tmp_dict['error_string']+","+tmp_dict['error_desc'])})
|
||||
self.UpdateInfos.update({"step":self.action_map.get(action, "")})
|
||||
if self.upgrade_mode == self.MODE_INSTALL_SYSTEM:
|
||||
self.UpdateInfos.update({"appname":"Upgrade System"})
|
||||
tmp_dict.update(self.UpdateInfos)
|
||||
json_file = json.dumps(tmp_dict.copy())
|
||||
self.UpdateMsg(self.messageType_map.get(action, ""), json_file, self.uuid)
|
||||
else:
|
||||
if action == self.ACTION_INSTALL_DEB:
|
||||
tmp_dict.update({"step":self.action_map.get(action, "")})
|
||||
json_file = json.dumps(tmp_dict.copy())
|
||||
self.UpdateMsg(self.messageType_map.get(action, ""), json_file, self.uuid)
|
||||
else:
|
||||
tmp_dict.update(self.UpdateInfos)
|
||||
json_file = json.dumps(tmp_dict.copy())
|
||||
self.UpdateMsg(self.messageType_map.get(action, ""), json_file, self.uuid)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
tmp_dict.clear()
|
||||
|
||||
def make_background_version(self,pkg):
|
||||
if pkg.is_installed == True:
|
||||
self.background_version.update({pkg.name:pkg.installed.source_version})
|
||||
else:
|
||||
self.background_version.update({pkg.name:"Unknown"})
|
||||
self.background_list.append(pkg.name)
|
||||
|
||||
def Init_UUID(self):
|
||||
DMI_UUID_FILE = "/sys/devices/virtual/dmi/id/product_uuid1"
|
||||
|
||||
if os.path.isfile(DMI_UUID_FILE):
|
||||
with open(DMI_UUID_FILE, 'r') as f:
|
||||
data = f.read()
|
||||
self.uuid = data.split()
|
||||
|
||||
if self.uuid == "":
|
||||
args = ["/usr/sbin/dmidecode","-s","system-uuid"]
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
p = Popen(args, stdout=PIPE, universal_newlines=True)
|
||||
res = p.wait()
|
||||
if res != 0:
|
||||
self.uuid = ""
|
||||
else:
|
||||
self.uuid = p.stdout.readline().strip()
|
||||
p.stdout.close()
|
||||
|
||||
def Msg_Clean(self):
|
||||
self.UploadMessage = {}
|
||||
self.PackageInfo = {}
|
||||
self.UpdateInfos = {}
|
||||
self.uuid = ""
|
||||
|
||||
def update_process(self, action,status,upgrade_group,error_code='',error_string='',error_desc=''):
|
||||
MsgInfos = {}
|
||||
|
||||
MsgInfos.update({"appname":str(",".join(upgrade_group))})
|
||||
MsgInfos.update({"status":str(status)})
|
||||
MsgInfos.update({"error_code":str(error_code)})
|
||||
MsgInfos.update({"error_string":str(error_string)})
|
||||
MsgInfos.update({"error_desc":str(error_desc)})
|
||||
if action == "finish-updatedetect":
|
||||
if upgrade_group != [] or len(upgrade_group) != 0:
|
||||
self.Upgrade_Process_Msg("finish-updatedetect", MsgInfos.copy())
|
||||
elif action == "finish-downfinish":
|
||||
self.Upgrade_Process_Msg("finish-downfinish", MsgInfos.copy())
|
||||
|
||||
MsgInfos.clear()
|
||||
|
||||
|
||||
class FormatConvert():
|
||||
def __init__(self, DataCollector):
|
||||
#秘钥
|
||||
self.publickey = UniqueKey()
|
||||
self.collector = DataCollector
|
||||
|
||||
def dictConvertJson(self, dict_msg):
|
||||
#字典转换为json格式字符串
|
||||
json_file = ''
|
||||
try:
|
||||
json_file = json.dumps(dict_msg)
|
||||
except JSONDecodeError as e:
|
||||
logging.error(str(e))
|
||||
return json_file
|
||||
|
||||
def JsonConvertDict(self, json_file):
|
||||
# json格式字符串转换为字典
|
||||
dict_file = {}
|
||||
try:
|
||||
dict_file = json.loads(json_file)
|
||||
except JSONDecodeError as e:
|
||||
logging.error(str(e))
|
||||
return dict_file
|
||||
|
||||
def Sha256Value(self, json_file):
|
||||
# 计算sha256值
|
||||
hsobj = hashlib.sha256()
|
||||
try:
|
||||
hsobj.update(json_file.encode("utf-8"))
|
||||
except ValueError as e:
|
||||
logging.error("SHA256 value error: %s.",str(e))
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
return hsobj.hexdigest()
|
||||
|
||||
def EncodeRSAtoBase64(self, value):
|
||||
# 将value进行RSA加密并base64转码
|
||||
try:
|
||||
# 计算hex值
|
||||
value_hex = a2b_hex(value)
|
||||
# 加载公钥,填充格式OAEP
|
||||
uniqueKey = self.publickey.keyvalue.encode('utf-8')
|
||||
uniqueKeyorig = base64.b64decode(uniqueKey) # 公钥文件
|
||||
rsa_pubkey = RSA.importKey(uniqueKeyorig) # RSA公钥
|
||||
oaep_pub = PKCS1_OAEP.new(rsa_pubkey) # OAEP填充
|
||||
# 加密数据
|
||||
encodemsg = oaep_pub.encrypt(value_hex)
|
||||
# 加密数据Base64转码
|
||||
enMsg = base64.b64encode(encodemsg)
|
||||
except ValueError:
|
||||
logging.error("Value error: %s.", value)
|
||||
except TypeError:
|
||||
logging.error("RSA key has no private half.")
|
||||
return enMsg
|
||||
|
||||
|
||||
class MessageSend():
|
||||
ERR_PARA_FROMAT = 1
|
||||
ERR_NO_LOACLTID = 2
|
||||
ERR_ABNORMAL_SHA = 3
|
||||
ERR_UPLOADMSG_SHA = 4
|
||||
ERR_UPLOADMSG_CTS = 5
|
||||
|
||||
def __init__(self, DataCollector=None) -> None:
|
||||
# self.convertor = FormatConvert()
|
||||
if DataCollector == None:
|
||||
self.collector = UpdateMsgCollector()
|
||||
else:
|
||||
self.collector = DataCollector
|
||||
|
||||
def MsgSendToServer(self, UploadMessage, PackageInfo, encodeMsg):
|
||||
daqbus = dbus.SystemBus()
|
||||
try:
|
||||
daqobj = daqbus.get_object('com.kylin.daq', '/com/kylin/daq')
|
||||
daqinterface = dbus.Interface(daqobj, dbus_interface='com.kylin.daq.interface')
|
||||
except DBusException as e:
|
||||
logging.error("kylin-daq service error: "+str(e))
|
||||
return
|
||||
try:
|
||||
retval,retid = daqinterface.UploadMessage(PackageInfo, UploadMessage, encodeMsg)
|
||||
except AttributeError:
|
||||
logging.error("Call UploadMessage: Attribute Error.")
|
||||
self.Send_finally(retval, retid, PackageInfo, UploadMessage, encodeMsg)
|
||||
|
||||
|
||||
def MsgSendToLogTransmit(self, UploadMessage, PackageInfo, encodeMsg):
|
||||
daqbus = dbus.SystemBus()
|
||||
hedronbus = dbus.SystemBus()
|
||||
messgae = {}
|
||||
info = {}
|
||||
hostname = ""
|
||||
try:
|
||||
daqobj = daqbus.get_object('org.log.sys_transmit', '/org/log/sys_transmit')
|
||||
daqinterface = dbus.Interface(daqobj, dbus_interface='org.log.transmit')
|
||||
except DBusException as e:
|
||||
logging.warning("sys_transmit service error: "+str(e)) #主线默认不通过安全管控上传日志
|
||||
return
|
||||
|
||||
dict_UploadMessage = self.collector.convertor.JsonConvertDict(UploadMessage)
|
||||
dict_PackageInfo = self.collector.convertor.JsonConvertDict(PackageInfo)
|
||||
|
||||
messgae.update({"packageName": str(dictgetattr(dict_PackageInfo, "packageName", 'None'))})
|
||||
messgae.update({"messageType": str(dictgetattr(dict_PackageInfo, "messageType", 'None'))})
|
||||
for k in dict_UploadMessage.keys():
|
||||
messgae.update({k: str(dictgetattr(dict_UploadMessage, k, 'unKnown'))})
|
||||
if "status" in messgae.keys():
|
||||
if messgae["status"] == "success":
|
||||
messgae.update({"status": str("成功")})
|
||||
else:
|
||||
messgae.update({"status": str("失败")})
|
||||
json_messgae = self.collector.convertor.dictConvertJson(messgae)
|
||||
|
||||
info.update({"time":str(dictgetattr(dict_UploadMessage, 'createTimeStamp', ' '))})
|
||||
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(('8.8.8.8', 80))
|
||||
host_ip = s.getsockname()[0]
|
||||
except:
|
||||
host_ip = '0.0.0.0'
|
||||
try:
|
||||
hedronobj = hedronbus.get_object('com.kylin.kydevmonit.hedronclient', '/kydevmonit/hedronclient')
|
||||
hedroninterface = dbus.Interface(hedronobj, dbus_interface='com.kylin.kydevmonit.hedronclient')
|
||||
hostname = hedroninterface.get_current_user()
|
||||
except Exception as err:
|
||||
logging.warning(err)
|
||||
hostname = ""
|
||||
info.update({"hostname":str(hostname)})
|
||||
info.update({"ip":str(host_ip)})
|
||||
info.update({"name":str("kylin-system-updater")})
|
||||
info.update({"lv":str("debug")})
|
||||
info.update({"message":json_messgae})
|
||||
json_info = self.collector.convertor.dictConvertJson(info)
|
||||
logging.info("Send to sys_transmit: < %s >.",json_info)
|
||||
try:
|
||||
retval = daqinterface.log_transmit(json_info)
|
||||
logging.info("Send retval: %s.", retval)
|
||||
except Exception as err:
|
||||
logging.error(err)
|
||||
|
||||
def Send_finally(self, retval, retid, json_PackageInfo, json_UploadMessage, encodeMsg):
|
||||
# 根据发送结果进行处理
|
||||
result = ''
|
||||
PackageInfo = self.collector.convertor.JsonConvertDict(json_PackageInfo)
|
||||
if retval != 0:
|
||||
if retval == self.ERR_PARA_FROMAT:
|
||||
result = "Parameter format error"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
elif retval == self.ERR_NO_LOACLTID:
|
||||
result = "The tid value in packageInfo is abnormal, but the message is saved successfully"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
# 将返回的tid保存到本地
|
||||
key = PackageInfo['packageName']+'_'+PackageInfo['messageType']
|
||||
self.SaveTid(key, retid)
|
||||
elif retval == self.ERR_ABNORMAL_SHA:
|
||||
result = "Abnormal UploadedMessage Sha256"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
elif retval == self.ERR_UPLOADMSG_SHA:
|
||||
result = "Description The UploadedMessageSha256 was decrypted incorrectly"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
elif retval == self.ERR_UPLOADMSG_CTS:
|
||||
result = "The createTimeStamp field of UploadedMessage is abnormal"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
elif retval == self.ERR_UPLOADMSG_CTS:
|
||||
result = "Invalid key included in \"uploadedMessage\" or \"packageInfo\": <@timestamp>,<_id>,<_index>,<_type>,<createTime>,<highlight>,<sn>,<sort>, check upload field"
|
||||
logging.debug("Sent Status: false - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
else:
|
||||
logging.debug("Sent Status: false - packageName: %s : retval: %s.", PackageInfo['packageName'], retval)
|
||||
# 上传失败写入本地json
|
||||
if retval != self.ERR_NO_LOACLTID or retval == self.ERR_NO_LOACLTID:
|
||||
self.WriteToJson(PackageInfo['messageType'], json_PackageInfo, json_UploadMessage, encodeMsg)
|
||||
elif retval == 0:
|
||||
result = "Send to server success"
|
||||
logging.debug("Sent Status: True - packageName: %s : result: %s.", PackageInfo['packageName'], result)
|
||||
|
||||
def GetLocalTid(self, key):
|
||||
# 试图获取本地tid
|
||||
try:
|
||||
# 存放至数据库
|
||||
tid = self.collector.updateManager.sqlite3_server.select_from_tid("tid",key)
|
||||
if tid == "None" or tid == None:
|
||||
self.localtid = ""
|
||||
else:
|
||||
self.localtid = tid
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
def SaveTid(self, key, localtid):
|
||||
if len(localtid) == 0:
|
||||
return
|
||||
_localtid = str(localtid)
|
||||
try:
|
||||
# 写入数据库
|
||||
self.collector.updateManager.sqlite3_server.insert_into_tid(key, _localtid)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
def WriteToJson(self, messageType, json_PackageInfo, json_UploadMessage, encodeMsg):
|
||||
#发送失败时,写入本地json中定时发送
|
||||
Msg = {}
|
||||
Msg["PackageInfo"] = json_PackageInfo
|
||||
Msg["UploadMessage"] = json_UploadMessage
|
||||
Msg["encodeMsg"] = str(encodeMsg)
|
||||
json_file = self.collector.convertor.dictConvertJson(Msg)
|
||||
# 保存信息
|
||||
try:
|
||||
if not os.path.exists(MSGSNDDIR):
|
||||
os.mkdir(MSGSNDDIR)
|
||||
# 根据messageType保存信息
|
||||
with open(MSGSNDDIR+messageType+".json","a") as f:
|
||||
f.write(json_file)
|
||||
f.write("\n")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
def _TimedTransmission(self, file_path = MSGSNDDIR):
|
||||
classify_list = [name for name in os.listdir(file_path) if name.endswith(".json")]
|
||||
for f in classify_list:
|
||||
# 循环发送每一个文件
|
||||
self._ReadFromFile(os.path.join(file_path, f))
|
||||
|
||||
def _ReadFromFile(self, json_path):
|
||||
new_lines = []
|
||||
# 从本地文件读取
|
||||
if not os.path.exists(json_path):
|
||||
return
|
||||
with open(json_path, "r+") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# file is empty and path is exit -> remove file
|
||||
if len(lines) == 0 and os.path.exists(json_path):
|
||||
os.remove(json_path)
|
||||
return
|
||||
|
||||
#send installinfo or updateinfo
|
||||
for line in lines:
|
||||
(retval,retid) = self._file_send_server(line)
|
||||
if retval != 0: # success
|
||||
new_lines.append(line)
|
||||
if os.path.exists(json_path):
|
||||
os.remove(json_path)
|
||||
if len(new_lines) != 0:
|
||||
with open(json_path, "w+") as f:
|
||||
for line in lines:
|
||||
f.write(line)
|
||||
|
||||
def _file_send_server(self, json):
|
||||
UploadMessage = {}
|
||||
PackageInfo = {}
|
||||
encodeMsg = ''
|
||||
dict_msg = self.collector.convertor.JsonConvertDict(json)
|
||||
if 'UploadMessage' in dict_msg.keys():
|
||||
UploadMessage = dict_msg['UploadMessage']
|
||||
UploadMessage = self.collector.convertor.dictConvertJson(UploadMessage)
|
||||
if 'PackageInfo' in dict_msg.keys():
|
||||
PackageInfo = dict_msg['PackageInfo']
|
||||
PackageInfo = self.collector.convertor.dictConvertJson(PackageInfo)
|
||||
if 'encodeMsg' in dict_msg.keys():
|
||||
encodeMsg = str(dict_msg['encodeMsg'])
|
||||
if len(UploadMessage) == 0 or len(PackageInfo) == 0 or encodeMsg == '':
|
||||
logging.error("Msg error")
|
||||
return 6, ''
|
||||
daqbus = dbus.SystemBus()
|
||||
try:
|
||||
daqobj = daqbus.get_object('com.kylin.daq', '/com/kylin/daq')
|
||||
daqinterface = dbus.Interface(daqobj, dbus_interface='com.kylin.daq.interface')
|
||||
except DBusException as e:
|
||||
logging.error(str(e))
|
||||
try:
|
||||
retval,retid = daqinterface.UploadMessage(PackageInfo, UploadMessage, encodeMsg)
|
||||
except AttributeError:
|
||||
logging.error("Call UploadMessage: Attribute Error.")
|
||||
return (retval,retid)
|
||||
|
||||
class UniqueKey():
|
||||
keyvalue = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR\
|
||||
OEFNSUlCQ2dLQ0FRRUFzdW1NTFJEdlFNb0tEQkRJODRqSgpqc1A0Mk55V0pWVEZob2Jra3ZiT05j\
|
||||
dExYTXVzRmo2TzJUblZYU3Z6VlVLSjRqZkpwT2l2WEphOVB5Z2wzYTRnClBzSU40enNCMEdOY0tr\
|
||||
R3VsS2RrV2x6S3lWQ2xlTzhiQnN6SjkwbTc3cWF6YWg3a1A0TUl0WTVFczBpSkpiR0oKN1MxcERj\
|
||||
MlJkNnVFQWJLaXJyRTFlNzlFTEd4am5VN2V5NWkyRDE2WWJoZEQwZ2lNa2RHR3piQXBKTWZWRVJR\
|
||||
TQo1NXorMFVqdS8zSFJhNFY3b3p2TGRPRE5HUURaeWNJU0l3VHBLbFR3RjBxazdCNjVhTUlJenQ1\
|
||||
dnhOK1lxYU1GClppZFRLNzcxNjdqNEExZ3F3MG45bjlybWVXUGRWZ3dudnRtVXp4Q1krNk05SXpK\
|
||||
TDI3eWpRUTV1WGQ3RVdMT3IKbndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
|
||||
|
||||
class PHPServer(threading.Thread):
|
||||
LOG_PATH = "/var/log/kylin-system-updater"
|
||||
TMP_LOG_PATH = "/run/kylin-system-updater"
|
||||
KYLIN_SOFTWARE_PROPERTIES_LOG = "/var/log/kylin-software-properties.log"
|
||||
PINGBACK_INTERNET_URL = "http://archive1.kylinos.cn:32294/kylin-update-manager-server/main.php?"
|
||||
PINGBACK_INTERNET_FILE_URL = "http://archive1.kylinos.cn:32294/kylin-update-manager-server/get_file.php?"
|
||||
PINGBACK_INTRANET_URL = "http://archive.kylinos-intranet.cn/kylin-update-manager-server/main.php?"
|
||||
PINGBACK_INTRANET_FILE_URL = "http://archive.kylinos-intranet.cn/kylin-update-manager-server/get_file.php?"
|
||||
SYSTEM_VERSION_PATH = "/etc/kylin-version/kylin-system-version.conf"
|
||||
|
||||
def get_values(self, _appname="", _appversion="", _state='', _errorcode='', _errorstring=""):
|
||||
self.appname = _appname
|
||||
self.appversion = _appversion
|
||||
self.status = _state
|
||||
self.errorcode = _errorcode
|
||||
self.errorstring = _errorstring
|
||||
|
||||
def run(self):
|
||||
# 获取本机ip
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(('8.8.8.8', 80))
|
||||
host_ip = s.getsockname()[0]
|
||||
except:
|
||||
host_ip = 'Ip failed to get'
|
||||
# 获取系统版本
|
||||
with open('/etc/lsb-release', 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line.strip().startswith('DISTRIB_DESCRIPTION='):
|
||||
versions = line.strip().split('=')
|
||||
if "V10" in line and "SP1" in versions[1]:
|
||||
version = "V10SP1"
|
||||
else:
|
||||
version = "V10Pro"
|
||||
break
|
||||
# 获取软件版本
|
||||
output = os.popen('dpkg -l|grep kylin-system-updater').readlines()
|
||||
if output:
|
||||
soft_version = output[0].strip().split()[2]
|
||||
# 获取时间
|
||||
nowtime = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
|
||||
# 获取Mac
|
||||
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
host_mac = ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
|
||||
# 获取序列号
|
||||
if os.path.exists("/etc/.kyinfo"):
|
||||
kyinfo_configs = UpgradeConfig(datadir = "/etc/", name = ".kyinfo")
|
||||
key = kyinfo_configs.getWithDefault("servicekey", "key", "0")
|
||||
else:
|
||||
key = "0"
|
||||
log_dir = ""
|
||||
log_file_gzip = ""
|
||||
try:
|
||||
# 用于收集更新器更新日志
|
||||
if self.status != "success":
|
||||
nowtime = get_east_8_time()
|
||||
os.makedirs(self.TMP_LOG_PATH, exist_ok=True)
|
||||
|
||||
log_dir = os.path.join(self.TMP_LOG_PATH, host_mac + "_" + nowtime)
|
||||
log_file_gzip = log_dir + ".tar.gz"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
#get updater log
|
||||
if os.path.exists("/var/log/kylin-system-updater/kylin-system-updater.log.1"):
|
||||
shutil.copy("/var/log/kylin-system-updater/kylin-system-updater.log.1", log_dir)
|
||||
if os.path.exists("/var/log/kylin-system-updater/kylin-system-updater.log.1.1.gz"):
|
||||
shutil.copy("/var/log/kylin-system-updater/kylin-system-updater.log.1.1.gz", log_dir)
|
||||
|
||||
#get apt log
|
||||
if os.path.exists("/var/log/apt/history.log"):
|
||||
shutil.copy("/var/log/apt/history.log", log_dir)
|
||||
if os.path.exists("/var/log/apt/term.log"):
|
||||
shutil.copy("/var/log/apt/term.log", log_dir)
|
||||
|
||||
#get version file
|
||||
if os.path.exists(self.SYSTEM_VERSION_PATH):
|
||||
shutil.copy(self.SYSTEM_VERSION_PATH, log_dir)
|
||||
gZipFile(log_dir, log_file_gzip)
|
||||
header = {'Content-Type': "multipart/form-data", "Accept-Encoding": "gzip"}
|
||||
try:
|
||||
with open(log_file_gzip, "rb") as f:
|
||||
requests.post(self.PINGBACK_INTRANET_FILE_URL + "filename=" + os.path.basename(log_file_gzip),
|
||||
data=f.read(), headers=header, timeout = (3,3))
|
||||
except:
|
||||
with open(log_file_gzip, "rb") as f:
|
||||
requests.post(self.PINGBACK_INTERNET_FILE_URL + "filename=" + os.path.basename(log_file_gzip),
|
||||
data=f.read(), headers=header, timeout = (3,3))
|
||||
else:
|
||||
log_file_gzip = ""
|
||||
kmg_tmp = {'ip': host_ip, 'version': version, 'soft_version': soft_version, 'datetime': nowtime,
|
||||
'host_mac': host_mac, 'appname': self.appname, 'appversion': self.appversion, 'serial_number': key,
|
||||
'state': self.status, 'filename': log_file_gzip, 'errorcode': self.errorcode, 'errorstring': self.errorstring}
|
||||
kmg = parse.urlencode(kmg_tmp)
|
||||
logging.debug("PHPServer UpdateInfos: %s .", kmg_tmp)
|
||||
# 优先使用内网服务器,再使用外网
|
||||
try:
|
||||
url = self.PINGBACK_INTRANET_URL + kmg
|
||||
req = request.urlopen(url=url, timeout=3)
|
||||
logging.info("The Intranet log server is successfully accessed, pkgname:%s .",self.appname)
|
||||
except:
|
||||
url = self.PINGBACK_INTERNET_URL + kmg
|
||||
req = request.urlopen(url=url, timeout=3)
|
||||
logging.info("The external log server is successfully accessed, pkgname:%s .",self.appname)
|
||||
except Exception as e:
|
||||
logging.error("Failed to access the external log server: %s, pkgname:%s .", e, self.appname)
|
||||
if os.path.isfile(log_file_gzip):
|
||||
os.remove(log_file_gzip)
|
||||
if os.path.isdir(log_dir):
|
||||
shutil.rmtree(log_dir)
|
||||
|
||||
def PHPSeverSend(_appname="", _appversion="", _statue="", _errorcode="", _errorstring=""):
|
||||
send_thread = PHPServer()
|
||||
send_thread.get_values(_appname=_appname, _appversion=_appversion, _state=_statue, _errorcode=_errorcode, _errorstring=_errorstring)
|
||||
send_thread.start()
|
||||
|
||||
def gZipFile(src, dst):
|
||||
with tarfile.open(dst, "w:gz") as tar:
|
||||
tar.add(src, arcname=os.path.basename(src))
|
||||
|
||||
def get_east_8_time():
|
||||
import time
|
||||
# UTC时间
|
||||
utc_time = datetime.utcnow()
|
||||
# 转时间字符串
|
||||
utc_time = utc_time.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
time_suffix = utc_time.split(".")[1]
|
||||
# 字符串转时间元祖
|
||||
utc_time = time.strptime(utc_time, "%Y-%m-%d %H:%M:%S.%f")
|
||||
# 时间元祖转时间戳
|
||||
utc_time = time.mktime(utc_time)
|
||||
# 生成东八区时间时间戳
|
||||
now_time = utc_time + 8*60*60
|
||||
# 时间戳转时间元祖
|
||||
now_time = time.localtime(now_time)
|
||||
# 时间元祖转字符串
|
||||
now_time = time.strftime("%Y-%m-%d %H:%M:%S",now_time)
|
||||
now_time = now_time + "." +time_suffix
|
||||
return now_time
|
||||
# return 0
|
||||
|
||||
def GetActivationCode():
|
||||
Code = ''
|
||||
try:
|
||||
bus = dbus.SystemBus()
|
||||
obj = bus.get_object('org.freedesktop.activation', '/org/freedesktop/activation')
|
||||
interface = dbus.Interface(obj, dbus_interface='org.freedesktop.activation.interface')
|
||||
retval,ret = interface.register_number()
|
||||
if ret == 0 and len(retval) != 0:
|
||||
Code = str(retval)
|
||||
elif len(retval) == 0: # sh 查询
|
||||
sh_retval = os.popen("kylin_gen_register").read().strip()
|
||||
if len(sh_retval) != 0:
|
||||
Code = str(sh_retval)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return ""
|
||||
return Code
|
||||
|
||||
def dictgetattr(_dict, _key, default_value):
|
||||
if type(_dict) != type(dict()):
|
||||
return
|
||||
if _key in _dict.keys():
|
||||
return _dict[_key]
|
||||
else :
|
||||
return default_value
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 执行定时发送
|
||||
ms = MessageSend()
|
||||
ms._ReadFromFile("/var/lib/kylin-system-updater/sendinfos/testMsg.json")
|
|
@ -0,0 +1,400 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import logging
|
||||
import sqlite3
|
||||
from operator import itemgetter
|
||||
from gettext import gettext as _
|
||||
from optparse import OptionParser
|
||||
|
||||
DB_UPDATER = "/var/cache/kylin-update-manager/kylin-update-manager.db"
|
||||
DB_UPGRADE = "/var/cache/kylin-system-updater/kylin-system-updater.db"
|
||||
VER_DB = "/usr/share/kylin-system-updater/kylin-system-updater.db"
|
||||
|
||||
def dateMigration(options=None, old_db=None, old_db_cursor=None, new_db=None, new_db_cursor=None):
|
||||
print(_("Loading Sqlite3Server..."))
|
||||
if options==None:
|
||||
old_path = DB_UPDATER
|
||||
new_path = DB_UPGRADE
|
||||
try:
|
||||
if old_db==None and old_db_cursor==None:
|
||||
old_db = sqlite3.connect(old_path, check_same_thread=False)
|
||||
old_db_cursor = old_db.cursor()
|
||||
if new_db==None and new_db_cursor==None:
|
||||
new_db = sqlite3.connect(new_path, check_same_thread=False)
|
||||
new_db_cursor = new_db.cursor()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
sql_commnd = ""
|
||||
old_cfg_dict = {}
|
||||
new_cfg_dict = {}
|
||||
# step 1: 更新旧配置数据
|
||||
try:
|
||||
print("更新旧配置数据")
|
||||
sql_commnd = "SELECT * FROM display where id=1"
|
||||
old_db_cursor.execute(sql_commnd)
|
||||
old_cfg = old_db_cursor.fetchone()
|
||||
for od in old_db_cursor.description:
|
||||
old_cfg_dict.update({str(od[0]):old_cfg[old_db_cursor.description.index(od)]})
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_cfg = new_db_cursor.fetchone()
|
||||
for od in new_db_cursor.description:
|
||||
new_cfg_dict.update({str(od[0]):new_cfg[new_db_cursor.description.index(od)]})
|
||||
|
||||
if "download_limit" in new_cfg_dict.keys() and "download_limit_value" in new_cfg_dict.keys():
|
||||
if new_cfg_dict['download_limit'] != None or new_cfg_dict['download_limit_value'] != None:
|
||||
print("目标数据库有更新的配置项")
|
||||
else:
|
||||
sql_commnd = "UPDATE display set check_time='"+old_cfg_dict['check_time']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set update_time='"+old_cfg_dict['update_time']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set auto_check='"+old_cfg_dict['auto_check']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set system_version='"+old_cfg_dict['system_version']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if old_cfg_dict['auto_backup'] != None:
|
||||
sql_commnd = "UPDATE display set auto_backup='"+old_cfg_dict['auto_backup']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if 'download_limit' in old_cfg_dict.keys() and old_cfg_dict['download_limit'] != None:
|
||||
sql_commnd = "UPDATE display set download_limit='"+old_cfg_dict['download_limit']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if 'download_limit_value' in old_cfg_dict.keys() and old_cfg_dict['download_limit_value'] != None:
|
||||
sql_commnd = "UPDATE display set download_limit_value='"+old_cfg_dict['download_limit_value']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("更新配置文件错误")
|
||||
return
|
||||
|
||||
# step 2: 更新installed
|
||||
try:
|
||||
print("更新installed")
|
||||
update_record_dict = {}
|
||||
tmp_update_record_dict = []
|
||||
sql_commnd = "SELECT * FROM installed"
|
||||
old_db_cursor.execute(sql_commnd)
|
||||
update_record = old_db_cursor.fetchall()
|
||||
sql_commnd = "SELECT * FROM updateinfos"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_update_record = new_db_cursor.fetchall()
|
||||
|
||||
for ur in update_record:
|
||||
id,appname,version,time,description,icon,statue,keyword,errorcode = ur
|
||||
if errorcode in range(200):
|
||||
errorcode = 'null'
|
||||
update_record_dict.clear()
|
||||
update_record_dict.update({"appname":appname})
|
||||
update_record_dict.update({"version":version})
|
||||
update_record_dict.update({"time":time})
|
||||
update_record_dict.update({"description":description})
|
||||
update_record_dict.update({"icon":icon})
|
||||
update_record_dict.update({"statue":statue})
|
||||
update_record_dict.update({"keyword":'1'})
|
||||
update_record_dict.update({"errorcode":errorcode})
|
||||
tmp_update_record_dict.append(update_record_dict.copy())
|
||||
for ur in new_update_record:
|
||||
id,appname,version,description,date,status,keyword,errorcode = ur
|
||||
if errorcode in range(200):
|
||||
errorcode = 'null'
|
||||
update_record_dict.clear()
|
||||
update_record_dict.update({"appname":appname})
|
||||
update_record_dict.update({"version":version})
|
||||
update_record_dict.update({"time":date})
|
||||
update_record_dict.update({"description":description})
|
||||
update_record_dict.update({"icon":None})
|
||||
update_record_dict.update({"statue":status})
|
||||
update_record_dict.update({"keyword":'1'})
|
||||
update_record_dict.update({"errorcode":errorcode})
|
||||
tmp_update_record_dict.append(update_record_dict.copy())
|
||||
|
||||
# 按时间排序
|
||||
tmp_update_record_dict = sorted(tmp_update_record_dict, key=itemgetter('time'))
|
||||
print("更新installed success")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("更新安装记录错误")
|
||||
return
|
||||
|
||||
try:
|
||||
# 删除 tmp
|
||||
# DeleteTable(options.new_path+':'+'tmp')
|
||||
# 创建表
|
||||
sql_commnd = "create table IF NOT EXISTS tmp('id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
|
||||
'appname' TEXT,\
|
||||
'version' TEXT,\
|
||||
'description' TEXT,\
|
||||
'date' TEXT,\
|
||||
'status' TEXT,\
|
||||
'keyword' TEXT,\
|
||||
'errorcode' TEXT) "
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
# 更新数据
|
||||
for urd in tmp_update_record_dict:
|
||||
new_db_cursor.execute(
|
||||
"insert into tmp (appname, version, description, date, status, keyword, errorcode) values(?,"
|
||||
"?,?,?,?,?,?)",
|
||||
(urd['appname'], urd['version'], urd['description'], urd['time'], urd['statue'], urd['keyword'], urd['errorcode']))
|
||||
new_db.commit()
|
||||
|
||||
# 删除updateinfos
|
||||
sql_commnd = "drop table updateinfos"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
# 修改表名
|
||||
sql_commnd = "alter table tmp rename to updateinfos"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("安装记录迁移错误")
|
||||
return
|
||||
print("数据迁移成功.")
|
||||
|
||||
def CleanTable(db_table):
|
||||
db_path, table_name = str(db_table).split(":")
|
||||
if not os.path.isfile(db_path):
|
||||
print("db path error.")
|
||||
exit(-1)
|
||||
print(_("Loading Sqlite3Server..."))
|
||||
try:
|
||||
db = sqlite3.connect(db_path, check_same_thread=False)
|
||||
db_cursor = db.cursor()
|
||||
sql_commnd = 'delete from '+table_name
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
print("clean %s success."%table_name)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("clean %s error."%table_name)
|
||||
|
||||
def DeleteTable(db_table):
|
||||
db_path, table_name = str(db_table).split(":")
|
||||
if not os.path.isfile(db_path):
|
||||
print("db path error.")
|
||||
exit(-1)
|
||||
print(_("Loading Sqlite3Server..."))
|
||||
try:
|
||||
db = sqlite3.connect(db_path, check_same_thread=False)
|
||||
db_cursor = db.cursor()
|
||||
sql_commnd = 'drop table '+table_name
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
print("delete %s success."%table_name)
|
||||
except Exception as e:
|
||||
print("delete %s error: %s"%(table_name,e))
|
||||
|
||||
def _has_first_migration(new_db, new_db_cursor):
|
||||
try:
|
||||
sql_commnd = "select * from sqlite_master where type='table' and name='display';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
retval = new_db_cursor.fetchone()
|
||||
for rv in retval:
|
||||
if "firstmigration" in str(rv):
|
||||
return True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def _is_first_migration(new_db, new_db_cursor):
|
||||
try:
|
||||
sql_commnd = "select firstmigration from display;"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
retval = new_db_cursor.fetchone()
|
||||
if "yes" in retval:
|
||||
return True
|
||||
else :
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def _is_display_exist_fields(field, db, db_cursor):
|
||||
try:
|
||||
sql_commnd = "select * from sqlite_master where type='table' and name='display';"
|
||||
db_cursor.execute(sql_commnd)
|
||||
retval = db_cursor.fetchone()
|
||||
for rv in retval:
|
||||
if field in str(rv):
|
||||
return True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
return False
|
||||
|
||||
def _is_updateinfos_exist_fields(field, db, db_cursor):
|
||||
try:
|
||||
sql_commnd = "select * from sqlite_master where type='table' and name='updateinfos';"
|
||||
db_cursor.execute(sql_commnd)
|
||||
retval = db_cursor.fetchone()
|
||||
for rv in retval:
|
||||
if field in str(rv):
|
||||
return True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
return False
|
||||
|
||||
def _add_display_fields(fields_default, default_table = True):
|
||||
try:
|
||||
if "=" not in fields_default:
|
||||
print("format: field=value")
|
||||
return False
|
||||
field, value = fields_default.split('=')
|
||||
# print(_("Loading Sqlite3Server..."))
|
||||
db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
db_cursor = db.cursor()
|
||||
if default_table:
|
||||
if _is_display_exist_fields(field, db, db_cursor):
|
||||
print("field %s is exist."%field)
|
||||
return False
|
||||
# 字段不存在,新增字段
|
||||
sql_commnd = "alter table display add column "+field+" TEXT;"
|
||||
db_cursor.execute(sql_commnd)
|
||||
sql_commnd = "UPDATE display SET "+field+"='"+value+"'"
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
else:
|
||||
if _is_updateinfos_exist_fields(field, db, db_cursor):
|
||||
print("field %s is exist."%field)
|
||||
return False
|
||||
# 字段不存在,新增字段
|
||||
sql_commnd = "alter table updateinfos add column "+field+" TEXT;"
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
print("Succeeded in adding field: '%s' "%field)
|
||||
return True
|
||||
|
||||
def _add_new_table(table):
|
||||
table = str(table).strip()
|
||||
if "=" not in table:
|
||||
return False
|
||||
opt, fields = table.split('=')
|
||||
try:
|
||||
if fields == 'tid_search':
|
||||
db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
db_cursor = db.cursor()
|
||||
sql_commnd = "create table IF NOT EXISTS tid_search('id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
|
||||
'key' TEXT,\
|
||||
'tid' TEXT) "
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
db.close()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def CopyData():
|
||||
try:
|
||||
# 判断新字段是否存在
|
||||
if (os.path.exists(VER_DB) and os.path.exists(DB_UPGRADE)):
|
||||
print(_("Loading Sqlite3Server..."))
|
||||
try:
|
||||
new_db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
new_db_cursor = new_db.cursor()
|
||||
ver_db = sqlite3.connect(VER_DB, check_same_thread=False)
|
||||
ver_db_cursor = ver_db.cursor()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
if (_has_first_migration(new_db, new_db_cursor)): # 存在 firstmigration
|
||||
if (_is_first_migration(new_db, new_db_cursor)):
|
||||
# 数据迁移
|
||||
dateMigration(new_db=new_db, new_db_cursor=new_db_cursor)
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
else:
|
||||
print("No data migration is required ...")
|
||||
else:# 不存在firstmigration
|
||||
# 新增 firstmigration 字段
|
||||
sql_commnd = "alter table display add column firstmigration text;"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
sql_commnd = "UPDATE display SET firstmigration='true';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
#数据迁移
|
||||
dateMigration(new_db=new_db, new_db_cursor=new_db_cursor)
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
|
||||
else :
|
||||
print("Not found kylin-system-updater.db, ensure that \'kylin-system-updater\' is successfully installed ... ")
|
||||
exit(-1)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Begin parsing of options
|
||||
parser = OptionParser()
|
||||
parser.add_option ("-d", "--debug", action="store_true", default=False,
|
||||
help=_("Show debug messages"))
|
||||
parser.add_option ("-o", "--old-path", dest="old_path",
|
||||
help=_("Enter the old database address"))
|
||||
parser.add_option ("-n", "--new-path", dest="new_path",
|
||||
help=_("Enter the new database address"))
|
||||
parser.add_option ("-c", "--clean-table", dest="clean_table",
|
||||
help=_("Clear the table"))
|
||||
parser.add_option ("-r", "--delete-table", dest="delete_table",
|
||||
help=_("Delete the table"))
|
||||
parser.add_option ("-m", "--data-migration", default=False, action="store_true",
|
||||
dest="data_migration", help=_("data migration"))
|
||||
parser.add_option ("-f", "--add-display-fields",
|
||||
dest="add_display_fields", help=_("add display fields"))
|
||||
parser.add_option ("-u", "--add-updateinfos-fields",
|
||||
dest="add_updateinfos_fields", help=_("add updateinfos fields"))
|
||||
parser.add_option ("-t", "--add-new-table",
|
||||
dest="add_new_table", help=_("add new table"))
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.clean_table:
|
||||
if ":" not in options.clean_table:
|
||||
print("format error: <database:table>")
|
||||
else:
|
||||
CleanTable(str(options.clean_table))
|
||||
|
||||
if options.delete_table:
|
||||
if ":" not in options.delete_table:
|
||||
print("format error: <database:table>")
|
||||
else:
|
||||
DeleteTable(str(options.delete_table))
|
||||
|
||||
if options.add_display_fields:
|
||||
_add_display_fields(str(options.add_display_fields))
|
||||
|
||||
if options.add_updateinfos_fields:
|
||||
_add_display_fields(str(options.add_updateinfos_fields), default_table = False)
|
||||
|
||||
if options.add_new_table:
|
||||
_add_new_table(str(options.add_new_table))
|
||||
|
||||
if options.data_migration:
|
||||
CopyData()
|
||||
exit(0)
|
||||
|
||||
if options.old_path or options.new_path:
|
||||
# 检查文件
|
||||
if not options.old_path or not options.new_path:
|
||||
print("parameter error")
|
||||
exit(-1)
|
||||
if not os.path.isfile(options.old_path):
|
||||
print("The source database file does not exist")
|
||||
exit(-1)
|
||||
if not os.path.isfile(options.new_path):
|
||||
print("The destination database file does not exist")
|
||||
exit(-1)
|
||||
dateMigration(options)
|
|
@ -0,0 +1,810 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import yaml
|
||||
import shutil
|
||||
import sqlite3
|
||||
import logging
|
||||
import datetime
|
||||
from operator import itemgetter
|
||||
from gettext import gettext as _
|
||||
from SystemUpdater.Core.errors import *
|
||||
from SystemUpdater.Core.enums import *
|
||||
# from SystemUpdater.Core.DataAcquisition import PHPSeverSend
|
||||
from SystemUpdater.Core.UpdaterConfigParser import UpgradeConfig
|
||||
# from SystemUpdater.Core.utils import get_config_patch
|
||||
|
||||
DB_FILE = os.path.join("/var/cache/kylin-system-updater/kylin-system-updater.db")
|
||||
# UMDB_FILE = os.path.join("/var/cache/kylin-system-updater/kylin-system-updater.db")
|
||||
DB_UPDATER = "/var/cache/kylin-update-manager/kylin-update-manager.db"
|
||||
DB_UPGRADE = "/var/cache/kylin-system-updater/kylin-system-updater.db"
|
||||
VER_DB = "/usr/share/kylin-system-updater/kylin-system-updater.db"
|
||||
INSTALLED_LIST = [{"item": "errorcode", "type": "int", "default": "0"}]
|
||||
DISPALY_LIST = []
|
||||
|
||||
class Sqlite3Server(object):
|
||||
def __init__(self, updateManager, _no_DataMigration=False):
|
||||
self.connect = None
|
||||
self.window_main = updateManager
|
||||
# self.config_path = get_config_patch()
|
||||
self.init_sqlit()
|
||||
|
||||
# uncoverable配置文件
|
||||
self.ucconfigs = UpgradeConfig(datadir = "/etc/kylin-version", name = "kylin-system-version.conf")
|
||||
self._system_version_config()
|
||||
#判断数据迁移
|
||||
if not _no_DataMigration:
|
||||
if (not os.path.exists(DB_UPDATER)):
|
||||
logging.debug("Can not found database: %s, should ignore.",DB_UPDATER)
|
||||
self.__need_DataMigration(mark_FirstMigration = True)
|
||||
else:
|
||||
self.__need_DataMigration(mark_FirstMigration = False)
|
||||
self.current_purge_pkgs = []
|
||||
self.init_metadata()
|
||||
|
||||
def init_metadata(self):
|
||||
self.deb_metadata = {}
|
||||
self.deb_metadata.update({"current_install_debfile":""})
|
||||
self.deb_metadata.update({"absolute_path":""})
|
||||
self.deb_metadata.update({"debname":""})
|
||||
self.deb_metadata.update({"deblist":[]})
|
||||
self.deb_metadata.update({"action":''})
|
||||
self.deb_metadata.update({"mode":''})
|
||||
self.deb_metadata.update({"source":''})
|
||||
self.deb_metadata.update({"sender":''})
|
||||
self.deb_metadata.update({"caller":''})
|
||||
self.deb_metadata.update({"old_version":''})
|
||||
self.deb_metadata.update({"new_version":''})
|
||||
self.deb_metadata.update({"old_update_version":''})
|
||||
self.deb_metadata.update({"new_update_version":''})
|
||||
|
||||
# Initialize the connection database and modify it to connect when using
|
||||
def init_sqlit(self):
|
||||
try:
|
||||
logging.info(_("Initialize database files ..."))
|
||||
if not os.path.isfile(DB_FILE):
|
||||
if not os.path.isdir(os.path.dirname(DB_FILE)):
|
||||
os.makedirs(os.path.dirname(DB_FILE))
|
||||
shutil.copy("/usr/share/kylin-system-updater/kylin-system-updater.db", os.path.dirname(DB_FILE))
|
||||
except Exception as e:
|
||||
logging.error("Failed to initialize database files: %s", str(e))
|
||||
|
||||
#connect连接数据库
|
||||
def connect_database(self):
|
||||
try:
|
||||
self.connect = sqlite3.connect(DB_FILE, check_same_thread=False)
|
||||
self.cursor = self.connect.cursor()
|
||||
except Exception as e:
|
||||
logging.error("Failed to connect database: %s", str(e))
|
||||
|
||||
#disconnect连接数据库
|
||||
def disconnect_database(self):
|
||||
try:
|
||||
if self.connect != None:
|
||||
self.connect.close()
|
||||
if self.cursor != None:
|
||||
del self.cursor
|
||||
except Exception as e:
|
||||
logging.error("Failed to disconnect database: %s", str(e))
|
||||
|
||||
# 数据库表格中动态增加新的字段用于扩展
|
||||
def insert_new_field(self):
|
||||
if len(INSTALLED_LIST) == 0 and len(DISPALY_LIST) == 0:
|
||||
return
|
||||
self.cursor.execute("select sql from sqlite_master where name='installed'")
|
||||
installed_sql = self.cursor.fetchone()[0]
|
||||
pattern = re.compile(r'\"\w+\"')
|
||||
installed_sql_list = pattern.findall(installed_sql)
|
||||
for value in INSTALLED_LIST:
|
||||
for field in installed_sql_list:
|
||||
if value["item"] == str(field).strip("\""):
|
||||
break
|
||||
elif field == installed_sql_list[len(installed_sql_list) - 1]:
|
||||
try:
|
||||
if value["default"] != "":
|
||||
sql = 'alter table installed add column "' + value["item"] + '" ' + value["type"] \
|
||||
+ ' default ' + str(value["default"])
|
||||
else:
|
||||
sql = 'alter table installed add column "' + value["item"] + '" ' + value["type"]
|
||||
self.cursor.execute(sql)
|
||||
logging.info(_("installed table insert new field: %s"), value["item"])
|
||||
except:
|
||||
logging.error(_("installed table failed to insert a new field:"), value["item"], exc_info=True)
|
||||
|
||||
self.cursor.execute("select sql from sqlite_master where name='display'")
|
||||
display_sql = self.cursor.fetchone()[0]
|
||||
pattern = re.compile(r'\"\w+\"')
|
||||
display_sql_list = pattern.findall(display_sql)
|
||||
for value in DISPALY_LIST:
|
||||
for field in display_sql_list:
|
||||
if value["item"] == str(field).strip("\""):
|
||||
break
|
||||
elif field == display_sql_list[len(display_sql_list) - 1]:
|
||||
try:
|
||||
if value["default"] != "":
|
||||
sql = 'alter table display add column "' + value["item"] + '" ' + value["type"] \
|
||||
+ ' default ' + str(value["default"])
|
||||
else:
|
||||
sql = 'alter table installed add column "' + value["item"] + '" ' + value["type"]
|
||||
self.cursor.execute(sql)
|
||||
logging.info(_("display table insert new field: %s"), value["item"])
|
||||
except:
|
||||
logging.error(_("display table failed to insert a new field: %s"), value["item"], exc_info=True)
|
||||
|
||||
# 写入数据到installed表中
|
||||
def insert_into_installed(self, *args, **kwargs):
|
||||
self.connect_database()
|
||||
self.cursor.execute(
|
||||
"insert into installed (appname, version, time, description, icon, statue, keyword, errorcode) values(?,"
|
||||
"?,?,?,?,?,?,?)", (args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]))
|
||||
self.connect.commit()
|
||||
logging.info("Database: Insert (%s=%s) To installed Complete ...", args[0], args[1])
|
||||
self.disconnect_database()
|
||||
|
||||
# 写入数据到display表中
|
||||
def insert_into_display(self, *args, **kwargs):
|
||||
self.connect_database()
|
||||
try:
|
||||
sql = "update display set " + args[0] + "='" + args[1] + "' where id = 1"
|
||||
self.cursor.execute(sql)
|
||||
self.connect.commit()
|
||||
except Exception as e:
|
||||
logging.error("Insert error: %s.", str(e))
|
||||
self.disconnect_database()
|
||||
return False
|
||||
logging.info("Database: Insert (%s=%s) To display Complete ...", args[0], args[1])
|
||||
self.disconnect_database()
|
||||
return True
|
||||
|
||||
# 写入数据到tid_search表中
|
||||
def insert_into_tid(self, *args, **kwargs):
|
||||
self.connect_database()
|
||||
self.cursor.execute(
|
||||
"insert into tid_search (key, tid) values(?,?)",
|
||||
(args[0], args[1]))
|
||||
self.connect.commit()
|
||||
logging.info("Database: Insert (%s=%s) To tid_search Complete ...", args[0], args[1])
|
||||
self.disconnect_database()
|
||||
|
||||
# 搜索tid_search表,获取tid值
|
||||
def select_from_tid(self, *args, **kwargs):
|
||||
retval = ''
|
||||
self.connect_database()
|
||||
try:
|
||||
sql = "select "+args[0]+" from tid_search where key='"+args[1]+"'"
|
||||
self.cursor.execute(sql)
|
||||
rets = self.cursor.fetchall()
|
||||
if len(rets)!= 0:
|
||||
if len(rets[0])!=0:
|
||||
ret_first = rets[0]
|
||||
retval = str(ret_first[0])
|
||||
except Exception as e:
|
||||
logging.error("Insert error: %s.", str(e))
|
||||
self.disconnect_database()
|
||||
logging.info("Database: Select tid_search data Complete...")
|
||||
self.disconnect_database()
|
||||
return retval
|
||||
|
||||
# 读出display表中数据
|
||||
def select_from_display(self, *args, **kwargs):
|
||||
self.connect_database()
|
||||
try:
|
||||
sql = "select "+args[0]+" from display"
|
||||
self.cursor.execute(sql)
|
||||
self.connect.commit()
|
||||
retval = str(self.cursor.fetchone()[0])
|
||||
except Exception as e:
|
||||
logging.error("select error: %s.", str(e))
|
||||
self.disconnect_database()
|
||||
return "Error"
|
||||
logging.info("Database: Search display Complete (%s) ...", args[0])
|
||||
self.disconnect_database()
|
||||
return retval
|
||||
|
||||
# 写入updateinfos表中
|
||||
def insert_into_updateinfo(self, *args, **kwargs):
|
||||
self.connect_database()
|
||||
try:
|
||||
self.cursor.execute(
|
||||
"insert into updateinfos (appname, version, description, date, status, keyword, errorcode, appname_cn, status_cn, changelog) values(?,"
|
||||
"?,?,?,?,?,?,?,?,?)",
|
||||
(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]))
|
||||
self.connect.commit()
|
||||
except Exception as e:
|
||||
logging.error("Insert error: %s.", str(e))
|
||||
self.disconnect_database()
|
||||
logging.info(_("Database: Insert To updateinfos Complete..."))
|
||||
self.disconnect_database()
|
||||
|
||||
#get display data
|
||||
def gen_display_mate(self)->dict:
|
||||
mateData = {}
|
||||
self.connect_database()
|
||||
try:
|
||||
sql = "pragma table_info({})".format("display")
|
||||
self.cursor.execute(sql)
|
||||
keys=[key[1] for key in self.cursor.fetchall()]
|
||||
sql = "select * from display where id=1;"
|
||||
self.cursor.execute(sql)
|
||||
values = self.cursor.fetchone()
|
||||
mateData = dict(zip(keys, values))
|
||||
#
|
||||
# self.connect.row_factory = self.dictFactory
|
||||
# values = self.cursor.execute("select * from display where id=1;").fetchall()
|
||||
except Exception as e:
|
||||
logging.error("select error: %s.", str(e))
|
||||
self.disconnect_database()
|
||||
return mateData
|
||||
|
||||
def dictFactory(self,cursor,row):
|
||||
"""将sql查询结果整理成字典形式"""
|
||||
d={}
|
||||
for index,col in enumerate(cursor.description):
|
||||
d[col[0]]=row[index]
|
||||
return d
|
||||
|
||||
def __need_DataMigration(self, mark_FirstMigration = False):
|
||||
# mateData = self.gen_display_mate()
|
||||
# if "firstmigration" in mateData.keys() and mateData["firstmigration"] == "true":
|
||||
dm = DataMigration()
|
||||
if (mark_FirstMigration):
|
||||
dm.MarkFirstMigration()
|
||||
else:
|
||||
dm.CopyData()
|
||||
|
||||
def _check_upgrade_content(self,cache,content):
|
||||
upgradeable_groups = []
|
||||
upgradeable_pkgs = []
|
||||
|
||||
for cont in content:
|
||||
if cont == '':
|
||||
continue
|
||||
if cont in cache:
|
||||
upgradeable_pkgs.append(cont)
|
||||
else:
|
||||
upgradeable_groups.append(cont)
|
||||
|
||||
return upgradeable_pkgs,upgradeable_groups
|
||||
|
||||
# 接收更新列表与信息,生成数据并插入数据库中
|
||||
def insert_info(self, success,matedata,error_code):
|
||||
if success:
|
||||
status = 'success'
|
||||
status_cn = '成功'
|
||||
else:
|
||||
status = 'failed'
|
||||
status_cn = '失败'
|
||||
|
||||
logging.info(matedata)
|
||||
|
||||
pkgappname = matedata.get("name",{}).get("zh_CN", "")
|
||||
pkgversion = matedata.get("version", "")
|
||||
pkgdescription = matedata.get("description", {}).get("zh_CN", "")
|
||||
pkgchangelog = matedata.get("changelog", "")
|
||||
|
||||
pkgtimestr = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
pkgstatus = str(status)
|
||||
pkgkeyword = str('1')
|
||||
pkgerrorcode = str(error_code)
|
||||
pkgappnamecn = str('系统更新')
|
||||
pkgstatuscn = str(status_cn)
|
||||
|
||||
errstr = get_error_description_from_enum(error_code)
|
||||
|
||||
self.insert_into_updateinfo(pkgappname, pkgversion, pkgdescription, pkgtimestr, \
|
||||
pkgstatus, pkgkeyword, errstr, pkgappnamecn, pkgstatuscn, pkgchangelog)
|
||||
|
||||
# 系统升级完成 更新版本号
|
||||
if status == "success":
|
||||
logging.info("Complete system upgrade, refresh system version ...")
|
||||
self._refresh_system_version(update_version = pkgversion)
|
||||
|
||||
# 获取group信息
|
||||
def GetGroupmsg(self, appname):
|
||||
jsonfile = appname+".json"
|
||||
files = os.listdir(self.config_path) #获取文件夹中所有文件
|
||||
if jsonfile in files: # 存在
|
||||
# 读取组JSON文件
|
||||
with open(self.config_path+jsonfile, "r") as f:
|
||||
try :
|
||||
data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(str(e))
|
||||
try:
|
||||
version = data['version']
|
||||
if "=" in version:
|
||||
version = version.split("=")[1].strip()
|
||||
tmpdescription = data['description']
|
||||
appname_cn = data['name']['zh_CN']
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
if "zh_CN" in tmpdescription and "en_US" in tmpdescription:
|
||||
description = tmpdescription["zh_CN"] + ": " + tmpdescription["en_US"]
|
||||
return (version,description,appname_cn)
|
||||
else: # 不存在
|
||||
return (None, None, None)
|
||||
|
||||
def refreshpkglist(self):
|
||||
pkgs_install = []
|
||||
pkgs_upgrade = []
|
||||
pkgs_remove = []
|
||||
|
||||
for pkg in self.window_main.cache:
|
||||
try:
|
||||
if pkg.marked_install:
|
||||
pkgs_install.append(pkg.name)
|
||||
if pkg.marked_upgrade:
|
||||
pkgs_upgrade.append(pkg.name)
|
||||
elif pkg.marked_delete:
|
||||
pkgs_remove.append(pkg.name)
|
||||
except KeyError:
|
||||
# pkg missing from fresh_cache can't be modified
|
||||
pass
|
||||
return pkgs_install,pkgs_upgrade,pkgs_remove
|
||||
|
||||
def _removal_of_marker(self):
|
||||
try:
|
||||
marker_path = "/var/cache/kylin-update-manager/ignoreOrDelay"
|
||||
if os.path.exists(marker_path):
|
||||
with open(marker_path, 'r+') as f:
|
||||
line= f.readline()
|
||||
if "2107" in line or "2203" in line:
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
except Exception as e:
|
||||
logging.error("Removing the upgrade success mark error: %s.",str(e))
|
||||
|
||||
# #查找数据库
|
||||
# def find_msg_from_datebase(self, table, field, action = 'check', cid = 0):
|
||||
# # 查询数据
|
||||
# try:
|
||||
# sql = "select "+field+" from "+table
|
||||
# self.cursor.execute(sql)
|
||||
# update_count = self.cursor.fetchone()[0]
|
||||
# logging.info("%d history updates detected.", update_count)
|
||||
# except Exception as e:
|
||||
# logging.error("Check update error: %s", str(e))
|
||||
|
||||
def _system_version_config(self):
|
||||
self.connect_database()
|
||||
try:
|
||||
sql = "select init_version from display where id=1"
|
||||
self.cursor.execute(sql)
|
||||
_is_init_verison = self.cursor.fetchone()[0]
|
||||
if _is_init_verison == "yes" or _is_init_verison == "true":
|
||||
logging.info("Need to refresh version ...")
|
||||
self._initial_system_version()
|
||||
sql = "update display set init_version = 'no'"
|
||||
self.cursor.execute(sql)
|
||||
self.connect.commit()
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
self.disconnect_database()
|
||||
|
||||
def _refresh_system_version(self, update_version = '', pseudo_version = False):
|
||||
try:
|
||||
#刷新版本号:update_version、os_version
|
||||
default_update_version, os_version = self.get_default_version()
|
||||
|
||||
if not pseudo_version:
|
||||
if len(os_version) != 0:
|
||||
self.ucconfigs.setValue("SYSTEM","os_version",str(os_version),True)
|
||||
if len(update_version) != 0:
|
||||
self.ucconfigs.setValue("SYSTEM","update_version",str(update_version),True)
|
||||
elif len(os_version) != 0 and len(update_version) == 0:
|
||||
self.ucconfigs.setValue("SYSTEM","update_version",str(os_version),True)
|
||||
else:
|
||||
current_update_version, current_os_version = self.get_current_version()
|
||||
if current_os_version != os_version:
|
||||
os_version+='*'
|
||||
self.ucconfigs.setValue("SYSTEM","os_version",str(os_version),True)
|
||||
if current_update_version != update_version:
|
||||
update_version+='*'
|
||||
self.ucconfigs.setValue("SYSTEM","update_version",str(update_version),True)
|
||||
except Exception as e:
|
||||
logging.error("Refresh system version error: %s.",str(e))
|
||||
|
||||
def _initial_system_version(self):
|
||||
try:
|
||||
#刷新版本号:update_version、os_version
|
||||
update_version, os_version = self.get_default_version()
|
||||
|
||||
if len(os_version) != 0:
|
||||
self.ucconfigs.setValue("SYSTEM","os_version",str(os_version),True)
|
||||
self.ucconfigs.setValue("SYSTEM","update_version",str(os_version),True)
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Initial system version error: %s.",str(e))
|
||||
|
||||
def get_default_version(self):
|
||||
update_version = ""
|
||||
os_version = ""
|
||||
INPUT_CONFIG_PATH = self.config_path + 'kylin-update-desktop-system.json'
|
||||
if os.path.isfile(INPUT_CONFIG_PATH): # 存在
|
||||
# 读取JSON文件
|
||||
with open(INPUT_CONFIG_PATH, "r") as f:
|
||||
try :
|
||||
data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(str(e))
|
||||
try:
|
||||
update_version = data['version']
|
||||
if "=" in update_version:
|
||||
update_version = update_version.split('=')[-1].strip()
|
||||
except Exception as e:
|
||||
logging.error("get_default_version error: %s .",str(e))
|
||||
version_path = "/etc/os-release"
|
||||
if os.path.isfile(version_path):
|
||||
with open(version_path, "r+") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if "KYLIN_RELEASE_ID" in line:
|
||||
os_version = line.split('=')[1]
|
||||
os_version = os_version.strip().strip('"')
|
||||
logging.info('Get default update_version: %s, os_version: %s .', update_version, os_version)
|
||||
|
||||
return str(update_version),str(os_version)
|
||||
|
||||
def get_current_version(self):
|
||||
os_version = ''
|
||||
update_version = ''
|
||||
try:
|
||||
if not os.path.exists("/etc/kylin-version/kylin-system-version.conf"):
|
||||
logging.warning("System version file doesn't exist.")
|
||||
return os_version,update_version
|
||||
os_version = eval(str(self.window_main.sqlite3_server.ucconfigs.get("SYSTEM","os_version")))
|
||||
update_version = str(self.window_main.sqlite3_server.ucconfigs.get("SYSTEM","update_version"))
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return update_version,os_version
|
||||
logging.info('Current os_version: %s, release_id: %s .', os_version, update_version)
|
||||
return str(update_version),str(os_version)
|
||||
|
||||
def get_cn_appname(self, name):
|
||||
try:
|
||||
SC_DB_FILE = "/usr/share/kylin-software-center/data/uksc.db"
|
||||
if os.path.isfile(SC_DB_FILE):
|
||||
connect = sqlite3.connect(SC_DB_FILE, check_same_thread=False)
|
||||
cursor = connect.cursor()
|
||||
else:
|
||||
logging.warning("software center database isn't exist .")
|
||||
return ""
|
||||
sql = "select display_name_cn from application where display_name='"+name+"'"
|
||||
cursor.execute(sql)
|
||||
connect.commit()
|
||||
retval = cursor.fetchone()
|
||||
connect.close()
|
||||
if retval != None and len(retval) != 0:
|
||||
return str(retval[0])
|
||||
else:
|
||||
return ''
|
||||
except Exception as e:
|
||||
logging.error(_("Failed to initialize the database: %s"), str(e))
|
||||
return ''
|
||||
|
||||
def insert_upgrade_history(self, args, caller):
|
||||
caller_list = ['kylin-unattended-upgrade', "d-feet", "root"]
|
||||
_in_list = False
|
||||
for cl in caller_list:
|
||||
if caller in cl:
|
||||
_in_list = True
|
||||
if _in_list == False:
|
||||
logging.warning("Caller \" %s \": Operation without permission...", caller)
|
||||
return False
|
||||
# {"appname":GLib.Variant("s", "kylin-system-updater"), "version":GLib.Variant("s", "0.0")}
|
||||
# "description":GLib.Variant("s", "Update Manager for Kylin"), "date":GLib.Variant("s", "2022-07-27 15:23:51")
|
||||
# "status":GLib.Variant("s", "failed"), "keyword":GLib.Variant("s", "1")
|
||||
# "errorcode":GLib.Variant("s", "System upgrade is complete. "), "appname_cn":GLib.Variant("s", "音乐")
|
||||
upgrade_info = {}
|
||||
try:
|
||||
for it in args:
|
||||
upgrade_info[str(it)] = str(args[str(it)])
|
||||
logging.info("upgrade_info: %s", upgrade_info)
|
||||
|
||||
if "appname" in upgrade_info.keys() and "version" in upgrade_info.keys() \
|
||||
and "description" in upgrade_info.keys() \
|
||||
and "date" in upgrade_info.keys() \
|
||||
and "status" in upgrade_info.keys() \
|
||||
and "keyword" in upgrade_info.keys() \
|
||||
and "errorcode" in upgrade_info.keys() \
|
||||
and "appname_cn" in upgrade_info.keys() \
|
||||
and "status_cn" in upgrade_info.keys() \
|
||||
and "changelog" in upgrade_info.keys():
|
||||
appname = upgrade_info["appname"]
|
||||
if "kylin-unattended-upgrade" == appname:
|
||||
upgrade_info["appname"] = self.get_cn_appname(appname)
|
||||
if upgrade_info["appname"] == "":
|
||||
upgrade_info["appname"] = _("kylin-unattended-upgrade")
|
||||
if appname in self.window_main.cache and upgrade_info["description"] == "":
|
||||
pkg = self.window_main.cache[appname]
|
||||
if pkg.is_installed:
|
||||
upgrade_info["description"] = pkg.installed.description
|
||||
self.insert_into_updateinfo( upgrade_info["appname"], upgrade_info["version"], \
|
||||
upgrade_info["description"], \
|
||||
upgrade_info["date"], \
|
||||
upgrade_info["status"], \
|
||||
upgrade_info["keyword"], \
|
||||
upgrade_info["errorcode"], \
|
||||
upgrade_info["appname_cn"], \
|
||||
upgrade_info["status_cn"], \
|
||||
upgrade_info["changelog"] )
|
||||
else:
|
||||
logging.warning("Incomplete field.")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return False
|
||||
class DataMigration():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
#connect连接数据库
|
||||
def connect_database(self):
|
||||
try:
|
||||
self.connect = sqlite3.connect(DB_FILE, check_same_thread=False)
|
||||
self.cursor = self.connect.cursor()
|
||||
except Exception as e:
|
||||
logging.error("Failed to connect database: %s", str(e))
|
||||
|
||||
#disconnect连接数据库
|
||||
def disconnect_database(self):
|
||||
try:
|
||||
if self.connect != None:
|
||||
self.connect.close()
|
||||
if self.connect != None:
|
||||
del self.cursor
|
||||
except Exception as e:
|
||||
logging.error("Failed to disconnect database: %s", str(e))
|
||||
|
||||
def MarkFirstMigration(self):
|
||||
if (os.path.exists(DB_UPGRADE)):
|
||||
try:
|
||||
new_db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
new_db_cursor = new_db.cursor()
|
||||
|
||||
if (self._has_first_migration(new_db, new_db_cursor)): # 存在 firstmigration
|
||||
if (self._is_first_migration(new_db, new_db_cursor)):
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
else:# 不存在firstmigration
|
||||
# 新增 firstmigration 字段
|
||||
sql_commnd = "alter table display add column firstmigration text;"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
except Exception as e:
|
||||
logging.error("Failed to disconnect database: %s", str(e))
|
||||
else :
|
||||
logging.info("Not found kylin-system-updater.db, ensure that \'kylin-system-updater\' is successfully installed ... ")
|
||||
|
||||
def CopyData(self):
|
||||
# 判断数据库是否存在
|
||||
if (os.path.exists(VER_DB) and os.path.exists(DB_UPGRADE)):
|
||||
try:
|
||||
new_db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
new_db_cursor = new_db.cursor()
|
||||
ver_db = sqlite3.connect(VER_DB, check_same_thread=False)
|
||||
ver_db_cursor = ver_db.cursor()
|
||||
|
||||
if (self._has_first_migration(new_db, new_db_cursor)): # 存在 firstmigration
|
||||
if (self._is_first_migration(new_db, new_db_cursor)):
|
||||
# 数据迁移
|
||||
if (self.dateMigration(new_db=new_db, new_db_cursor=new_db_cursor)):
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
else:
|
||||
logging.info("No data migration is required ...")
|
||||
else:# 不存在firstmigration
|
||||
# 新增 firstmigration 字段
|
||||
sql_commnd = "alter table display add column firstmigration text;"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
sql_commnd = "UPDATE display SET firstmigration='yes';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
#数据迁移
|
||||
if (self.dateMigration(new_db=new_db, new_db_cursor=new_db_cursor)):
|
||||
sql_commnd = "UPDATE display SET firstmigration='false';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
except Exception as e:
|
||||
logging.error("Failed to disconnect database: %s", str(e))
|
||||
else :
|
||||
logging.info("Not found kylin-system-updater.db, ensure that \'kylin-system-updater\' is successfully installed ... ")
|
||||
|
||||
def _has_first_migration(self, new_db, new_db_cursor)->bool:
|
||||
try:
|
||||
sql_commnd = "select * from sqlite_master where type='table' and name='display';"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
retval = new_db_cursor.fetchone()
|
||||
for rv in retval:
|
||||
if "firstmigration" in str(rv):
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error("Failed to get field firstMigration: %s", str(e))
|
||||
return False
|
||||
|
||||
def _is_first_migration(self, new_db, new_db_cursor):
|
||||
try:
|
||||
sql_commnd = "select firstmigration from display;"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
retval = new_db_cursor.fetchone()
|
||||
if "true" in retval or "yes" in retval:
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error("Failed to select firstMigration: %s", str(e))
|
||||
return False
|
||||
|
||||
def _is_display_exist_fields(self, field, db, db_cursor):
|
||||
try:
|
||||
sql_commnd = "select * from sqlite_master where type='table' and name='display';"
|
||||
db_cursor.execute(sql_commnd)
|
||||
retval = db_cursor.fetchone()
|
||||
for rv in retval:
|
||||
if field in str(rv):
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error("Failed to select %s: %s", field, str(e))
|
||||
return False
|
||||
|
||||
def _add_display_fields(self, fields_default):
|
||||
try:
|
||||
if "=" not in fields_default:
|
||||
print("format: field=value")
|
||||
return False
|
||||
field, value = fields_default.split('=')
|
||||
print(_("Loading Sqlite3Server..."))
|
||||
db = sqlite3.connect(DB_UPGRADE, check_same_thread=False)
|
||||
db_cursor = db.cursor()
|
||||
if self._is_display_exist_fields(field, db, db_cursor):
|
||||
print("field %s is exist."%field)
|
||||
return False
|
||||
# 字段不存在,新增字段
|
||||
sql_commnd = "alter table display add column "+field+" TEXT;"
|
||||
db_cursor.execute(sql_commnd)
|
||||
sql_commnd = "UPDATE display SET "+field+"='"+value+"'"
|
||||
db_cursor.execute(sql_commnd)
|
||||
db.commit()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
print("Succeeded in adding field: '%s' "%field)
|
||||
return True
|
||||
|
||||
def dateMigration(self,new_db,new_db_cursor,old_db=None,old_db_cursor=None)->bool:
|
||||
sql_commnd = ""
|
||||
update_record_dict = {}
|
||||
tmp_update_record_dict = []
|
||||
old_cfg_dict = {}
|
||||
new_cfg_dict = {}
|
||||
|
||||
try:
|
||||
# step 1: 数据库初始化
|
||||
if old_db==None and old_db_cursor==None:
|
||||
old_db = sqlite3.connect(DB_UPDATER, check_same_thread=False)
|
||||
old_db_cursor = old_db.cursor()
|
||||
|
||||
# step 2: 获取更新数据
|
||||
sql_commnd = "SELECT * FROM installed"
|
||||
old_db_cursor.execute(sql_commnd)
|
||||
update_record = old_db_cursor.fetchall()
|
||||
|
||||
for ur in update_record:
|
||||
id,appname,version,time,description,icon,statue,keyword,errorcode = ur
|
||||
if keyword == '2': #2:本条数据是deb安装记录,不迁移
|
||||
continue
|
||||
if errorcode in range(200):
|
||||
errorcode = 'null'
|
||||
update_record_dict.clear()
|
||||
update_record_dict.update({"appname":appname})
|
||||
update_record_dict.update({"version":version})
|
||||
update_record_dict.update({"time":time})
|
||||
update_record_dict.update({"description":description})
|
||||
update_record_dict.update({"icon":icon})
|
||||
if statue == 'Success':
|
||||
statue = 'success'
|
||||
elif statue == 'Fail':
|
||||
statue = 'failed'
|
||||
update_record_dict.update({"statue":statue})
|
||||
update_record_dict.update({"keyword":'1'})
|
||||
update_record_dict.update({"errorcode":errorcode})
|
||||
tmp_update_record_dict.append(update_record_dict.copy())
|
||||
|
||||
# 按时间排序
|
||||
tmp_update_record_dict = sorted(tmp_update_record_dict, key=itemgetter('time'))
|
||||
logging.info("Generate update records complete.")
|
||||
|
||||
# step 3: insert新生成的记录
|
||||
sql_commnd = "create table IF NOT EXISTS tmp('id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
|
||||
'appname' TEXT,\
|
||||
'version' TEXT,\
|
||||
'description' TEXT,\
|
||||
'date' TEXT,\
|
||||
'status' TEXT,\
|
||||
'keyword' TEXT,\
|
||||
'errorcode' TEXT,\
|
||||
'appname_cn' TEXT,\
|
||||
'status_cn' TEXT,\
|
||||
'changelog' TEXT) "
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
# 更新数据
|
||||
for urd in tmp_update_record_dict:
|
||||
new_db_cursor.execute(
|
||||
"insert into tmp (appname, version, description, date, status, keyword, errorcode) values(?,"
|
||||
"?,?,?,?,?,?)",
|
||||
(urd['appname'], urd['version'], urd['description'], urd['time'], urd['statue'], urd['keyword'], urd['errorcode']))
|
||||
new_db.commit()
|
||||
|
||||
# 备份updateinfos
|
||||
new_db_cursor.execute(
|
||||
"insert into tmp (appname, version, description, date, status, keyword, errorcode, appname_cn, status_cn, changelog) "
|
||||
"SELECT appname, version, description, date, status, keyword, errorcode, appname_cn, status_cn, changelog FROM updateinfos")
|
||||
new_db.commit()
|
||||
|
||||
# 删除updateinfos
|
||||
sql_commnd = "drop table updateinfos"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
|
||||
# 修改表名
|
||||
sql_commnd = "alter table tmp rename to updateinfos"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
logging.info("Insert update records complete.")
|
||||
|
||||
# step 4: 更新配置转移
|
||||
sql_commnd = "SELECT * FROM display where id=1"
|
||||
old_db_cursor.execute(sql_commnd)
|
||||
old_cfg = old_db_cursor.fetchone()
|
||||
if not old_cfg:
|
||||
logging.warning("Table 'display' is empty .")
|
||||
else:
|
||||
for od in old_db_cursor.description:
|
||||
old_cfg_dict.update({str(od[0]):old_cfg[old_db_cursor.description.index(od)]})
|
||||
if old_db != None:
|
||||
old_db.close()
|
||||
if old_db_cursor != None:
|
||||
del old_db_cursor
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_cfg = new_db_cursor.fetchone()
|
||||
for od in new_db_cursor.description:
|
||||
new_cfg_dict.update({str(od[0]):new_cfg[new_db_cursor.description.index(od)]})
|
||||
|
||||
sql_commnd = "UPDATE display set check_time='"+old_cfg_dict['check_time']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set update_time='"+old_cfg_dict['update_time']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set auto_check='"+old_cfg_dict['auto_check']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
sql_commnd = "UPDATE display set system_version='"+old_cfg_dict['system_version']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if old_cfg_dict['auto_backup'] != None:
|
||||
sql_commnd = "UPDATE display set auto_backup='"+old_cfg_dict['auto_backup']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if 'download_limit' in old_cfg_dict.keys() and old_cfg_dict['download_limit'] != None:
|
||||
sql_commnd = "UPDATE display set download_limit='"+old_cfg_dict['download_limit']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
if 'download_limit_value' in old_cfg_dict.keys() and old_cfg_dict['download_limit_value'] != None:
|
||||
sql_commnd = "UPDATE display set download_limit_value='"+old_cfg_dict['download_limit_value']+"' Where id=1"
|
||||
new_db_cursor.execute(sql_commnd)
|
||||
new_db.commit()
|
||||
|
||||
except Exception as e:
|
||||
logging.warning("Update table 'display' error: %s .",e)
|
||||
logging.info("The data migration is complete.")
|
||||
return True
|
||||
|
||||
def listtojsonstr(lists):
|
||||
import json
|
||||
jsonfile = json.dumps(lists)
|
||||
return jsonfile
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,124 @@
|
|||
import os
|
||||
from gettext import gettext as _
|
||||
import apt
|
||||
import logging
|
||||
import fcntl
|
||||
import apt_pkg
|
||||
|
||||
|
||||
class LogInstallProgress(apt.progress.base.InstallProgress):
|
||||
""" Install progress that writes to self.progress_log
|
||||
(/var/run/unattended-upgrades.progress by default)
|
||||
"""
|
||||
def __init__(self,file):
|
||||
# type: (str) -> None
|
||||
apt.progress.base.InstallProgress.__init__(self)
|
||||
self.output_logfd = None # type: int
|
||||
self.filename=file
|
||||
self.error_pkg=""
|
||||
self.errormsg=""
|
||||
# raise Exception("for test!!!")
|
||||
|
||||
def error(self,pkg, errormsg):
|
||||
logging.error(("Install mode - dpkg, Install error: %s"), errormsg)
|
||||
self.error_pkg=self.filename
|
||||
self.errormsg = errormsg
|
||||
|
||||
def status_change(self, pkg, percent, status):
|
||||
# type: (str, float, str) -> None
|
||||
logging.info(("pkg:%s,percent:%s,status:%s"),pkg,percent,status)
|
||||
with open(self.progress_log, "w") as f:
|
||||
f.write(("%s")%percent)
|
||||
f.write(_("当前进度: %s ,正在安装:%s,当前状态:%s") % (percent, pkg,status))
|
||||
f.write(_("Progress: %s %% (%s)") % (percent, pkg))
|
||||
|
||||
def _fixup_fds(self):
|
||||
# () -> None
|
||||
required_fds = [0, 1, 2, # stdin, stdout, stderr
|
||||
self.writefd,
|
||||
self.write_stream.fileno(),
|
||||
self.statusfd,
|
||||
self.status_stream.fileno()
|
||||
]
|
||||
# ensure that our required fds close on exec
|
||||
for fd in required_fds[3:]:
|
||||
old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
|
||||
# close all fds
|
||||
try:
|
||||
# PEP-446 implemented in Python 3.4 made all descriptors
|
||||
# CLOEXEC, but we need to be able to pass writefd to dpkg
|
||||
# when we spawn it
|
||||
os.set_inheritable(self.writefd, True)
|
||||
except AttributeError: # if we don't have os.set_inheritable()
|
||||
pass
|
||||
proc_fd = "/proc/self/fd"
|
||||
if os.path.exists(proc_fd):
|
||||
error_count = 0
|
||||
for fdname in os.listdir(proc_fd):
|
||||
try:
|
||||
fd = int(fdname)
|
||||
except Exception:
|
||||
print("ERROR: can not get fd for %s" % fdname)
|
||||
if fd in required_fds:
|
||||
continue
|
||||
try:
|
||||
os.close(fd)
|
||||
# print("closed: ", fd)
|
||||
except OSError as e:
|
||||
# there will be one fd that can not be closed
|
||||
# as its the fd from pythons internal diropen()
|
||||
# so its ok to ignore one close error
|
||||
error_count += 1
|
||||
if error_count > 1:
|
||||
print("ERROR: os.close(%s): %s" % (fd, e))
|
||||
|
||||
def _redirect_stdin(self):
|
||||
# type: () -> None
|
||||
REDIRECT_INPUT = os.devnull
|
||||
fd = os.open(REDIRECT_INPUT, os.O_RDWR)
|
||||
os.dup2(fd, 0)
|
||||
|
||||
def _redirect_output(self):
|
||||
# type: () -> None
|
||||
# do not create log in dry-run mode, just output to stdout/stderr
|
||||
if not apt_pkg.config.find_b("Debug::pkgDPkgPM", False):
|
||||
logfd = self._get_logfile_dpkg_fd()
|
||||
os.dup2(logfd, 1)
|
||||
os.dup2(logfd, 2)
|
||||
|
||||
def _get_logfile_dpkg_fd(self):
|
||||
# type: () -> int
|
||||
logfd = os.open(
|
||||
"/var/log/kylin-system-updater/kylin-system-updater.log.1", os.O_RDWR | os.O_APPEND | os.O_CREAT, 0o640)
|
||||
try:
|
||||
import grp
|
||||
adm_gid = grp.getgrnam("adm").gr_gid
|
||||
os.fchown(logfd, 0, adm_gid)
|
||||
except (KeyError, OSError):
|
||||
pass
|
||||
return logfd
|
||||
|
||||
def update_interface(self):
|
||||
# type: () -> None
|
||||
# call super class first
|
||||
apt.progress.base.InstallProgress.update_interface(self)
|
||||
|
||||
def _log_in_dpkg_log(self, msg):
|
||||
# type: (str) -> None
|
||||
logfd = self._get_logfile_dpkg_fd()
|
||||
os.write(logfd, msg.encode("utf-8"))
|
||||
os.close(logfd)
|
||||
|
||||
def finish_update(self):
|
||||
# if error_status == 1:
|
||||
# os._exit(1)
|
||||
pass
|
||||
|
||||
def fork(self):
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
self._fixup_fds()
|
||||
self._redirect_stdin()
|
||||
self._redirect_output()
|
||||
return pid
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/python3
|
||||
# DistUpgradeConfigParser.py
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
class Singleton(object):
|
||||
def __init__(self, cls):
|
||||
self._cls = cls
|
||||
self._instance = {}
|
||||
def __call__(self):
|
||||
if self._cls not in self._instance:
|
||||
self._instance[self._cls] = self._cls()
|
||||
return self._instance[self._cls]
|
||||
|
||||
@Singleton
|
||||
class JsonConfig():
|
||||
NOW_UPDATE_CONFIG = '/usr/share/kylin-update-desktop-config/config/kylin-update-desktop-system.json'
|
||||
|
||||
def __init__(self):
|
||||
self._configDate = None
|
||||
self.read()
|
||||
|
||||
def read(self):
|
||||
try:
|
||||
with open(self.NOW_UPDATE_CONFIG,'r') as f:
|
||||
self._configDate = json.load(f)
|
||||
logging.info("Finished: refreshing Json Configuration File Successfully...")
|
||||
except Exception as exc:
|
||||
self._configDate = None
|
||||
|
||||
def getWithDefault(self,key1=None,key2=None,key3=None,key4=None,default=None):
|
||||
try:
|
||||
if self._configDate == None:
|
||||
return default
|
||||
|
||||
if key4 != None:
|
||||
return self._configDate[key1][key2][key3][key4]
|
||||
elif key3 != None:
|
||||
return self._configDate[key1][key2][key3]
|
||||
elif key2 != None:
|
||||
return self._configDate[key1][key2]
|
||||
elif key1 != None:
|
||||
return self._configDate[key1]
|
||||
else:
|
||||
return self._configDate
|
||||
except Exception as e:
|
||||
logging.warning(str(e))
|
||||
return default
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#参考文档: https://cuiqingcai.com/6080.html
|
||||
|
||||
import os
|
||||
|
||||
path = '/var/log/kylin-system-updater/'
|
||||
|
||||
numlist = []
|
||||
|
||||
def get_FileSize(filePath):
|
||||
fsize = os.path.getsize(filePath)
|
||||
fsize = fsize / float(1024 * 1024)
|
||||
return round(fsize, 2)
|
||||
|
||||
#日志回滚
|
||||
def get_logfile():
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
return os.path.join(path, "kylin-system-updater.log.1")
|
||||
#优先获取当前未写满100M的日志编号文件
|
||||
for i in os.listdir(path):
|
||||
if "kylin-system-updater.log." in os.path.basename(path + i):
|
||||
numlist.append((path + i).split(".")[2])
|
||||
if get_FileSize(path + i) < 100:
|
||||
return path + i
|
||||
#获取1-5未使用的最小数字的标号作为日志文件
|
||||
for i in range(1, 6):
|
||||
if str(i) not in numlist:
|
||||
return(os.path.join(path, ("kylin-system-updater.log.%s") % i))
|
||||
try:
|
||||
#编号1-5日志文件均写满时,删除第一个,往前移动日志编号,获取最后一个编号作为日志文件
|
||||
if len(numlist) != 0:
|
||||
os.remove(os.path.join(path, "kylin-system-updater.log.1"))
|
||||
for i in range(2, 6):
|
||||
os.rename(os.path.join(path, ("kylin-system-updater.log.%s") % i),
|
||||
os.path.join(path, ("kylin-system-updater.log.%s") % (i - 1)))
|
||||
return os.path.join(path, "kylin-system-updater.log.5")
|
||||
#默认情况下未生成任何日志时使用编号1的日志文件
|
||||
else:
|
||||
return os.path.join(path, "kylin-system-updater.log.1")
|
||||
except:
|
||||
return os.path.join(path, "kylin-system-updater.log.1")
|
||||
|
||||
def upgrade_strategies_logfile():
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
#优先获取当前未写满100M的日志编号文件
|
||||
for i in os.listdir(path):
|
||||
if "upgrade-strategies-daemon.log." in os.path.basename(path + i):
|
||||
numlist.append((path + i).split(".")[2])
|
||||
if get_FileSize(path + i) < 10:
|
||||
return path + i
|
||||
#获取1-5未使用的最小数字的标号作为日志文件
|
||||
for i in range(1, 6):
|
||||
if str(i) not in numlist:
|
||||
return(os.path.join(path, ("upgrade-strategies-daemon.log.%s") % i))
|
||||
try:
|
||||
#编号1-5日志文件均写满时,删除第一个,往前移动日志编号,获取最后一个编号作为日志文件
|
||||
if len(numlist) != 0:
|
||||
os.remove(os.path.join(path, "upgrade-strategies-daemon.log.1"))
|
||||
for i in range(2, 6):
|
||||
os.rename(os.path.join(path, ("upgrade-strategies-daemon.log.%s") % i),
|
||||
os.path.join(path, ("upgrade-strategies-daemon.log.%s") % (i - 1)))
|
||||
return os.path.join(path, "upgrade-strategies-daemon.log.5")
|
||||
#默认情况下未生成任何日志时使用编号1的日志文件
|
||||
else:
|
||||
return os.path.join(path, "upgrade-strategies-daemon.log.1")
|
||||
except:
|
||||
return os.path.join(path, "upgrade-strategies-daemon.log.1")
|
|
@ -0,0 +1,88 @@
|
|||
# MyCache.py
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2004-2008 Canonical
|
||||
#
|
||||
# Author: Michael Vogt <mvo@debian.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
|
||||
import gi
|
||||
gi.require_version('OSTree', '1.0')
|
||||
from gi.repository import OSTree
|
||||
import logging
|
||||
|
||||
LOCAL_SUMMARY_DATA = "/var/ostree-summary"
|
||||
|
||||
class MyCache():
|
||||
def __init__(self):
|
||||
# sysroot
|
||||
self.sysroot = OSTree.Sysroot.new_default()
|
||||
self.sysroot.set_mount_namespace_in_use()
|
||||
self.sysroot.initialize()
|
||||
self.sysroot.load()
|
||||
|
||||
self.deployment = self.sysroot.get_booted_deployment()
|
||||
|
||||
self.cur_checksum = self.deployment.get_csum()
|
||||
|
||||
self.osname = self.deployment.get_osname()
|
||||
|
||||
oringin_f = self.deployment.get_origin()
|
||||
refspec = oringin_f.get_string("origin","refspec")
|
||||
ret,self.origin_remote,self.origin_ref = OSTree.parse_refspec(refspec)
|
||||
|
||||
self.available_checksum = self.cur_checksum
|
||||
self.available_refs = self.origin_ref
|
||||
|
||||
def is_upgradable(self):
|
||||
return self.available_checksum != self.deployment.get_osname()
|
||||
|
||||
def _initDepCache(self):
|
||||
self._depcache.read_pinfile()
|
||||
self._depcache.init()
|
||||
|
||||
def clear(self):
|
||||
self._initDepCache()
|
||||
|
||||
def list_refs(self):
|
||||
repo = self.sysroot.repo()
|
||||
|
||||
ret,all_refs = repo.list_refs(None,None)
|
||||
|
||||
refs = list(all_refs.keys())
|
||||
|
||||
return refs
|
||||
|
||||
def rollback_deployment(self):
|
||||
repo = self.sysroot.repo()
|
||||
out_pending,out_rollback = self.sysroot.query_deployments_for(self.osname)
|
||||
|
||||
if out_rollback:
|
||||
rollback_checksum = self.deployment.get_csum()
|
||||
|
||||
ret,metadata = repo.load_variant(OSTree.ObjectType.COMMIT,rollback_checksum)
|
||||
|
||||
n_metadata = metadata[0]
|
||||
|
||||
return n_metadata
|
||||
else:
|
||||
return ""
|
||||
|
||||
def get_metadata(self,checksum):
|
||||
repo = self.sysroot.repo()
|
||||
ret,metadata = repo.load_variant(OSTree.ObjectType.COMMIT,checksum)
|
||||
return metadata[0]
|
|
@ -0,0 +1,580 @@
|
|||
#!/usr/bin/python3
|
||||
import apt
|
||||
import apt_pkg
|
||||
import fnmatch
|
||||
import logging
|
||||
import logging.handlers
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
import subprocess
|
||||
import json
|
||||
try:
|
||||
from typing import List
|
||||
from typing import Union
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from gettext import gettext as _
|
||||
|
||||
SYSTEM_UPDATER_CORE_LIB_PATH="/usr/share/kylin-system-updater/"
|
||||
sys.path.append(SYSTEM_UPDATER_CORE_LIB_PATH)
|
||||
from SystemUpdater.Core.utils import get_config_patch
|
||||
|
||||
ImportantListPath="/var/lib/kylin-software-properties/template/important.list"
|
||||
SOURCESLIST = "/etc/apt/sources.list"
|
||||
|
||||
# no py3 lsb_release in debian :/
|
||||
DISTRO_CODENAME = subprocess.check_output(
|
||||
["lsb_release", "-c", "-s"], universal_newlines=True).strip() # type: str
|
||||
DISTRO_DESC = subprocess.check_output(
|
||||
["lsb_release", "-d", "-s"], universal_newlines=True).strip() # type: str
|
||||
DISTRO_ID = subprocess.check_output(
|
||||
["lsb_release", "-i", "-s"], universal_newlines=True).strip() # type: str
|
||||
|
||||
ARCHITECTUREMAP = ['arm64','amd64','armhf','i386','loongarch64','mips64el','sw64']
|
||||
|
||||
RELEASEOFFSET = 1
|
||||
ORIGINOFFSET = 2
|
||||
HTTPTYPE = "HTTP"
|
||||
FTPTYPE = "FTP"
|
||||
|
||||
class UpdateListFilterCache(apt.Cache):
|
||||
|
||||
def __init__(self, window_main):
|
||||
self.window_main = window_main
|
||||
# whitelist
|
||||
self.upgradeList = []
|
||||
# 必须升级的包
|
||||
self.installList = []
|
||||
|
||||
self.config_path = get_config_patch()
|
||||
|
||||
# 获取源属性
|
||||
self.origin_property = OriginProperty()
|
||||
self.origin_property.get_allowed_sources()
|
||||
self.origin_property.get_allowed_origin()
|
||||
|
||||
self.allowed_origins = get_allowed_origins(self.origin_property.allow_origin)
|
||||
|
||||
self.allowed_origins = deleteDuplicatedElementFromList(self.allowed_origins)
|
||||
logging.info(_("Allowed origins: %s"),
|
||||
self.allowed_origins)
|
||||
|
||||
# self.blacklist = apt_pkg.config.value_list(
|
||||
# "Kylin-system-updater::Package-Blacklist")
|
||||
# self.blacklist = deleteDuplicatedElementFromList(self.blacklist)
|
||||
|
||||
# self.whitelist = apt_pkg.config.value_list(
|
||||
# "Kylin-system-updater::Package-Whitelist")
|
||||
# self.whitelist = deleteDuplicatedElementFromList(self.whitelist)
|
||||
|
||||
# self.strict_whitelist = apt_pkg.config.find_b(
|
||||
# "Kylin-system-updater::Package-Whitelist-Strict", False)
|
||||
|
||||
def checkInCache(self):
|
||||
logging.info("start Check in cache")
|
||||
tmplist = []
|
||||
cache = apt.Cache()
|
||||
for i in self.upgradeList:
|
||||
try:
|
||||
cache[i]
|
||||
tmplist.append(i)
|
||||
except Exception as e:
|
||||
pass
|
||||
self.upgradeList = tmplist
|
||||
|
||||
def initLocalPackagesList(self):
|
||||
jsonfiles = []
|
||||
tmplist = []
|
||||
|
||||
# 获取importantlist 本次更新推送
|
||||
with open(ImportantListPath, 'r') as f:
|
||||
text = f.read()
|
||||
importantList = text.split()
|
||||
logging.info("importantList: %s",importantList)
|
||||
f.close()
|
||||
|
||||
if not importantList:
|
||||
logging.error("importantList is empty")
|
||||
exit(-1)
|
||||
|
||||
# 获取/usr/share/kylin-update-desktop-config/data/下所有json文件
|
||||
for root,dirs,files in os.walk(self.config_path):
|
||||
pass
|
||||
for i in files:
|
||||
if ".json" in i:
|
||||
jsonfiles.append(i.split('.')[0])
|
||||
|
||||
# 找到importantlist中对应的json文件
|
||||
for i in importantList:
|
||||
if i not in jsonfiles:
|
||||
# 说明这个是单独的包,不在分组中
|
||||
# 加入更新列表
|
||||
if i not in self.upgradeList:
|
||||
self.upgradeList.append(i)
|
||||
else:
|
||||
# 在分组中
|
||||
# 获取每个对应json文件中的upgrade_list
|
||||
if i in jsonfiles:
|
||||
filepath = os.path.join(self.config_path, i)
|
||||
filepath = filepath+".json"
|
||||
with open(filepath, 'r') as f:
|
||||
pkgdict = f.read()
|
||||
jsonfile = json.loads(pkgdict)
|
||||
tmplist = jsonfile['install_list']
|
||||
for j in tmplist:
|
||||
if j not in self.upgradeList:
|
||||
self.upgradeList.append(j)
|
||||
f.close()
|
||||
|
||||
# 更改:传入包列表,经过源过滤,返回的pkg中进行版本调整
|
||||
def check_in_allowed_origin(self, pkg_lists, _is_adjust):
|
||||
new_upgrade_pkgs = []
|
||||
adjust_candidate_pkgs = []
|
||||
for pkg in pkg_lists:
|
||||
try:
|
||||
new_ver = ver_in_allowed_origin(pkg, self.allowed_origins)
|
||||
if _is_adjust and len(new_ver) == 0:
|
||||
logging.warning("< %s > did not find a suitable version..." % pkg.name)
|
||||
continue
|
||||
if len(new_ver) == 0:
|
||||
continue
|
||||
if not pkg.installed: # 判断安装列表
|
||||
if pkg.candidate == new_ver[0] and pkg not in new_upgrade_pkgs:
|
||||
new_upgrade_pkgs.append(pkg)
|
||||
elif new_ver[0] != pkg.candidate and pkg not in new_upgrade_pkgs:
|
||||
logging.info("adjusting candidate version: %s" % new_ver[0])
|
||||
if _is_adjust == True:
|
||||
pkg.candidate = new_ver[0]
|
||||
adjust_candidate_pkgs.append(pkg.name+"="+pkg.candidate.version)
|
||||
new_upgrade_pkgs.append(pkg)
|
||||
else: # 判断升级列表
|
||||
for nv in new_ver:
|
||||
if nv > pkg.installed and nv != pkg.candidate:
|
||||
logging.info("adjusting candidate version: %s" % nv)
|
||||
if _is_adjust == True:
|
||||
pkg.candidate = nv
|
||||
adjust_candidate_pkgs.append(pkg.name+"="+pkg.candidate.version)
|
||||
break
|
||||
elif nv > pkg.installed and nv == pkg.candidate:
|
||||
new_upgrade_pkgs.append(pkg)
|
||||
break
|
||||
elif _is_adjust == True:
|
||||
logging.warning("< %s > did not find a suitable version..." % pkg.name)
|
||||
except NoAllowedOriginError:
|
||||
logging.error("Cannot found allowed version: %s", pkg.name)
|
||||
continue
|
||||
|
||||
return (new_upgrade_pkgs, adjust_candidate_pkgs)
|
||||
|
||||
def is_pkgname_in_blacklist(self, pkgs):
|
||||
blacklist_filter_pkgs = []
|
||||
for pkg in pkgs:
|
||||
if pkg.name in self.blacklist:
|
||||
pass
|
||||
else :
|
||||
blacklist_filter_pkgs.append(pkg)
|
||||
|
||||
return blacklist_filter_pkgs
|
||||
|
||||
def is_pkgname_in_whitelist(self, pkgs):
|
||||
whitelist_filter_upgrade_pkgs = []
|
||||
for pkg in pkgs:
|
||||
if pkg.name in self.upgradeList:
|
||||
whitelist_filter_upgrade_pkgs.append(pkg)
|
||||
else :
|
||||
pkg.mark_keep()
|
||||
return whitelist_filter_upgrade_pkgs
|
||||
|
||||
class OriginProperty():
|
||||
|
||||
def __init__(self):
|
||||
# 包含了本地所有源 http & ftp
|
||||
self.local_sourcelist = {"http":[],"ftp":[]}
|
||||
# 经过解析后的本地源,获取所有的分发属性
|
||||
self.local_origin = {"http":[],"ftp":[]}
|
||||
# 允许的源列表
|
||||
self.allow_sources = []
|
||||
# 允许的源+属性
|
||||
self.allow_origin = {"http":[],"ftp":[]}
|
||||
# 加载本地所有源
|
||||
self.init_local_origin()
|
||||
# 进行属性解析
|
||||
self.analytic_properties(self.local_sourcelist)
|
||||
|
||||
def init_local_origin(self):
|
||||
http_origin = {}
|
||||
ftp_orgin = {}
|
||||
#apt policy
|
||||
sh_retval = os.popen("apt-cache policy").read().split("\n")
|
||||
# policy = [ rv for rv in sh_retval if "http" in rv or "ftp" in rv or "release" in rv or "origin" in rv]
|
||||
for rv in sh_retval:
|
||||
if "http" in rv:
|
||||
http_origin['sources'] = rv
|
||||
http_origin['release'] = sh_retval[sh_retval.index(rv) + RELEASEOFFSET]
|
||||
http_origin['origin'] = sh_retval[sh_retval.index(rv) + ORIGINOFFSET]
|
||||
self.local_sourcelist['http'].append(http_origin.copy())
|
||||
elif "ftp" in rv:
|
||||
ftp_orgin['sources'] = rv
|
||||
ftp_orgin['release'] = sh_retval[sh_retval.index(rv) + RELEASEOFFSET]
|
||||
ftp_orgin['origin'] = sh_retval[sh_retval.index(rv) + ORIGINOFFSET]
|
||||
self.local_sourcelist['ftp'].append(ftp_orgin.copy())
|
||||
|
||||
def merge_origin(self, source_type, source_origin):
|
||||
is_append = True
|
||||
if source_type == HTTPTYPE:
|
||||
if self.local_origin['http']:
|
||||
for lo in self.local_origin['http']:
|
||||
if lo['origin_source'] == source_origin['origin_source'] and lo['dist'] == source_origin['dist']:
|
||||
lo['component'] = list(set(lo['component']).union(set(source_origin['component'])))
|
||||
is_append = False
|
||||
if is_append:
|
||||
self.local_origin['http'].append(source_origin.copy())
|
||||
else:
|
||||
self.local_origin['http'].append(source_origin.copy())
|
||||
elif source_type == FTPTYPE:
|
||||
if self.local_origin['ftp']:
|
||||
for lo in self.local_origin['ftp']:
|
||||
if lo['origin_source'] == source_origin['origin_source'] and lo['dist'] == source_origin['dist']:
|
||||
lo['component'] = list(set(lo['component']).union(set(source_origin['component'])))
|
||||
is_append = False
|
||||
if is_append:
|
||||
self.local_origin['ftp'].append(source_origin.copy())
|
||||
else:
|
||||
self.local_origin['ftp'].append(source_origin.copy())
|
||||
|
||||
def analytic_properties(self, local_sourcelist):
|
||||
http_origin = {"component":[],"release":{}}
|
||||
ftp_orgin = {"component":[],"release":{}}
|
||||
dist_list = []
|
||||
# 经过解析后的本地源,获取所有的分发属性
|
||||
for ls in local_sourcelist['http']:
|
||||
for item in filter(not_empty, ls['sources'].split(' ')):
|
||||
if item.isdigit():
|
||||
http_origin['policy_priority'] = item
|
||||
elif "http" in item:
|
||||
http_origin['origin_source'] = item
|
||||
elif "/" in item:
|
||||
dist_list = item.split("/")
|
||||
dist_list.pop()
|
||||
http_origin['dist'] = "/".join(dist_list)
|
||||
http_origin['component'].append(item.split("/")[1])
|
||||
elif item not in ARCHITECTUREMAP and item != "Packages":
|
||||
http_origin['component'].append(item)
|
||||
release_list = ls['release'].split(',')
|
||||
release_list = [ rl.strip() for rl in release_list ]
|
||||
if "release" in release_list[0]:
|
||||
release_list[0] = release_list[0].lstrip("release").strip()
|
||||
for rl in release_list:
|
||||
if "=" in rl:
|
||||
self.generate_dict(http_origin['release'], rl)
|
||||
for item in filter(not_empty, ls['origin'].split(' ')):
|
||||
if "origin" not in ls['origin']:
|
||||
break
|
||||
elif "origin" != item:
|
||||
http_origin['origin'] = item
|
||||
self.merge_origin(HTTPTYPE, http_origin)
|
||||
http_origin = {"component":[],"release":{}}
|
||||
|
||||
for ls in local_sourcelist['ftp']:
|
||||
for item in filter(not_empty, ls['sources'].split(' ')):
|
||||
if item.isdigit():
|
||||
ftp_orgin['policy_priority'] = item
|
||||
elif "ftp" in item:
|
||||
ftp_orgin['origin_source'] = item
|
||||
elif "/" in item:
|
||||
ftp_orgin['dist'] = item.split("/")[0]
|
||||
ftp_orgin['component'].append(item.split("/")[1])
|
||||
elif item not in ARCHITECTUREMAP and item != "Packages":
|
||||
ftp_orgin['component'].append(item)
|
||||
release_list = ls['release'].split(',')
|
||||
if "release " in release_list[0]:
|
||||
release_list[0] = release_list[0].lstrip("release ")
|
||||
for rl in release_list:
|
||||
if "=" in rl:
|
||||
self.generate_dict(ftp_orgin['release'], rl)
|
||||
for item in filter(not_empty, ls['origin'].split(' ')):
|
||||
if "origin" not in ls['origin']:
|
||||
break
|
||||
elif "origin" != item:
|
||||
ftp_orgin['origin'] = item
|
||||
self.merge_origin(FTPTYPE, ftp_orgin)
|
||||
ftp_orgin = {"component":[],"release":{}}
|
||||
|
||||
def generate_dict(self, dict, item):
|
||||
item = item.strip()
|
||||
if item == "":
|
||||
logging.warning("empty match string matches nothing")
|
||||
return False
|
||||
(what, value) = [ s for s in item.split("=")]
|
||||
if what in ('o', 'origin'):
|
||||
dict['origin'] = value
|
||||
elif what in ("l", "label"):
|
||||
dict['label'] = value
|
||||
elif what in ("a", "suite", "archive"):
|
||||
dict['archive'] = value
|
||||
elif what in ("c", "component"):
|
||||
dict['component'] = value
|
||||
elif what in ("site",):
|
||||
dict['site'] = value
|
||||
elif what in ("n", "codename",):
|
||||
dict['codename'] = value
|
||||
else:
|
||||
dict[what] = value
|
||||
# raise UnknownMatcherError(
|
||||
# "Unknown whitelist entry for matcher %s (value %s)" % (
|
||||
# what, value))
|
||||
|
||||
def get_allowed_sources(self):
|
||||
# 源地址,在本地源列表中查找. 源服务器下发source.list为允许的源, 本模块屏蔽了sources.list.d下的源
|
||||
# 获取允许的源
|
||||
try:
|
||||
old_sources_list = apt_pkg.config.find("Dir::Etc::sourcelist")
|
||||
old_sources_list_d = apt_pkg.config.find("Dir::Etc::sourceparts")
|
||||
old_cleanup = apt_pkg.config.find("APT::List-Cleanup")
|
||||
apt_pkg.config.set("Dir::Etc::sourcelist",
|
||||
os.path.abspath(SOURCESLIST))
|
||||
apt_pkg.config.set("Dir::Etc::sourceparts", "xxx")
|
||||
apt_pkg.config.set("APT::List-Cleanup", "0")
|
||||
slist = apt_pkg.SourceList()
|
||||
slist.read_main_list()
|
||||
self.allow_sources = slist.list
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
finally:
|
||||
apt_pkg.config.set("Dir::Etc::sourcelist",
|
||||
old_sources_list)
|
||||
apt_pkg.config.set("Dir::Etc::sourceparts",
|
||||
old_sources_list_d)
|
||||
apt_pkg.config.set("APT::List-Cleanup",
|
||||
old_cleanup)
|
||||
|
||||
def get_allowed_origin(self):
|
||||
# 获取允许的源
|
||||
# 生成源与属性
|
||||
self.local_origin
|
||||
self.allow_sources
|
||||
self.allow_origin
|
||||
try:
|
||||
for item in self.allow_sources:
|
||||
for lo in self.local_origin['http']:
|
||||
if item.uri.strip('/') == lo['origin_source'].strip('/') and item.dist == lo['dist']:
|
||||
self.allow_origin['http'].append(lo)
|
||||
for lo in self.local_origin['ftp']:
|
||||
if item.uri.strip('/') == lo['origin_source'].strip('/') and item.dist == lo['dist']:
|
||||
self.allow_origin['ftp'].append(lo)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
class UnattendUpgradeFilter():
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
def GetAllowOrigins(self):
|
||||
# 获取源属性
|
||||
self.origin_property = OriginProperty()
|
||||
self.origin_property.get_allowed_sources()
|
||||
self.origin_property.get_allowed_origin()
|
||||
|
||||
self.allowed_origins = get_allowed_origins(self.origin_property.allow_origin)
|
||||
|
||||
self.allowed_origins = deleteDuplicatedElementFromList(self.allowed_origins)
|
||||
logging.info(_("Allowed origins: %s"),
|
||||
self.allowed_origins)
|
||||
return self.allowed_origins
|
||||
|
||||
|
||||
def ver_in_allowed_origin(pkg, allow_origin):
|
||||
# type: (apt.Package, List[str]) -> apt.package.Version
|
||||
allown_versions = []
|
||||
versions = _get_priority_order(pkg)
|
||||
# 获取每个优先级别中 允许源的最高版本
|
||||
allown_versions = _get_allowed_list(versions, allow_origin)
|
||||
|
||||
return allown_versions
|
||||
|
||||
def _get_priority_order(pkg):
|
||||
versions = []
|
||||
for ver in pkg.versions:
|
||||
if versions:
|
||||
for v in versions:
|
||||
if v.policy_priority >= ver.policy_priority and v == versions[-1]:
|
||||
break
|
||||
elif v.policy_priority >= ver.policy_priority and v != versions[-1]:
|
||||
continue
|
||||
else:
|
||||
index = versions.index(v)
|
||||
versions.insert(index,ver)
|
||||
break
|
||||
if v == versions[-1] and versions[-1].policy_priority >= ver.policy_priority:
|
||||
versions.append(ver)
|
||||
else:
|
||||
versions.append(ver)
|
||||
return versions
|
||||
|
||||
def _get_allowed_list(versions, allow_origin):
|
||||
current_priority = -100
|
||||
allown_versions = []
|
||||
for ver in versions:
|
||||
if current_priority != ver.policy_priority:
|
||||
if is_in_allowed_origin(ver, allow_origin):
|
||||
allown_versions.append(ver)
|
||||
current_priority = ver.policy_priority
|
||||
else:
|
||||
continue
|
||||
return allown_versions
|
||||
|
||||
def get_allowed_origins(allow_origin):
|
||||
""" return a list of allowed origins
|
||||
"""
|
||||
allowed_origins = []
|
||||
origin = ''
|
||||
archive = ''
|
||||
uri = ''
|
||||
label = ''
|
||||
for ao in (allow_origin['http']+allow_origin['ftp']):
|
||||
if 'origin' in ao['release']:
|
||||
origin = 'o='+ao['release']['origin']
|
||||
else:
|
||||
origin = 'o='
|
||||
if 'archive' in ao['release']:
|
||||
archive = 'a='+ao['release']['archive']
|
||||
else:
|
||||
archive = 'a='
|
||||
if 'label' in ao['release']:
|
||||
label = 'l='+ao['release']['label']
|
||||
else:
|
||||
label = 'l='
|
||||
if 'origin_source' in ao:
|
||||
uri = 'uri='+ao['origin_source']
|
||||
else:
|
||||
uri = 'uri='
|
||||
allowed_origins.append(origin+","+archive+","+label+","+uri)
|
||||
return allowed_origins
|
||||
|
||||
def get_allowed_origins_legacy():
|
||||
# type: () -> List[str]
|
||||
""" legacy support for old Allowed-Origins var """
|
||||
allowed_origins = [] # type: List[str]
|
||||
key = "Kylin-system-updater::Allowed-Origins"
|
||||
try:
|
||||
for s in apt_pkg.config.value_list(key):
|
||||
# if there is a ":" use that as seperator, else use spaces
|
||||
if re.findall(r'(?<!\\):', s):
|
||||
(distro_id, distro_codename) = re.split(r'(?<!\\):', s)
|
||||
else:
|
||||
(distro_id, distro_codename) = s.split()
|
||||
# unescape "\:" back to ":"
|
||||
distro_id = re.sub(r'\\:', ':', distro_id)
|
||||
# escape "," (see LP: #824856) - can this be simpler?
|
||||
distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id)
|
||||
distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename)
|
||||
# convert to new format
|
||||
allowed_origins.append("o=%s,a=%s" % (substitute(distro_id),
|
||||
substitute(distro_codename)))
|
||||
except ValueError:
|
||||
logging.error(_("Unable to parse %s." % key))
|
||||
raise
|
||||
return allowed_origins
|
||||
|
||||
def substitute(line):
|
||||
# type: (str) -> str
|
||||
""" substitude known mappings and return a new string
|
||||
|
||||
Currently supported ${distro-release}
|
||||
"""
|
||||
mapping = {"distro_codename": get_distro_codename(),
|
||||
"distro_id": get_distro_id()}
|
||||
return string.Template(line).substitute(mapping)
|
||||
|
||||
|
||||
def get_distro_codename():
|
||||
# type: () -> str
|
||||
return DISTRO_CODENAME
|
||||
|
||||
|
||||
def get_distro_id():
|
||||
# type: () -> str
|
||||
return DISTRO_ID
|
||||
|
||||
def is_in_allowed_origin(ver, allowed_origins):
|
||||
# type: (apt.package.Version, List[str]) -> bool
|
||||
if not ver:
|
||||
return False
|
||||
for origin in ver.origins:
|
||||
if is_allowed_origin(origin, allowed_origins):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_allowed_origin(origin, allowed_origins):
|
||||
# type: (Union[apt.package.Origin, apt_pkg.PackageFile], List[str]) -> bool
|
||||
for allowed in allowed_origins:
|
||||
if match_whitelist_string(allowed, origin):
|
||||
return True
|
||||
return False
|
||||
|
||||
def match_whitelist_string(whitelist, origin):
|
||||
# type: (str, Union[apt.package.Origin, apt_pkg.PackageFile]) -> bool
|
||||
"""
|
||||
take a whitelist string in the form "origin=Debian,label=Debian-Security"
|
||||
and match against the given python-apt origin. A empty whitelist string
|
||||
never matches anything.
|
||||
"""
|
||||
whitelist = whitelist.strip()
|
||||
if whitelist == "":
|
||||
logging.warning("empty match string matches nothing")
|
||||
return False
|
||||
res = True
|
||||
# make "\," the html quote equivalent
|
||||
whitelist = whitelist.replace("\\,", "%2C")
|
||||
for token in whitelist.split(","):
|
||||
# strip and unquote the "," back
|
||||
(what, value) = [s.strip().replace("%2C", ",")
|
||||
for s in token.split("=")]
|
||||
# logging.debug("matching %s=%s against %s" % (
|
||||
# what, value, origin))
|
||||
# support substitution here as well
|
||||
value = substitute(value)
|
||||
# first char is apt-cache policy output, send is the name
|
||||
# in the Release file
|
||||
if what in ("o", "origin"):
|
||||
match = fnmatch.fnmatch(origin.origin, value)
|
||||
elif what in ("l", "label"):
|
||||
match = fnmatch.fnmatch(origin.label, value)
|
||||
elif what in ("a", "suite", "archive"):
|
||||
match = fnmatch.fnmatch(origin.archive, value)
|
||||
elif what in ("c", "component"):
|
||||
match = fnmatch.fnmatch(origin.component, value)
|
||||
elif what in ("site",):
|
||||
match = fnmatch.fnmatch(origin.site, value)
|
||||
elif what in ("n", "codename",):
|
||||
match = fnmatch.fnmatch(origin.codename, value)
|
||||
elif what in ("uri",):
|
||||
match = True
|
||||
else:
|
||||
raise UnknownMatcherError(
|
||||
"Unknown whitelist entry for matcher %s (token %s)" % (
|
||||
what, token))
|
||||
# update res
|
||||
res = res and match
|
||||
# logging.debug("matching %s=%s against %s" % (
|
||||
# what, value, origin))
|
||||
return res
|
||||
|
||||
def deleteDuplicatedElementFromList(list):
|
||||
resultList = []
|
||||
for item in list:
|
||||
if not item in resultList:
|
||||
resultList.append(item)
|
||||
return resultList
|
||||
|
||||
def not_empty(s):
|
||||
return s and s.strip()
|
||||
|
||||
class UnknownMatcherError(ValueError):
|
||||
pass
|
||||
|
||||
class NoAllowedOriginError(ValueError):
|
||||
pass
|
|
@ -0,0 +1,402 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
# 脚本插件化执行管理
|
||||
# TODO:
|
||||
# 使能/失能 --配置文件--ok
|
||||
# 错误码 --脚本/本程序--wait/add
|
||||
# 进度同步 --线程获取--add
|
||||
# 输出规范 --脚本/本程序(重定向日志文件、输出格式)--ok/ok
|
||||
# 元数据类型 --描述信息、翻译(配置文件)--ok
|
||||
# 运行等级 --(root/user)--wait
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
from sre_compile import isstring
|
||||
import threading
|
||||
import yaml
|
||||
import logging
|
||||
from gi.repository import GObject
|
||||
|
||||
class pluginState():
|
||||
PLUGIN_SUCCESS = 0
|
||||
PLUGINERR_PLUGIN_NOT_EXIST = PLUGIN_SUCCESS - 1
|
||||
PLUGINERR_PLUGIN_NOT_COMPLETED = PLUGINERR_PLUGIN_NOT_EXIST - 1
|
||||
PLUGINERR_NO_AVAILABLE_YAML = PLUGINERR_PLUGIN_NOT_COMPLETED - 1
|
||||
PLUGINERR_NOT_LOAD_ALL = PLUGINERR_NO_AVAILABLE_YAML - 1
|
||||
PLUGINERR_PLUGIN_NOT_IN_LIST = PLUGINERR_NOT_LOAD_ALL - 1
|
||||
PLUGINERR_PLUGIN_NOT_ENABLED = PLUGINERR_PLUGIN_NOT_IN_LIST - 1
|
||||
PLUGINERR_PLUGIN_CONFIG_FAILED = PLUGINERR_PLUGIN_NOT_ENABLED - 1
|
||||
PLUGINERR_LOG_PATH_NOT_EXIT = PLUGINERR_PLUGIN_CONFIG_FAILED - 1
|
||||
PLUGINERR_CONFIG_NOT_COMPLETED = PLUGINERR_LOG_PATH_NOT_EXIT - 1
|
||||
PLUGINERR_CMD_IS_NONE = PLUGINERR_CONFIG_NOT_COMPLETED - 1
|
||||
PLUGINERR_LANGUAGE_NOT_SUPPORT = PLUGINERR_CMD_IS_NONE - 1
|
||||
|
||||
_numToInfo = {
|
||||
PLUGIN_SUCCESS: 'success',
|
||||
PLUGINERR_PLUGIN_NOT_EXIST: 'plugin path not exist',
|
||||
PLUGINERR_PLUGIN_NOT_COMPLETED: 'plugin folder not completed',
|
||||
PLUGINERR_NO_AVAILABLE_YAML: 'there is no available yaml',
|
||||
PLUGINERR_NOT_LOAD_ALL: 'not run load_all',
|
||||
PLUGINERR_PLUGIN_NOT_IN_LIST: 'plugin not in loaded plugin list',
|
||||
PLUGINERR_PLUGIN_NOT_ENABLED: 'plugin not enabled',
|
||||
PLUGINERR_PLUGIN_CONFIG_FAILED: 'plugin config failed',
|
||||
PLUGINERR_LOG_PATH_NOT_EXIT: 'log path not exists',
|
||||
PLUGINERR_CONFIG_NOT_COMPLETED: 'config not completed',
|
||||
PLUGINERR_CMD_IS_NONE: 'cmd is none',
|
||||
PLUGINERR_LANGUAGE_NOT_SUPPORT: 'not support this language',
|
||||
}
|
||||
_infoToNum = {
|
||||
'success': PLUGIN_SUCCESS,
|
||||
'plugin path not exist': PLUGINERR_PLUGIN_NOT_EXIST,
|
||||
'plugin folder not completed': PLUGINERR_PLUGIN_NOT_COMPLETED,
|
||||
'there is no available yaml': PLUGINERR_NO_AVAILABLE_YAML,
|
||||
'not run load_all': PLUGINERR_NOT_LOAD_ALL,
|
||||
'plugin not in loaded plugin list': PLUGINERR_PLUGIN_NOT_IN_LIST,
|
||||
'plugin not enabled': PLUGINERR_PLUGIN_NOT_ENABLED,
|
||||
'plugin config failed': PLUGINERR_PLUGIN_CONFIG_FAILED,
|
||||
'log path not exists': PLUGINERR_LOG_PATH_NOT_EXIT,
|
||||
'config not completed': PLUGINERR_CONFIG_NOT_COMPLETED,
|
||||
'cmd is none': PLUGINERR_CMD_IS_NONE,
|
||||
'not support this language': PLUGINERR_LANGUAGE_NOT_SUPPORT,
|
||||
}
|
||||
|
||||
|
||||
PLUGIN_MANAGER_PATH = "./" # 可修改
|
||||
|
||||
# 目录结构 FILE PATH
|
||||
CFG_FILE = "conf.yaml"
|
||||
CFG_EX_DIR = "conf.d/"
|
||||
CFG_PATH = PLUGIN_MANAGER_PATH + CFG_FILE
|
||||
CFG_EX_PATH = PLUGIN_MANAGER_PATH + CFG_EX_DIR
|
||||
MOD_DIR = "modules/"
|
||||
MOD_PATH = PLUGIN_MANAGER_PATH + MOD_DIR
|
||||
MOD_AVAILABLE = "modules-available/"
|
||||
MOD_ENABLED = "modules-enabled/"
|
||||
MOD_AVAILABLE_PATH = MOD_PATH + MOD_AVAILABLE
|
||||
MOD_ENABLED_PATH = MOD_PATH + MOD_ENABLED
|
||||
PLUGIN_DIR = "script/"
|
||||
PLUGIN_PATH = PLUGIN_MANAGER_PATH + PLUGIN_DIR
|
||||
|
||||
# 配置 日志路径
|
||||
LOG_DIR_ROOT = '/var/log/kylin-system-updater/'
|
||||
# 默认插件日志路径
|
||||
PLUGIN_LOG_DIR = '/var/log/kylin-system-updater/plugin/'
|
||||
|
||||
# PLUGIN.YAML
|
||||
PLUGIN_CONF_KEY_NAME = 'name'
|
||||
PLUGIN_CONF_KEY_DESC = 'desc'
|
||||
PLUGIN_CONF_KEY_EXEC = 'exec'
|
||||
PLUGIN_CONF_KEY_LOGLEVEL = 'loglevel'
|
||||
PLUGIN_CONF_KEY_RUNLEVEL = 'runlevel'
|
||||
PLUGIN_CONF_KEY_LIST = [PLUGIN_CONF_KEY_NAME,PLUGIN_CONF_KEY_DESC,PLUGIN_CONF_KEY_EXEC,PLUGIN_CONF_KEY_LOGLEVEL,PLUGIN_CONF_KEY_RUNLEVEL]
|
||||
|
||||
# CONF.YAML AND CONF.D
|
||||
MANAGER_CONF_KEY_LOGDIR = "logdir"
|
||||
MANAGER_CONF_KEY_LIST = [MANAGER_CONF_KEY_LOGDIR, ]
|
||||
|
||||
|
||||
FORMAT = "%(asctime)s [%(levelname)s]: %(message)s"
|
||||
RUNLEVEL_LIST = ['ROOT', 'USER']
|
||||
LOGLEVEL_LIST = ['DEBUG', 'INFO', 'NOTIFY', 'WARNING', 'ERROR', 'CRITICAL']
|
||||
|
||||
class LOADSTATE():
|
||||
PLGNAME = 0x01
|
||||
EXECCMD = 0x02
|
||||
STATESUM = PLGNAME + EXECCMD
|
||||
|
||||
|
||||
LANG_KEY_ZH_CN = 'zh_CN'
|
||||
LANG_KEY_EN = 'en'
|
||||
class LANGLIST():
|
||||
LANG_EN = 0
|
||||
LANG_ZH_CN = 1
|
||||
|
||||
|
||||
class pluginClass(pluginState):
|
||||
|
||||
def __init__(self):
|
||||
# 必须配置项
|
||||
self.pluginName = None
|
||||
self.execCmd = None
|
||||
# 可选配置项
|
||||
self.descList = [] # en / zh
|
||||
self.logLevel = LOGLEVEL_LIST.index('DEBUG')
|
||||
self.runLevel = RUNLEVEL_LIST.index('ROOT')
|
||||
self.enabled = False
|
||||
# 合成变量
|
||||
self.cmd = None
|
||||
self.logDir = PLUGIN_LOG_DIR # 插件日志路径
|
||||
self.logPath = os.path.join(self.logDir, "default.log") # 插件日志文件
|
||||
self.fifoName = "default-fifo" # 插件进度文件
|
||||
# self.fifoPath = PLUGIN_PATH + self.fifoName
|
||||
self.fifoPath = "/var/log/kylin-system-updater"+self.fifoName
|
||||
# 记录变量
|
||||
self.running = False # 是否在运行
|
||||
self.process = 0 # 执行进度
|
||||
self.loadState = 0 # 插件配置完成
|
||||
logging.info("init finished.")
|
||||
|
||||
###################### 内部函数 ######################
|
||||
# 1-配置指定字段
|
||||
# 2-更新进度 (1/0.5s)
|
||||
# 3-
|
||||
######################
|
||||
def _config_key(self, cfg, key):
|
||||
if cfg == None or key == None or key not in cfg:
|
||||
logging.warning("[PLUGIN]: key[%s] not in yaml.", key)
|
||||
|
||||
if key == PLUGIN_CONF_KEY_NAME:
|
||||
if isstring(cfg[key]):
|
||||
self.pluginName = cfg[key]
|
||||
self.fifoName = cfg[key] + "-fifo"
|
||||
self.loadState += LOADSTATE.PLGNAME
|
||||
else:
|
||||
logging.error("[PLUGIN]: name[%s] not string.", cfg[key])
|
||||
|
||||
elif key == PLUGIN_CONF_KEY_DESC:
|
||||
langList = cfg[key]
|
||||
descDict = {}
|
||||
if langList == None or len(langList) == 0:
|
||||
return
|
||||
for i in range(len(langList)):
|
||||
descDict = langList[i]
|
||||
if LANG_KEY_EN in descDict:
|
||||
self.descList.insert(LANGLIST.LANG_EN, descDict.pop(LANG_KEY_EN))
|
||||
continue
|
||||
elif LANG_KEY_ZH_CN in descDict:
|
||||
self.descList.insert(LANGLIST.LANG_ZH_CN, descDict.pop(LANG_KEY_ZH_CN))
|
||||
continue
|
||||
|
||||
elif key == PLUGIN_CONF_KEY_EXEC:
|
||||
if isstring(cfg[key]):
|
||||
self.execCmd = cfg[key]
|
||||
self.loadState += LOADSTATE.EXECCMD
|
||||
else:
|
||||
logging.error("[PLUGIN]: execCmd[%s] not string.", cfg[key])
|
||||
|
||||
elif key == PLUGIN_CONF_KEY_LOGLEVEL:
|
||||
loglevel = cfg[key].upper()
|
||||
if loglevel in LOGLEVEL_LIST:
|
||||
self.logLevel = LOGLEVEL_LIST.index(loglevel)
|
||||
|
||||
elif key == PLUGIN_CONF_KEY_RUNLEVEL:
|
||||
runlevel = cfg[key].upper()
|
||||
if runlevel in RUNLEVEL_LIST:
|
||||
self.runLevel = RUNLEVEL_LIST.index(runlevel)
|
||||
else:
|
||||
logging.warning("[PLUGIN]: key[%s] not need config.", key)
|
||||
|
||||
def _update_process(self):
|
||||
if not self.running:
|
||||
logging.info("[PLUGIN]: plugin [%s] is not running.", self.pluginName)
|
||||
return
|
||||
|
||||
if os.path.exists(self.fifoPath):
|
||||
try:
|
||||
fd = open(self.fifoPath, 'r', 1)
|
||||
process = fd.readline()
|
||||
self.process = int(process.strip("\n"))
|
||||
except Exception as e:
|
||||
logging.info("[PLUGIN]: get process err[%s].",e)
|
||||
else:
|
||||
logging.info("[PLUGIN]: fifo[%s] not exists.", self.fifoPath)
|
||||
|
||||
if self.process >= 100 or self.process < 0:
|
||||
return
|
||||
|
||||
tmptimer = threading.Timer(0.5, function=self._update_process)
|
||||
tmptimer.start()
|
||||
|
||||
###################### 外部函数 ######################
|
||||
# 1-读取配置文件,并配置该插件
|
||||
# 2-使能插件
|
||||
# 3-失能插件
|
||||
# 4-获取插件名称
|
||||
# 5-获取进度
|
||||
# 6-注册进度跟新回调
|
||||
# 7-执行插件
|
||||
# 8-获取描述信息
|
||||
# 9-设置脚本日志路径
|
||||
|
||||
# TODO:
|
||||
# 重配置该插件
|
||||
######################
|
||||
|
||||
# 配置该插件
|
||||
def plg_config(self, filePath):
|
||||
if not os.path.exists(filePath):
|
||||
logging.error("[PLUGIN]: [%s] not exist.", filePath)
|
||||
return self.PLUGINERR_PLUGIN_CONFIG_FAILED
|
||||
|
||||
def plg_enable(self):
|
||||
self.enabled = True
|
||||
def plg_disable(self):
|
||||
self.enabled = False
|
||||
|
||||
def plg_get_name(self):
|
||||
return self.pluginName
|
||||
|
||||
def plg_get_process(self):
|
||||
return self.process
|
||||
|
||||
def plg_get_desc(self):
|
||||
# 获得语言变量
|
||||
#TODO: 例如:中文繁体,如果不存在的话,显示中文简体
|
||||
lang=os.getenv("LANG")
|
||||
if LANG_KEY_EN in lang:
|
||||
if len(self.descList) > LANGLIST.LANG_EN:
|
||||
return self.descList[LANGLIST.LANG_EN]
|
||||
else:
|
||||
logging.error("[PLUGIN]: There is not a desc of the language[%s].", lang)
|
||||
elif LANG_KEY_ZH_CN in lang:
|
||||
if len(self.descList) > LANGLIST.LANG_ZH_CN:
|
||||
return self.descList[LANGLIST.LANG_ZH_CN]
|
||||
else:
|
||||
logging.error("[PLUGIN]: There is not a desc of the language[%s].", lang)
|
||||
else:
|
||||
logging.error("[PLUGIN]: There is not a desc of the language[%s].", lang)
|
||||
return
|
||||
|
||||
# 添加 update cmd
|
||||
# 设置脚本日志路径
|
||||
def plg_set_logDir(self, logPath):
|
||||
if not os.path.exists(logPath):
|
||||
try:
|
||||
os.makedirs(logPath, mode=0o755)
|
||||
except Exception as e:
|
||||
logging.error("[PLUGIN]: create plugin log dir failed.[%s]", e)
|
||||
return self.PLUGINERR_LOG_PATH_NOT_EXIT
|
||||
self.logDir = logPath
|
||||
if self.pluginName != None:
|
||||
self.logPath = os.path.join(self.logDir, self.pluginName + ".log")
|
||||
self.cmd = "bash " + self.execCmd + " fifoname=" + self.fifoName + " logpath=" + self.logPath + " loglevel=" + str(self.logLevel) + " modename=" + self.pluginName
|
||||
|
||||
def plg_run(self):
|
||||
if not self.enabled:
|
||||
logging.error("[PLUGIN]: [%s] not enabled.", self.pluginName)
|
||||
return self.PLUGINERR_PLUGIN_NOT_ENABLED
|
||||
|
||||
self.running = True
|
||||
tmptimer = threading.Timer(0.5, function=self._update_process)
|
||||
tmptimer.start()
|
||||
|
||||
if self.cmd == None:
|
||||
logging.error("[PLUGIN]: cmd is None.")
|
||||
return self.PLUGINERR_CMD_IS_NONE, self._numToInfo(self.PLUGINERR_CMD_IS_NONE), self._numToInfo(self.PLUGINERR_CMD_IS_NONE)
|
||||
|
||||
logging.debug("[PLUGIN]: cmd[%s].",self.cmd)
|
||||
try:
|
||||
ret = subprocess.run(self.cmd, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
except Exception as e:
|
||||
logging.error("[PLUGIN]: subprocess run err[%s].", e)
|
||||
|
||||
self.running = False
|
||||
logging.debug("[PLUGIN]: [%s] run finished ret[%d].",self.pluginName, ret.returncode)
|
||||
return ret.returncode, ret.stdout.decode(), ret.stderr.decode()
|
||||
|
||||
def plg_reconfig(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class pluginManagerClass(pluginState):
|
||||
def __init__(self):
|
||||
# 变量初始化
|
||||
self.plgClassList = [] # 插件句柄
|
||||
self.loaded = False
|
||||
|
||||
self.managerLogDir = LOG_DIR_ROOT # 管理器日志路径
|
||||
# 日志配置初始化,试用updater的logger
|
||||
# if not os.path.exists(self.managerLogDir):
|
||||
# os.mkdir(self.managerLogDir, mode=0o755)
|
||||
# logfile = os.path.join(self.managerLogDir, 'PluginManager.log.' + str(self.classNum))
|
||||
# logging.basicConfig(format=FORMAT, level='DEBUG', datefmt='%m-%d,%H:%M:%S', filename=logfile, filemode='a')
|
||||
# self.pluginLogDir = PLUGIN_LOG_DIR # 插件日志路径
|
||||
|
||||
# 将单个插件句柄添加到全局记录, 并使能
|
||||
def _add_single_plugin(self, filePath, enable):
|
||||
if not os.path.exists(filePath):
|
||||
logging.debug("[PLUGIN]: [%s] not exist.", filePath)
|
||||
return
|
||||
|
||||
singlePlgClass = pluginClass()
|
||||
singlePlgClass.plg_config(filePath)
|
||||
self.plgClassList.append(singlePlgClass)
|
||||
if enable:
|
||||
singlePlgClass.plg_enable()
|
||||
singlePlgClass.plg_set_logDir(self.pluginLogDir)
|
||||
|
||||
def _remove_single_plugin(self, pluginClass):
|
||||
if pluginClass in self.plgClassList:
|
||||
logging.debug("[PLUGIN]: remove [%s].", pluginClass.plg_get_name())
|
||||
pluginClass.remove(pluginClass)
|
||||
pluginClass.plg_disable()
|
||||
|
||||
|
||||
# 加载所有插件,读取所有配置
|
||||
# 第一个执行
|
||||
# 返回插件句柄列表
|
||||
# TODO:加载指定插件, 读取指定配置
|
||||
def reload_plugin(self, pluginName):
|
||||
pass
|
||||
|
||||
# 通过句柄获取插件名称
|
||||
def get_plugin_name(self, pluginClass):
|
||||
if not self.loaded:
|
||||
logging.error("[PLUGIN]: please run load_all first.")
|
||||
return self.PLUGINERR_NOT_LOAD_ALL
|
||||
if pluginClass not in self.plgClassList:
|
||||
logging.error("[PLUGIN]: there is no this plugin in pluginList.")
|
||||
return self.PLUGINERR_PLUGIN_NOT_IN_LIST
|
||||
|
||||
return pluginClass.plg_get_name()
|
||||
|
||||
# 运行指定插件
|
||||
# pluginName, pluginClass 都指定时,以名称为准
|
||||
def run_plugin(self, pluginName = None):
|
||||
self.running = True
|
||||
|
||||
if pluginName == None or not os.path.isfile(pluginName):
|
||||
logging.error("[PLUGIN]: [%s] Cann't found.",pluginName)
|
||||
return True
|
||||
cmd = "bash " + pluginName
|
||||
try:
|
||||
ret = subprocess.run(cmd, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
logging.info("[PLUGIN]: script[%s].",pluginName)
|
||||
except Exception as e:
|
||||
logging.error("[PLUGIN]: subprocess run err[%s].", e)
|
||||
return True
|
||||
|
||||
self.running = False
|
||||
|
||||
if ret.returncode != 0:
|
||||
logging.error("[PLUGIN]: code:%d, out:%s, err:%s",ret.returncode, ret.stdout.decode(), ret.stderr.decode())
|
||||
logging.debug("[PLUGIN]: run finished returncode[%d], out[%s], err[%s]",ret.returncode, ret.stdout.decode(), ret.stderr.decode())
|
||||
return (ret.returncode==0)
|
||||
|
||||
def connect_signal(self, plgclass, signal, handler):
|
||||
if plgclass not in self.plgClassList:
|
||||
logging.error("[PLUGIN]: there is no this plugin in pluginList.")
|
||||
return self.PLUGINERR_PLUGIN_NOT_IN_LIST
|
||||
return plgclass.connect(signal, handler)
|
||||
|
||||
|
||||
def plugin_process_handler(obj, process):
|
||||
logging.info("[PLUGIN]: ******* process [%d].", process)
|
||||
|
||||
# if __name__ == "__main__":
|
||||
|
||||
# pMClass = pluginManagerClass()
|
||||
# plgList = pMClass.load_all("./")
|
||||
|
||||
# for everyPlg in iter(plgList):
|
||||
# name = pMClass.get_plugin_name(everyPlg)
|
||||
# print("name:", name)
|
||||
# desc = pMClass.get_desc(everyPlg)
|
||||
# print("desc:", desc)
|
||||
# pMClass.connect_signal(everyPlg, "processChanged", plugin_process_handler)
|
||||
|
||||
# ret = pMClass.run_plugin(name)
|
||||
|
||||
# exit(0)
|
||||
|
|
@ -0,0 +1,543 @@
|
|||
# UpdateList.py
|
||||
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import yaml
|
||||
from gi.repository import Gio
|
||||
from .errors import *
|
||||
from .enums import *
|
||||
|
||||
class UpdateList():
|
||||
OUTPUT_JSON_PATH = '/var/lib/kylin-system-updater/json/'
|
||||
|
||||
def __init__(self,parent):
|
||||
self.parent = parent
|
||||
self.uuconfigs = self.parent.uuconfigs
|
||||
self.push_groups = []
|
||||
self.push_steps = []
|
||||
self.push_singles = []
|
||||
self.pkgs_data = {}
|
||||
|
||||
if 'XDG_CURRENT_DESKTOP' in os.environ:
|
||||
self.current_desktop = os.environ.get('XDG_CURRENT_DESKTOP')
|
||||
else:
|
||||
self.current_desktop = ''
|
||||
|
||||
if 'XDG_DATA_DIRS' in os.environ and os.environ['XDG_DATA_DIRS']:
|
||||
data_dirs = os.environ['XDG_DATA_DIRS']
|
||||
else:
|
||||
data_dirs = '/usr/local/share/:/usr/share/'
|
||||
|
||||
self.application_dirs = [os.path.join(base, 'applications')
|
||||
for base in data_dirs.split(':')]
|
||||
|
||||
def get_push(self):
|
||||
return self.push_groups + self.push_singles
|
||||
|
||||
def push_pop(self,content):
|
||||
for cont in content:
|
||||
if cont in self.push_singles:
|
||||
self.push_singles.remove(cont)
|
||||
if cont in self.push_groups:
|
||||
self.push_groups.remove(cont)
|
||||
|
||||
def classify_content(self,content):
|
||||
if content == []:
|
||||
steps = []
|
||||
if self.push_groups:
|
||||
steps = self.push_steps
|
||||
return self.push_singles,self.push_groups,steps
|
||||
else:
|
||||
singles = []
|
||||
groups = []
|
||||
steps = []
|
||||
for cont in content:
|
||||
if cont in self.push_singles:
|
||||
singles.append(cont)
|
||||
elif cont in self.push_groups:
|
||||
groups.append(cont)
|
||||
|
||||
if groups != [] and self.push_steps != []:
|
||||
steps = self.push_steps
|
||||
return singles,groups,steps
|
||||
|
||||
def copy_pkgs_data(self,content):
|
||||
updating_data = {}
|
||||
for con in content:
|
||||
updating_data.update({con:self.pkgs_data.get(con,{})})
|
||||
|
||||
return updating_data
|
||||
|
||||
def is_steps(self,content):
|
||||
for cont in content:
|
||||
if cont in self.push_singles:
|
||||
return False
|
||||
|
||||
if self.push_steps == []:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _make_important_list(self,cache,pkgs_upgrade,important_list = []):
|
||||
upgradeable_pkgs = []
|
||||
# tmp = []
|
||||
upgradeable_groups = []
|
||||
|
||||
logging.info("The Server Push List: %a",important_list)
|
||||
|
||||
for pkg_name in important_list:
|
||||
if pkg_name in cache:
|
||||
pkg_obj = cache[pkg_name]
|
||||
if pkg_obj.is_installed:
|
||||
if pkg_name in pkgs_upgrade:
|
||||
pkgs_upgrade.remove(pkg_name)
|
||||
upgradeable_pkgs.append(pkg_obj.name)
|
||||
else:
|
||||
upgradeable_pkgs.append(pkg_obj.name)
|
||||
else:
|
||||
upgradeable_groups.append(pkg_name)
|
||||
|
||||
logging.info("Push Single Packages: %a, Push Groups:%a",upgradeable_pkgs,upgradeable_groups)
|
||||
return upgradeable_groups,upgradeable_pkgs
|
||||
|
||||
def _make_pkg_info_json(self,cache,pkgs_list):
|
||||
total_download_size = 0
|
||||
total_installed_size = 0
|
||||
pkgs_info_json = {}
|
||||
|
||||
for pkg_name in pkgs_list:
|
||||
pkg = cache[pkg_name]
|
||||
cur_version = getattr(pkg.installed, "version", '')
|
||||
new_version = getattr(pkg.candidate, "version", '')
|
||||
|
||||
download_size = getattr(pkg.candidate, "size", 0)
|
||||
installed_size = getattr(pkg.candidate, "installed_size", 0)
|
||||
|
||||
total_download_size = total_download_size + download_size
|
||||
total_installed_size = total_installed_size + installed_size
|
||||
|
||||
pkgs_info_json.update({pkg_name:{"cur_version":cur_version,"new_version":new_version,\
|
||||
"download_size":str(download_size),"install_size":str(installed_size)}})
|
||||
|
||||
pkgs_info_json.update({"total_download_size":str(total_download_size)})
|
||||
pkgs_info_json.update({"total_install_size":str(total_installed_size)})
|
||||
return pkgs_info_json
|
||||
|
||||
def _check_pkg_in_cache(self,cache,pkgs_list):
|
||||
new_pkgs_list = []
|
||||
for pkg_name in pkgs_list:
|
||||
#检查是否在cache 以及 是否安装检查
|
||||
if pkg_name in cache and not cache[pkg_name].is_installed:
|
||||
new_pkgs_list.append(pkg_name)
|
||||
else:
|
||||
pass
|
||||
return new_pkgs_list
|
||||
|
||||
def _make_group_output_json(self,data,data_yaml,upgrade_pkgs_json,install_pkgs_json,output_path):
|
||||
groups_base_info = {}
|
||||
output_json = {}
|
||||
|
||||
output_config_name = output_path + data['package'] + '.json'
|
||||
|
||||
groups_base_info.update({"package":data['package']})
|
||||
groups_base_info.update({"new_version":data['version']})
|
||||
groups_base_info.update({"name":data['name']})
|
||||
groups_base_info.update({"description":data['description']})
|
||||
groups_base_info.update({"icon":data['icon']})
|
||||
|
||||
groups_base_info.update({"changelog":data_yaml['changelog']})
|
||||
|
||||
output_json.update(groups_base_info)
|
||||
output_json.update({"upgrade_list":upgrade_pkgs_json})
|
||||
output_json.update({"install_list":install_pkgs_json})
|
||||
# output_json.update({"hold_list":hold_pkgs_list})
|
||||
# output_json.update({"remove_list":remove_pkgs_list})
|
||||
|
||||
with open(output_config_name, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_json, f, ensure_ascii=False, indent=4)
|
||||
logging.info("Generate Jsonfile(%s) to complete... ",output_config_name)
|
||||
|
||||
def _split_package_id(self,package):
|
||||
"""Return the name, the version number and the release of the
|
||||
specified package."""
|
||||
if "=" in package:
|
||||
name, version = package.split("=", 1)
|
||||
release = None
|
||||
elif "/" in package:
|
||||
name, release = package.split("/", 1)
|
||||
version = None
|
||||
else:
|
||||
name = package
|
||||
version = release = None
|
||||
return name, version, release
|
||||
|
||||
def _make_downgrade(self,cache,downgrade_pkgs):
|
||||
output_downgrade = []
|
||||
adjust_pkgs = []
|
||||
for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
|
||||
for pkg in downgrade_pkgs]:
|
||||
try:
|
||||
pkg = cache[pkg_name]
|
||||
except KeyError:
|
||||
logging.warning("Package %s isn't available",pkg_name)
|
||||
continue
|
||||
if not pkg.is_installed:
|
||||
logging.warning("Package %s isn't installed",pkg_name)
|
||||
|
||||
if pkg_ver:
|
||||
if pkg.installed and pkg.installed.version < pkg_ver:
|
||||
logging.warning("The former version %s of %s is already installed",pkg.installed.version, pkg.name)
|
||||
continue
|
||||
elif pkg.installed and pkg.installed.version == pkg_ver:
|
||||
logging.warning("The version %s of %s is already installed",pkg.installed.version, pkg.name)
|
||||
continue
|
||||
|
||||
try:
|
||||
pkg.candidate = pkg.versions[pkg_ver]
|
||||
except KeyError:
|
||||
logging.warning("The version %s of %s isn't available",pkg_ver, pkg_name)
|
||||
continue
|
||||
|
||||
output_downgrade.append(pkg_name)
|
||||
adjust_pkgs.append(pkg_name+'='+pkg_ver)
|
||||
|
||||
return output_downgrade,adjust_pkgs
|
||||
|
||||
def _get_downgrade_list(self,cache,data):
|
||||
downgrade_pkgs = []
|
||||
|
||||
try:
|
||||
downgrade_raw = data['force_install_list']
|
||||
except Exception as e:
|
||||
downgrade_raw = []
|
||||
|
||||
for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
|
||||
for pkg in downgrade_raw]:
|
||||
|
||||
if pkg_name in cache:
|
||||
downgrade_pkgs.append(pkg_name)
|
||||
else:
|
||||
logging.warning("Package %s isn't available",pkg_name)
|
||||
continue
|
||||
|
||||
return downgrade_raw,downgrade_pkgs
|
||||
|
||||
def _make_groups_pkgs(self,cache,data,pkgs_upgrade = []):
|
||||
|
||||
upgrade_pkgs_list = data['upgrade_list']
|
||||
new_install_list = self._check_pkg_in_cache(cache,data['install_list'])
|
||||
|
||||
new_upgrade_list = list(set(pkgs_upgrade) & set(upgrade_pkgs_list))
|
||||
|
||||
for pkg in new_upgrade_list:
|
||||
pkgs_upgrade.remove(pkg)
|
||||
|
||||
for pkg in self.push_singles:
|
||||
if pkg in new_install_list:
|
||||
new_install_list.remove(pkg)
|
||||
|
||||
return new_install_list,new_upgrade_list
|
||||
|
||||
def _make_groups_upgrade(self,cache,group_list,is_openkylin,pkgs_install,pkgs_upgrade,output_path,config_path):
|
||||
upgrade_list = []
|
||||
install_list = []
|
||||
|
||||
if os.path.isdir(config_path) == False:
|
||||
logging.warning("configPath(%s) is not exists...",config_path)
|
||||
return
|
||||
|
||||
files = os.listdir(config_path)
|
||||
|
||||
for ifile in files:
|
||||
if ifile.endswith('.json'):
|
||||
with open(config_path+ifile,'r') as f:
|
||||
try:
|
||||
data = json.load(f)
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
raise UpdateBaseError(ERROR_LOAD_CONFIG_FAILED)
|
||||
|
||||
group_name = data['package']
|
||||
with open(config_path + group_name + ".yaml", "r") as stream:
|
||||
try:
|
||||
data_yaml = yaml.safe_load(stream)
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
raise UpdateBaseError(ERROR_LOAD_CONFIG_FAILED)
|
||||
|
||||
if not group_name in group_list:
|
||||
continue
|
||||
|
||||
if is_openkylin == True:
|
||||
install_list,upgrade_list = pkgs_install,pkgs_upgrade
|
||||
else:
|
||||
install_list,upgrade_list = self._make_groups_pkgs(cache,data,pkgs_upgrade)
|
||||
|
||||
if len(install_list) == 0 and len(upgrade_list) == 0:
|
||||
continue
|
||||
|
||||
upgrade_pkgs_json = self._make_pkg_info_json(cache,upgrade_list)
|
||||
install_pkgs_json = self._make_pkg_info_json(cache,install_list)
|
||||
self._make_group_output_json(data,data_yaml,upgrade_pkgs_json,install_pkgs_json,output_path)
|
||||
|
||||
# 读取策略下发 策略优先级最高
|
||||
if self.uuconfigs.getWithDefault("updateStrategiesManager","strategiesState",False) == True:
|
||||
install_type = self.uuconfigs.getWithDefault("updateStrategiesManager","installType",DEFAULT_INSTALL_TYPE)
|
||||
if install_type == DEFAULT_INSTALL_TYPE:
|
||||
install_type = data.setdefault("install_type",RUNTIME_INSTALL_TYPE)
|
||||
else:
|
||||
install_type = data.setdefault("install_type",RUNTIME_INSTALL_TYPE)
|
||||
|
||||
poweroff_install = install_type == POWEROFF_INSTALL_TYPE
|
||||
|
||||
progress_begin = 50
|
||||
if poweroff_install == True:
|
||||
logging.info("Turn on shutdown installation mode...")
|
||||
progress_begin = 0
|
||||
|
||||
step_update = data.setdefault("step_update",{})
|
||||
if step_update != {}:
|
||||
if poweroff_install == False:
|
||||
progress_begin = self._make_steps_runtime(progress_begin,step_update,install_list,upgrade_list)
|
||||
else:
|
||||
progress_begin = self._make_steps_poweroff(progress_begin,step_update,install_list,upgrade_list)
|
||||
|
||||
put_data = {group_name:{"progress_begin":progress_begin,"progress_end":100,"upgrade_list":upgrade_list,\
|
||||
"install_list":install_list,"script":data.setdefault("script",{}),\
|
||||
"install_type":install_type}}
|
||||
|
||||
self.push_groups.append(group_name)
|
||||
self.pkgs_data.update(put_data)
|
||||
logging.info("Group(%s) upgrade:%d install:%d",group_name,len(upgrade_list),len(install_list))
|
||||
else:
|
||||
pass
|
||||
|
||||
def _make_steps_poweroff(self,steps_begin,step_update,install_list,upgrade_list):
|
||||
delete_step = []
|
||||
for step_name in step_update:
|
||||
step_data = step_update.get(step_name,{})
|
||||
if step_data == {}:
|
||||
continue
|
||||
step_install = list(set(step_data.setdefault("install_list",[])) & set(install_list))
|
||||
step_upgrade = list(set(step_data.setdefault("upgrade_list",[])) & set(upgrade_list))
|
||||
|
||||
if step_install == [] and step_upgrade == []:
|
||||
delete_step.append(step_name)
|
||||
continue
|
||||
|
||||
step_data["install_list"] = step_install
|
||||
step_data["upgrade_list"] = step_upgrade
|
||||
|
||||
for step in delete_step:
|
||||
step_update.pop(step)
|
||||
|
||||
for step_name in step_update:
|
||||
step_data = step_update.get(step_name,{})
|
||||
step_install = step_data["install_list"]
|
||||
step_upgrade = step_data["upgrade_list"]
|
||||
|
||||
value = int((len(step_install) + len(step_upgrade))/(len(install_list) + len(upgrade_list)) * 50)
|
||||
if value == 0:
|
||||
value = 1
|
||||
progress_end = steps_begin + value
|
||||
step_data.update({"progress_begin":steps_begin})
|
||||
step_data.update({"progress_end":progress_end})
|
||||
steps_begin = progress_end
|
||||
|
||||
logging.info("Steps(%s) upgrade:%d install:%d",step_name,len(step_upgrade),len(step_install))
|
||||
self.push_steps.append(step_name)
|
||||
self.pkgs_data.update({step_name:step_data})
|
||||
|
||||
return steps_begin
|
||||
|
||||
def _make_steps_runtime(self,steps_begin,step_update,install_list,upgrade_list):
|
||||
for step_name in step_update:
|
||||
step_data = step_update.get(step_name,{})
|
||||
if step_data == {}:
|
||||
continue
|
||||
step_install = list(set(step_data.setdefault("install_list",[])) & set(install_list))
|
||||
step_upgrade = list(set(step_data.setdefault("upgrade_list",[])) & set(upgrade_list))
|
||||
need_reboot = step_data.setdefault("need_reboot",False)
|
||||
if step_install == [] and step_upgrade == []:
|
||||
continue
|
||||
step_data["install_list"] = step_install
|
||||
step_data["upgrade_list"] = step_upgrade
|
||||
|
||||
value = int((len(step_install) + len(step_upgrade))/(len(install_list) + len(upgrade_list)) * 50)
|
||||
if need_reboot == True:
|
||||
step_data.update({"progress_begin":steps_begin})
|
||||
step_data.update({"progress_end":100})
|
||||
else:
|
||||
progress_end = steps_begin + value
|
||||
step_data.update({"progress_begin":steps_begin})
|
||||
step_data.update({"progress_end":progress_end})
|
||||
steps_begin = progress_end
|
||||
|
||||
logging.info("Steps(%s) upgrade:%d install:%d",step_name,len(step_upgrade),len(step_install))
|
||||
|
||||
self.push_steps.append(step_name)
|
||||
self.pkgs_data.update({step_name:step_data})
|
||||
|
||||
if need_reboot == True:
|
||||
break
|
||||
return steps_begin
|
||||
|
||||
|
||||
def _rate_application_for_package(self, application, pkg):
|
||||
score = 0
|
||||
desktop_file = os.path.basename(application.get_filename())
|
||||
application_id = os.path.splitext(desktop_file)[0]
|
||||
|
||||
if application.should_show():
|
||||
score += 1
|
||||
|
||||
if application_id == pkg.name:
|
||||
score += 5
|
||||
|
||||
return score
|
||||
|
||||
def _file_is_application(self, file_path):
|
||||
# WARNING: This is called often if there's a lot of updates. A poor
|
||||
# performing call here has a huge impact on the overall performance!
|
||||
if not file_path.endswith(".desktop"):
|
||||
# First the obvious case: If the path doesn't end in a .desktop
|
||||
# extension, this isn't a desktop file.
|
||||
return False
|
||||
|
||||
file_path = os.path.abspath(file_path)
|
||||
for app_dir in self.application_dirs:
|
||||
if file_path.startswith(app_dir):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_application_for_package(self, pkg):
|
||||
desktop_files = []
|
||||
rated_applications = []
|
||||
|
||||
for installed_file in pkg.installed_files:
|
||||
if self._file_is_application(installed_file):
|
||||
desktop_files.append(installed_file)
|
||||
|
||||
for desktop_file in desktop_files:
|
||||
try:
|
||||
application = Gio.DesktopAppInfo.new_from_filename(
|
||||
desktop_file)
|
||||
application.set_desktop_env(self.current_desktop)
|
||||
except Exception as e:
|
||||
logging.warning("Error loading .desktop file %s: %s" %
|
||||
(desktop_file, e))
|
||||
continue
|
||||
score = self._rate_application_for_package(application, pkg)
|
||||
if score > 0:
|
||||
rated_applications.append((score, application))
|
||||
|
||||
rated_applications.sort(key=lambda app: app[0], reverse=True)
|
||||
if len(rated_applications) > 0:
|
||||
return rated_applications[0][1]
|
||||
else:
|
||||
return None
|
||||
|
||||
def _make_single_upgrade(self,cache,pkg_list,output_path):
|
||||
for pkg in pkg_list:
|
||||
zh_name = ''
|
||||
base_info = {}
|
||||
output_json = {}
|
||||
output_config_name = output_path + pkg + '.json'
|
||||
|
||||
pkg_cache = cache[pkg]
|
||||
|
||||
if pkg_cache.is_installed:
|
||||
app = self.get_application_for_package(pkg_cache)
|
||||
if app is not None:
|
||||
zh_name = app.get_display_name()
|
||||
|
||||
pkgs_json = self._make_pkg_info_json(cache,[pkg])
|
||||
en_name = getattr(pkg_cache.candidate, "summary", '')
|
||||
description_str = getattr(pkg_cache.candidate, "description", '')
|
||||
|
||||
base_info.update({"package":pkg})
|
||||
|
||||
base_info.update({"cur_version":getattr(pkg_cache.installed, "version", '')})
|
||||
base_info.update({"new_version":getattr(pkg_cache.candidate, "version", '')})
|
||||
base_info.update({"name":{"zh_CN":zh_name,"en_US":en_name}})
|
||||
base_info.update({"description":{"zh_CN":description_str,"en_US":description_str}})
|
||||
base_info.update({"icon":''})
|
||||
|
||||
output_json.update(base_info)
|
||||
if pkg_cache.is_installed:
|
||||
output_json.update({"upgrade_list":pkgs_json})
|
||||
output_json.update({"install_list":{}})
|
||||
else:
|
||||
output_json.update({"upgrade_list":{}})
|
||||
output_json.update({"install_list":pkgs_json})
|
||||
|
||||
with open(output_config_name, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_json, f, ensure_ascii=False, indent=4)
|
||||
logging.info("Generate Jsonfile(%s) to complete... ",output_config_name)
|
||||
|
||||
def _make_distupgrade(self,cache):
|
||||
pkgs_upgrade = []
|
||||
pkgs_install = []
|
||||
if cache.get_changes():
|
||||
cache.clear()
|
||||
cache._depcache.upgrade(True)
|
||||
|
||||
for pkg in cache:
|
||||
try:
|
||||
if pkg.marked_install:
|
||||
pkgs_install.append(pkg.name)
|
||||
elif pkg.marked_upgrade:
|
||||
pkgs_upgrade.append(pkg.name)
|
||||
except KeyError:
|
||||
pass
|
||||
return pkgs_install,pkgs_upgrade
|
||||
|
||||
|
||||
|
||||
def _backup_current_serverid(self):
|
||||
import shutil
|
||||
|
||||
SERVERIDPATH = "/var/lib/kylin-software-properties/config/serverID.conf"
|
||||
BACKUPPATH = "/var/lib/kylin-system-updater/json/"
|
||||
|
||||
try:
|
||||
if os.path.isfile(SERVERIDPATH):
|
||||
dst = shutil.copy(SERVERIDPATH, BACKUPPATH)
|
||||
logging.info("Backup serverID conf completed: %s...",dst)
|
||||
else:
|
||||
logging.info("ServerID conf is not exists...")
|
||||
except Exception as e:
|
||||
logging.error("%s",e)
|
||||
|
||||
def update_kylin(self,cache,important_data,is_openkylin = False):
|
||||
system_install = []
|
||||
system_upgrade = []
|
||||
|
||||
if is_openkylin == True:
|
||||
system_install,system_upgrade = self._make_distupgrade(cache)
|
||||
else:
|
||||
if cache.get_changes():
|
||||
cache.clear()
|
||||
for pkg in cache:
|
||||
if pkg.is_upgradable and pkg.is_installed:
|
||||
system_upgrade.append(pkg.name)
|
||||
|
||||
logging.info("System all upgradeable packages:upgrade:%d install:%d ",len(system_upgrade),len(system_install))
|
||||
|
||||
group_list,single_pkgs = self._make_important_list(cache,system_upgrade,important_data)
|
||||
|
||||
make_empty_dir(self.OUTPUT_JSON_PATH)
|
||||
|
||||
if not group_list and not single_pkgs:
|
||||
return
|
||||
|
||||
self.push_singles = single_pkgs
|
||||
|
||||
self._make_single_upgrade(cache,single_pkgs,self.OUTPUT_JSON_PATH)
|
||||
|
||||
self._make_groups_upgrade(cache,group_list,is_openkylin,\
|
||||
system_install,system_upgrade,self.OUTPUT_JSON_PATH,get_config_patch())
|
||||
|
||||
self._backup_current_serverid()
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
# DistUpgradeConfigParser.py
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
# USA
|
||||
|
||||
|
||||
from configparser import NoOptionError
|
||||
from configparser import ConfigParser as SafeConfigParser
|
||||
import os.path
|
||||
import os
|
||||
import logging
|
||||
|
||||
class UpgradeConfig(SafeConfigParser):
|
||||
def __init__(self, datadir="/var/lib/kylin-system-updater/", name="system-updater.conf",defaults_dir=None):
|
||||
SafeConfigParser.__init__(self)
|
||||
self.datadir = datadir
|
||||
maincfg = os.path.join(datadir, name)
|
||||
# defaults are read first
|
||||
self.config_files = []
|
||||
if defaults_dir:
|
||||
self.config_files.append(os.path.join(datadir, defaults_dir))
|
||||
# our config file
|
||||
self.config_files += [maincfg]
|
||||
for conf in self.config_files:
|
||||
if not os.path.exists(conf):
|
||||
logging.warning("Check: Conf(%s) not exits...",conf)
|
||||
self.read(self.config_files, encoding='iso-8859-1')
|
||||
logging.info("Initialize Upgrade ConfigFile(%s) to success",str(self.config_files))
|
||||
|
||||
def optionxform(self, optionstr):
|
||||
return optionstr
|
||||
|
||||
def reRead(self):
|
||||
self.read(self.config_files, encoding='iso-8859-1')
|
||||
|
||||
def setValue(self, section, option, value=None,is_write = True):
|
||||
logging.info("SetValue Section:%s Option:%s Value:%s",section, option, value)
|
||||
try:
|
||||
self.reRead()
|
||||
self.set(section, option,value)
|
||||
except Exception as e:
|
||||
logging.error("Error: setValue section:%s option:%s value:%s",section, option, value)
|
||||
logging.error(str(e))
|
||||
return False
|
||||
if is_write == True:
|
||||
with open(self.config_files[-1], 'w+') as configfile:
|
||||
self.write(configfile)
|
||||
return True
|
||||
|
||||
def getWithDefault(self, section, option, default,re_read=False):
|
||||
try:
|
||||
if re_read == True:
|
||||
self.reRead()
|
||||
|
||||
if type(default) == bool:
|
||||
return self.getboolean(section, option)
|
||||
elif type(default) == float:
|
||||
return self.getfloat(section, option)
|
||||
elif type(default) == int:
|
||||
return self.getint(section, option)
|
||||
return self.get(section, option)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return default
|
||||
|
||||
def getlist(self, section, option):
|
||||
try:
|
||||
tmp = self.get(section, option)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return []
|
||||
items = [x.strip() for x in tmp.split(" ")]
|
||||
if '' in items and len(items):
|
||||
return []
|
||||
return items
|
||||
|
||||
def setListValue(self, section, option, value=None,is_write = True):
|
||||
tmp = str(value).replace('[', '').replace(']', '')
|
||||
tmp = tmp.replace("'", '').replace(',', '')
|
||||
try:
|
||||
self.set(section, option,tmp)
|
||||
except Exception as e:
|
||||
logging.error("setListValue section:%s option:%s",section, option)
|
||||
logging.error(str(e))
|
||||
return
|
||||
if is_write == True:
|
||||
with open(self.config_files[-1], 'w+') as configfile:
|
||||
self.write(configfile)
|
||||
|
||||
def getListFromFile(self, section, option):
|
||||
try:
|
||||
filename = self.get(section, option)
|
||||
except NoOptionError:
|
||||
return []
|
||||
p = os.path.join(self.datadir, filename)
|
||||
if not os.path.exists(p):
|
||||
logging.error("getListFromFile: no '%s' found" % p)
|
||||
with open(p) as f:
|
||||
items = [x.strip() for x in f]
|
||||
return [s for s in items if not s.startswith("#") and not s == ""]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""enums - Enumerates for apt daemon dbus messages"""
|
||||
|
||||
__all__ = (
|
||||
#错误枚举
|
||||
"ERROR_OTHER_PROGRESS_OCCUPATION","ERROR_NETWORK_FAILED","ERROR_CANCELLED","ERROR_NOT_ROLLBAK_DEPLOYMENT",
|
||||
"ERROR_ORIGIN_IS_NONE",
|
||||
# 方法
|
||||
"get_error_description_from_enum"
|
||||
)
|
||||
|
||||
import gettext
|
||||
gettext.bindtextdomain('kylin-system-updater', '/usr/share/locale')
|
||||
gettext.textdomain('kylin-system-updater')
|
||||
_ = gettext.gettext
|
||||
|
||||
#系统更新的所有枚举
|
||||
PRIORITY_UPGRADE_SUCCCESSED = "priority-upgrade-successed"
|
||||
|
||||
#apt update阶段出现的错误解析
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#通用错误
|
||||
ERROR_PROGRAM_EXCEPTION = "#0000"
|
||||
ERROR_OTHER_PROGRESS_OCCUPATION = "#0001"
|
||||
ERROR_NETWORK_FAILED = "#0002"
|
||||
|
||||
#检查更新错误 1
|
||||
ERROR_ORIGIN_IS_NONE = "#0100"
|
||||
|
||||
|
||||
#下载错误 2
|
||||
ERROR_CANCELLED = "#0200"
|
||||
|
||||
#部署错误 3
|
||||
ERROR_NOT_ROLLBAK_DEPLOYMENT = "#0300"
|
||||
|
||||
|
||||
GLIB_ERROR_NETWORK_FAILED = "While fetching mirrorlist"
|
||||
|
||||
|
||||
|
||||
_DESCS_ERROR = {
|
||||
ERROR_OTHER_PROGRESS_OCCUPATION: _("Other tasks are being updated and upgraded, please try again later."),
|
||||
ERROR_NETWORK_FAILED: _("Network anomaly, can't check for updates!"),
|
||||
ERROR_CANCELLED: _("_Cancel Upgrade"),
|
||||
ERROR_NOT_ROLLBAK_DEPLOYMENT: _("There is no way to rollback to the previous version, there is nothing to rollback."),
|
||||
ERROR_ORIGIN_IS_NONE: _("Check for update exceptions! Please verify that the system deployment is complete.")
|
||||
|
||||
}
|
||||
|
||||
def get_error_description_from_enum(enum):
|
||||
"""Get a long description of an error.
|
||||
|
||||
:param enum: The transaction error enum, e.g. :data:`ERROR_NO_LOCK`.
|
||||
:returns: The description string.
|
||||
"""
|
||||
try:
|
||||
return _DESCS_ERROR[enum]
|
||||
except KeyError:
|
||||
return ''
|
||||
|
||||
# vim:ts=4:sw=4:et
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Exception classes"""
|
||||
|
||||
import logging
|
||||
from .enums import *
|
||||
|
||||
class UpdateBaseError(Exception):
|
||||
|
||||
"""Internal error if a transaction could not be processed successfully."""
|
||||
|
||||
_dbus_error_name = "org.debian.apt.TransactionFailed"
|
||||
|
||||
def __init__(self, code,desc=None,*args):
|
||||
self.code = code
|
||||
|
||||
if not desc:
|
||||
self.desc = get_error_description_from_enum(self.code)
|
||||
else:
|
||||
self.desc = desc
|
||||
|
||||
Exception.__init__(self, *args)
|
||||
|
||||
def __str__(self):
|
||||
return "%s" % \
|
||||
(get_error_description_from_enum(self.code))
|
||||
|
||||
class UpdateProgressExit(Exception):
|
||||
def __init__(self,*args):
|
||||
Exception.__init__(self, *args)
|
||||
logging.info("Update Progress wiil be Exit...")
|
||||
|
||||
class DebDeltaError(UpdateBaseError):
|
||||
|
||||
"""Internal error if a transaction could not be processed successfully."""
|
||||
|
||||
# vim:ts=4:sw=4:et
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Main loop for aptdaemon."""
|
||||
|
||||
__all__ = ("mainloop", "get_main_loop")
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
mainloop = GLib.MainLoop()
|
||||
|
||||
def get_main_loop():
|
||||
"""Return the glib main loop as a singleton."""
|
||||
return mainloop
|
|
@ -0,0 +1,198 @@
|
|||
# UpdateManager.py
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import dbus,time,sys
|
||||
import logging
|
||||
from .Core.errors import *
|
||||
from .Core.enums import *
|
||||
from .Core.loop import mainloop
|
||||
from gettext import gettext as _
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
from .Core.Database import Sqlite3Server
|
||||
from .backend.BackendOstreeNext import UpdateBackend,DownloadBackend,DeployBackend,RollbackBackend
|
||||
from .UpdateManagerDbus import UpdateManagerDbusController,UPDATER_DBUS_INTERFACE,UPDATER_DBUS_PATH,UPDATER_DBUS_SERVICE
|
||||
from SystemUpdater.Core.UpdaterConfigParser import UpgradeConfig
|
||||
from .Core.MyCache import MyCache
|
||||
from .UpdatesAvailable import UpdatesAvailable
|
||||
import subprocess
|
||||
|
||||
OUTPUT_JSON_PATH = '/var/cache/kylin-system-updater/json/'
|
||||
SYSTEM_UPDATE_GROUPS = "kylin-update-desktop-system"
|
||||
|
||||
class UpdateManager():
|
||||
def __init__(self,options):
|
||||
try:
|
||||
self.options = options
|
||||
|
||||
#FIXME: 如何解决值的保存
|
||||
# self.cache = MyCache()
|
||||
|
||||
self.trans = UpdatesAvailable(self)
|
||||
|
||||
self.sqlite3_server = Sqlite3Server(self)
|
||||
self.configs_uncover = UpgradeConfig(defaults_dir="system-updater-defaults.conf")
|
||||
self.bus = dbus.SystemBus()
|
||||
self.dbus_send = self._setup_dbus(self.bus)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def run(self):
|
||||
"""Start the daemon and listen for calls."""
|
||||
logging.info("Waiting for calls...")
|
||||
try:
|
||||
mainloop.run()
|
||||
except KeyboardInterrupt:
|
||||
self.dbus_send.Quit(None)
|
||||
|
||||
def start_cancel(self):
|
||||
if self.trans:
|
||||
self.trans.cancellable.cancel()
|
||||
|
||||
#进行更新的操作
|
||||
def start_update(self):
|
||||
try:
|
||||
def _download_info(parent,fetched,requested,bytes_transferred,bytes_sec):
|
||||
self.dbus_send.UpdateDownloadInfo(fetched,requested,bytes_transferred,10000,bytes_sec)
|
||||
#更新回调
|
||||
def _update_finished(parent,trans):
|
||||
if trans.exit:
|
||||
# 检查是否可以升级
|
||||
if trans.is_upgradable:
|
||||
self._make_meta_for_panel(trans.available_metadata,OUTPUT_JSON_PATH)
|
||||
self.dbus_send.UpdateDetectFinishedNext(True,[SYSTEM_UPDATE_GROUPS],'')
|
||||
else:
|
||||
self.dbus_send.UpdateDetectFinishedNext(True,[],'')
|
||||
else:
|
||||
self.dbus_send.UpdateDetectFinishedNext(trans.exit,[],trans.error_code)
|
||||
|
||||
update_backend = UpdateBackend(self,self.options.sysroot,self.options.os)
|
||||
update_backend.connect("transaction-done", _update_finished)
|
||||
update_backend.connect("download-info", _download_info)
|
||||
update_backend.run(self.trans)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def start_download(self):
|
||||
try:
|
||||
def _download_info(parent,fetched,requested,bytes_transferred,bytes_sec):
|
||||
self.dbus_send.UpdateDownloadInfo(fetched,requested,bytes_transferred,10000,bytes_sec)
|
||||
|
||||
def _download_finished(parent,trans):
|
||||
self.dbus_send.UpdateDownloadFinishedNext(trans.exit,[SYSTEM_UPDATE_GROUPS],trans.error_code)
|
||||
|
||||
# if trans.exit:
|
||||
# self.dbus_send.RebootLogoutRequired("reboot")
|
||||
|
||||
download_backend = DownloadBackend(self,self.options.sysroot,self.options.os)
|
||||
download_backend.connect("transaction-done", _download_finished)
|
||||
download_backend.connect("download-info", _download_info)
|
||||
download_backend.run(self.trans)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def start_deploy(self,device_status):
|
||||
try:
|
||||
def _deploy_finished(parent,trans):
|
||||
self.dbus_send.DeployUpdatFinishedNext(trans.exit,[SYSTEM_UPDATE_GROUPS],trans.available_metadata,trans.error_code)
|
||||
|
||||
if trans.exit:
|
||||
self._system_reboot_shutdown(device_status,self.options.prohibit_shutdown)
|
||||
|
||||
deploy_backend = DeployBackend(self,self.options.sysroot,self.options.os)
|
||||
deploy_backend.connect("transaction-done", _deploy_finished)
|
||||
deploy_backend.run(self.trans)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def start_rollback(self):
|
||||
try:
|
||||
def _rollback_finished(parent,trans):
|
||||
self.dbus_send.RollbackSysFinishedNext(trans.exit,trans.available_refs,trans.error_code)
|
||||
|
||||
if trans.exit:
|
||||
self._system_reboot_shutdown("reboot",self.options.prohibit_shutdown)
|
||||
|
||||
rollback_backend = RollbackBackend(self)
|
||||
rollback_backend.connect("transaction-done", _rollback_finished)
|
||||
rollback_backend.run(self.trans)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def _make_meta_for_panel(self,data,output_path):
|
||||
groups_base_info = {}
|
||||
output_json = {}
|
||||
|
||||
output_config_name = output_path + SYSTEM_UPDATE_GROUPS + '.json'
|
||||
|
||||
groups_base_info.update({"package":SYSTEM_UPDATE_GROUPS})
|
||||
groups_base_info.update({"new_version":data.setdefault("new_version","")})
|
||||
groups_base_info.update({"name":data.setdefault("name","")})
|
||||
groups_base_info.update({"description":data.setdefault("description","")})
|
||||
groups_base_info.update({"icon":data.setdefault("icon","")})
|
||||
groups_base_info.update({"total_download_size":data.setdefault("total_download_size","")})
|
||||
groups_base_info.update({"total_install_size":data.setdefault("total_install_size","")})
|
||||
groups_base_info.update({"changelog":data.setdefault("changelog","")})
|
||||
|
||||
output_json.update(groups_base_info)
|
||||
|
||||
with open(output_config_name, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_json, f, ensure_ascii=False, indent=4)
|
||||
logging.info("Generate Jsonfile(%s) to complete... ",output_config_name)
|
||||
|
||||
def _system_reboot_shutdown(self,status="reboot",prohibit_shutdown=False):
|
||||
if status == "shutdown":
|
||||
args = ["/sbin/shutdown","-h","now"]
|
||||
else:
|
||||
args = ["/sbin/shutdown","-r","now"]
|
||||
|
||||
if prohibit_shutdown:
|
||||
pass
|
||||
else:
|
||||
logging.info("The device will be %s by run system command(%r)...",status,args)
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode != 0:
|
||||
logging.info("The device has (%s) Failed...",status)
|
||||
return False
|
||||
|
||||
def _setup_dbus(self,bus):
|
||||
# check if there is another g-a-i already and if not setup one
|
||||
# listening on dbus
|
||||
try:
|
||||
bus_name = dbus.service.BusName(UPDATER_DBUS_SERVICE,
|
||||
bus,do_not_queue=True)
|
||||
logging.info("Initiate dbus success ...")
|
||||
return UpdateManagerDbusController(self,bus,bus_name)
|
||||
except dbus.exceptions.NameExistsException:
|
||||
if self.options.replace is False:
|
||||
logging.critical("Another daemon is already running")
|
||||
sys.exit(1)
|
||||
logging.warning("Replacing already running daemon")
|
||||
|
||||
retry_reboot_times = 0
|
||||
the_other_guy = bus.get_object(UPDATER_DBUS_SERVICE,
|
||||
UPDATER_DBUS_PATH)
|
||||
the_other_guy.Quit(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
timeout=300)
|
||||
time.sleep(1)
|
||||
while True:
|
||||
retry_reboot_times = retry_reboot_times + 1
|
||||
#当重试次数超过5次时退出程序
|
||||
if retry_reboot_times > 5:
|
||||
logging.critical("Reboot backend is Failed...")
|
||||
sys.exit(1)
|
||||
try:
|
||||
bus_name = dbus.service.BusName(UPDATER_DBUS_SERVICE,
|
||||
bus,
|
||||
do_not_queue=True)
|
||||
logging.warning("Replacing already running daemon to Success...")
|
||||
return UpdateManagerDbusController(self,bus,bus_name)
|
||||
except dbus.exceptions.NameExistsException:
|
||||
the_other_guy = bus.get_object(UPDATER_DBUS_SERVICE,
|
||||
UPDATER_DBUS_PATH)
|
||||
the_other_guy.Quit(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
timeout=300)
|
||||
logging.error("Dbus has not withdrawn and retry reboot times:%d...",retry_reboot_times)
|
||||
time.sleep(1)
|
|
@ -0,0 +1,448 @@
|
|||
#!/usr/bin/python3
|
||||
import os
|
||||
import dbus
|
||||
import time
|
||||
import dbus.service
|
||||
import logging
|
||||
from gettext import gettext as _
|
||||
from .Core.loop import mainloop
|
||||
import SystemUpdater.Core.enums as enums
|
||||
from SystemUpdater.Core.errors import *
|
||||
from SystemUpdater.Core.enums import *
|
||||
from xml.etree import ElementTree
|
||||
import locale
|
||||
from gettext import ngettext
|
||||
from math import ceil
|
||||
UPDATER_DBUS_INTERFACE = 'com.kylin.systemupgrade.interface'
|
||||
UPDATER_DBUS_PATH = '/com/kylin/systemupgrade'
|
||||
UPDATER_DBUS_SERVICE = 'com.kylin.systemupgrade'
|
||||
RUN_UNATTENDED_UPGRADE = '/var/run/unattended-upgrades.pid'
|
||||
SYSTEM_VERSION = '/etc/kylin-version/kylin-system-version.conf'
|
||||
UPDATER_DBUS_PATH_UTILS = '/com/kylin/systemupgrade/utils'
|
||||
|
||||
#颜色设置
|
||||
COLORLOG_SUFFIX = "\033[0m"
|
||||
|
||||
# Define some foreground colors
|
||||
BLACK = 30
|
||||
RED = 31
|
||||
GREEN = 32
|
||||
YELLOW = 33
|
||||
BLUE = 34
|
||||
MAGENTA = 35
|
||||
CYAN = 36
|
||||
WHITE = 37
|
||||
|
||||
#字体颜色
|
||||
FRONT_COLOR_SEQ = "\033[1;%dm"
|
||||
#背景颜色
|
||||
BACK_COLOR_SEQ = "\033[%d;1m"
|
||||
|
||||
COLORLOG_PREFIX = FRONT_COLOR_SEQ % GREEN
|
||||
COLORMETHOR_PREFIX = FRONT_COLOR_SEQ % CYAN
|
||||
|
||||
UU_UPGRADE_MODE_TIMING = 0
|
||||
UU_UPGRADE_MODE_BEFORE_SHUTDOWN = 1
|
||||
|
||||
ACTION_DEFUALT_STATUS = -1
|
||||
ACTION_DOWNLOADONLY = 1
|
||||
ACTION_DEPLOY = 2
|
||||
|
||||
def humanize_size(bytes):
|
||||
"""
|
||||
Convert a given size in bytes to a nicer better readable unit
|
||||
"""
|
||||
|
||||
if bytes < 1000 * 1000:
|
||||
# to have 0 for 0 bytes, 1 for 0-1000 bytes and for 1 and above
|
||||
# round up
|
||||
size_in_kb = int(ceil(bytes / float(1000)))
|
||||
# TRANSLATORS: download size of small updates, e.g. "250 kB"
|
||||
return ngettext("%(size).0f kB", "%(size).0f kB", size_in_kb) % {
|
||||
"size": size_in_kb}
|
||||
else:
|
||||
# TRANSLATORS: download size of updates, e.g. "2.3 MB"
|
||||
return locale.format_string(_("%.1f MB"), bytes / 1000.0 / 1000.0)
|
||||
|
||||
|
||||
def get_proc_from_dbus_name(dbus_name, bus=None):
|
||||
"""Return a deferred that gets the id of process owning the given
|
||||
system D-Bus name.
|
||||
"""
|
||||
|
||||
if not bus:
|
||||
bus = dbus.SystemBus()
|
||||
bus_obj = bus.get_object("org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus/Bus")
|
||||
pid = bus_obj.GetConnectionUnixProcessID(dbus_name,
|
||||
dbus_interface="org.freedesktop.DBus")
|
||||
# proc = psutil.Process(int(pid))
|
||||
|
||||
with open("/proc/%s/status" % pid) as process:
|
||||
values = [v for v in process.readlines() if v.startswith("Uid:")]
|
||||
uid = int(values[0].split()[1])
|
||||
|
||||
#检查是否root用户执行
|
||||
if uid == 0:
|
||||
return "root"
|
||||
|
||||
# return proc.name()
|
||||
return uid
|
||||
|
||||
#dbus 建立
|
||||
class UpdateManagerDbusController(dbus.service.Object):
|
||||
""" this is a helper to provide the UpdateManagerIFace """
|
||||
|
||||
ACTION_DEFUALT_STATUS = -1
|
||||
ACTION_UPDATE = 0
|
||||
ACTION_DOWNLOADONLY = 1
|
||||
ACTION_DEPLOY = 2
|
||||
ACTION_ROLLBACK = 3
|
||||
|
||||
RETURN_SUCCESS_CODE = 0
|
||||
RETURN_SUCCESS_DESC = ""
|
||||
|
||||
RETURN_UNKNOWN_CODE = -1
|
||||
RETURN_UNKNOWN_DESC = ""
|
||||
|
||||
RETURN_BUSY_STATE = 1
|
||||
RETURN_BUSY_DESC = "In the process of updating or Upgrading..."
|
||||
|
||||
def __init__(self, parent,bus,bus_name,
|
||||
object_path=UPDATER_DBUS_PATH):
|
||||
dbus.service.Object.__init__(self, bus_name, object_path)
|
||||
self.parent = parent
|
||||
# self.cache = parent.cache
|
||||
self.bus = bus
|
||||
self.prohibit_list = []
|
||||
|
||||
self.database = self.parent.sqlite3_server
|
||||
|
||||
self.now_working = self.ACTION_DEFUALT_STATUS
|
||||
|
||||
self.transaction = None
|
||||
if not self.parent.options.debug:
|
||||
self.prohibit_list = ["dbus-send","gdbus"]
|
||||
|
||||
def _check_prohibit_user(self, sender_name):
|
||||
if sender_name in self.prohibit_list:
|
||||
raise dbus.exceptions.DBusException("ERROR: You are not allowed to perform this action.")
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,
|
||||
in_signature="", out_signature="",
|
||||
sender_keyword="caller_name")
|
||||
def Quit(self, caller_name):
|
||||
"""Request a shutdown of the daemon."""
|
||||
logging.info("Quitting was requested")
|
||||
logging.debug("Quitting main loop...")
|
||||
mainloop.quit()
|
||||
logging.debug("Exit")
|
||||
|
||||
|
||||
#获取后端现在的状态
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,in_signature='s',out_signature='i',sender_keyword='sender')
|
||||
def GetBackendStatus(self,user_lang,sender=None):
|
||||
try:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' GetBackendStatus and user_lang = %s sender_name:%s status:%d...',str(user_lang),sender_name,self.now_working)
|
||||
return self.now_working
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return self.now_working
|
||||
|
||||
#更新的dbus
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,out_signature='b',sender_keyword='sender')
|
||||
def CheckPopupOnPoweroffInstalled(self,sender=None):
|
||||
try:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' ChcekPopupOnPoweroffInstalled sender:%s...',sender_name)
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
|
||||
|
||||
# =============================== 检查更新 =============================== */
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,out_signature='is',sender_keyword='sender')
|
||||
def UpdateDetect(self,sender=None):
|
||||
try:
|
||||
#处于更新和升级中的话 不进行更新
|
||||
if self.now_working != ACTION_DEFUALT_STATUS:
|
||||
logging.warning('UpdateDetect In the process of Updating or Upgrading...')
|
||||
return self.RETURN_BUSY_STATE,self.RETURN_BUSY_DESC
|
||||
else:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' UpdateDetect sender:%s...',sender_name)
|
||||
self._check_prohibit_user(sender_name)
|
||||
self.parent.start_update()
|
||||
self.now_working = self.ACTION_UPDATE
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return self.RETURN_UNKNOWN_CODE,str(e)
|
||||
|
||||
#更新 信号
|
||||
def UpdateDetectFinishedNext(self,success,upgrade_group,error_code=''):
|
||||
self.UpdateDetectFinished(success,upgrade_group,error_code,get_error_description_from_enum(error_code))
|
||||
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='basss')
|
||||
def UpdateDetectFinished(self, success, upgrade_group,error_code='',error_desc=''):
|
||||
self.now_working = self.ACTION_DEFUALT_STATUS
|
||||
logging.info(COLORLOG_PREFIX + "Emitting"+ COLORLOG_SUFFIX + " UpdateDetectFinished success = %r , upgrade_group = %a, error_code = %s , error_desc = %s ",\
|
||||
success,upgrade_group,error_code,error_desc)
|
||||
|
||||
# =============================== 下载 =============================== */
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,out_signature='is',sender_keyword='sender')
|
||||
def UpdateDownloadAll(self,sender=None):
|
||||
try:
|
||||
#处于更新和升级中的话 不进行更新
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' UpdateDownloadAll sender:%s...',sender_name)
|
||||
self._check_prohibit_user(sender_name)
|
||||
self.parent.start_download()
|
||||
self.now_working = self.ACTION_DOWNLOADONLY
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return self.RETURN_UNKNOWN_CODE,str(e)
|
||||
|
||||
# 下载信号
|
||||
def UpdateDownloadFinishedNext(self,success,upgrade_group,error_code=''):
|
||||
self.UpdateDownloadFinished(success,upgrade_group,error_code,get_error_description_from_enum(error_code))
|
||||
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='basss')
|
||||
def UpdateDownloadFinished(self, success, upgrade_group,error_code='',error_desc=''):
|
||||
self.now_working = self.ACTION_DEFUALT_STATUS
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" UpdateDownloadFinished success = %r , upgrade_group = %a, error_code = %s , error_desc = %s ",\
|
||||
success,upgrade_group, error_code,error_desc)
|
||||
|
||||
#发送下载包信息 fix bug 字节大小改成u 无符号32位
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE, signature='iiuui')
|
||||
def UpdateDownloadInfo(self,current_items, total_items, currenty_bytes, total_bytes, current_cps):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" UpdateDownloadInfo current_items = %d, total_items = %d, currenty_bytes = %s, total_bytes = %s, current_cps = %s/s",
|
||||
current_items, total_items, \
|
||||
humanize_size(currenty_bytes), humanize_size(total_bytes),\
|
||||
humanize_size(current_cps))
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,out_signature='is',sender_keyword='sender')
|
||||
def CancelDownload(self,sender=None):
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' CancelDownload ')
|
||||
|
||||
self.parent.start_cancel()
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
|
||||
# =============================== 部署 =============================== */
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,in_signature='s',out_signature='is',sender_keyword='sender')
|
||||
def DeployLatestUpdate(self,mode,sender=None):
|
||||
try:
|
||||
#处于更新和升级中的话 不进行更新
|
||||
if self.now_working != ACTION_DEFUALT_STATUS:
|
||||
logging.warning('DeployLatestUpdate In the process of Updating or Upgrading...')
|
||||
return self.RETURN_BUSY_STATE,self.RETURN_BUSY_DESC
|
||||
else:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' DeployLatestUpdate sender:%s...',sender_name)
|
||||
self._check_prohibit_user(sender_name)
|
||||
self.parent.start_deploy(str(mode))
|
||||
self.now_working = self.ACTION_DEPLOY
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return self.RETURN_UNKNOWN_CODE,str(e)
|
||||
|
||||
def DeployUpdatFinishedNext(self,success,upgrade_group,metadata,error_code=''):
|
||||
self.DeployUpdatFinished(success,upgrade_group,error_code,get_error_description_from_enum(error_code))
|
||||
self.database.insert_info(success,metadata,error_code)
|
||||
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='basss')
|
||||
def DeployUpdatFinished(self, success, upgrade_group,error_code='',error_desc=''):
|
||||
self.now_working = self.ACTION_DEFUALT_STATUS
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" DeployUpdatFinished success = %r , upgrade_group = %a, error_code = %s , error_desc = %s ",\
|
||||
success,upgrade_group, error_code,error_desc)
|
||||
|
||||
# =============================== 回滚 =============================== */
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,out_signature='is',sender_keyword='sender')
|
||||
def RollbackSysVersion(self,mode,version,sender=None):
|
||||
try:
|
||||
#处于更新和升级中的话 不进行更新
|
||||
if self.now_working != ACTION_DEFUALT_STATUS:
|
||||
logging.warning('RollbackSysVersion In the process of Updating or Upgrading...')
|
||||
return self.RETURN_BUSY_STATE,self.RETURN_BUSY_DESC
|
||||
else:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' RollbackSysVersion sender:%s...',sender_name)
|
||||
self._check_prohibit_user(sender_name)
|
||||
self.parent.start_rollback()
|
||||
self.now_working = self.ACTION_ROLLBACK
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return self.RETURN_UNKNOWN_CODE,str(e)
|
||||
|
||||
#向数据库display表中插入数据
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='ss', out_signature='is', sender_keyword='sender')
|
||||
def InsertInstallState(self, item, value, sender=None):
|
||||
try:
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' InsertInstallState, options:%s,value:%s, InsertInstallState sender: %s .' % (item, value, sender_name))
|
||||
self.database.insert_into_display(item, value)
|
||||
logging.info("Database insert to display successfully,options:%s,value:%s" % (item, value))
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
except Exception as e:
|
||||
logging.error("Database insert to display failed,options:%s,value:%s" % (item, value))
|
||||
return self.RETURN_UNKNOWN_CODE,str(e)
|
||||
|
||||
def RollbackSysFinishedNext(self, success, version_name,error_code):
|
||||
self.RollbackSysFinished(success,version_name,error_code,get_error_description_from_enum(error_code))
|
||||
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='bsss')
|
||||
def RollbackSysFinished(self, success, version_name,error_code='',error_desc=''):
|
||||
self.now_working = self.ACTION_DEFUALT_STATUS
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" RollbackSysFinished success = %r , upgrade_group = %s, error_code = %s , error_desc = %s ",\
|
||||
success,version_name, error_code,error_desc)
|
||||
|
||||
#重启和注销请求信号
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='s')
|
||||
def RebootLogoutRequired(self,required_status=''):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting"+ COLORLOG_SUFFIX + " RebootLogoutRequired required_status = %s",required_status)\
|
||||
|
||||
WRITABLE_PROPERTIES = ()
|
||||
|
||||
# pylint: disable-msg=C0103,C0322
|
||||
@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
signature="sa{sv}as")
|
||||
def PropertiesChanged(self, interface, changed_properties,
|
||||
invalidated_properties):
|
||||
"""The signal gets emitted if a property of the object's
|
||||
interfaces changed.
|
||||
|
||||
:param property: The name of the interface.
|
||||
:param changed_properties: A dictrionary of changed
|
||||
property/value pairs
|
||||
:param invalidated_properties: An array of property names which
|
||||
changed but the value isn't conveyed.
|
||||
|
||||
:type interface: s
|
||||
:type changed_properties: a{sv}
|
||||
:type invalidated_properties: as
|
||||
"""
|
||||
logging.info("Emitting PropertiesChanged: %s, %s, %s" %
|
||||
(interface, changed_properties, invalidated_properties))
|
||||
|
||||
# pylint: disable-msg=C0103,C0322
|
||||
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
|
||||
in_signature='', out_signature='s',
|
||||
path_keyword='object_path',
|
||||
connection_keyword='connection')
|
||||
def Introspect(self, object_path, connection):
|
||||
# Inject the properties into the introspection xml data
|
||||
data = dbus.service.Object.Introspect(self, object_path, connection)
|
||||
xml = ElementTree.fromstring(data)
|
||||
for iface in xml.findall("interface"):
|
||||
props = self._get_properties(iface.attrib["name"])
|
||||
if not hasattr(props,'items'):
|
||||
continue
|
||||
for key, value in props.items():
|
||||
attrib = {"name": key}
|
||||
if key in self.WRITABLE_PROPERTIES:
|
||||
attrib["access"] = "readwrite"
|
||||
else:
|
||||
attrib["access"] = "read"
|
||||
if isinstance(value, dbus.String):
|
||||
attrib["type"] = "s"
|
||||
elif isinstance(value, dbus.UInt32):
|
||||
attrib["type"] = "u"
|
||||
elif isinstance(value, dbus.Int32):
|
||||
attrib["type"] = "i"
|
||||
elif isinstance(value, dbus.UInt64):
|
||||
attrib["type"] = "t"
|
||||
elif isinstance(value, dbus.Int64):
|
||||
attrib["type"] = "x"
|
||||
elif isinstance(value, dbus.Boolean):
|
||||
attrib["type"] = "b"
|
||||
elif isinstance(value, dbus.Struct):
|
||||
attrib["type"] = "(%s)" % value.signature
|
||||
elif isinstance(value, dbus.Dictionary):
|
||||
attrib["type"] = "a{%s}" % value.signature
|
||||
elif isinstance(value, dbus.Array):
|
||||
attrib["type"] = "a%s" % value.signature
|
||||
else:
|
||||
raise Exception("Type %s of property %s isn't "
|
||||
"convertable" % (type(value), key))
|
||||
iface.append(ElementTree.Element("property", attrib))
|
||||
new_data = ElementTree.tostring(xml, encoding="UTF-8")
|
||||
return new_data
|
||||
|
||||
# pylint: disable-msg=C0103,C0322
|
||||
@dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
in_signature="ssv", out_signature="",
|
||||
sender_keyword="sender")
|
||||
def Set(self, iface, name, value, sender):
|
||||
"""Set a property.
|
||||
|
||||
Only the user who intiaited the transaction is
|
||||
allowed to modify it.
|
||||
|
||||
:param iface: The interface which provides the property.
|
||||
:param name: The name of the property which should be modified.
|
||||
:param value: The new value of the property.
|
||||
|
||||
:type iface: s
|
||||
:type name: s
|
||||
:type value: v
|
||||
"""
|
||||
logging.info("Set() was called: %s, %s" % (name, value))
|
||||
return self._set_property(iface, name, value, sender)
|
||||
|
||||
# pylint: disable-msg=C0103,C0322
|
||||
@dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
in_signature="s", out_signature="a{sv}")
|
||||
def GetAll(self, iface):
|
||||
"""Get all available properties of the given interface."""
|
||||
logging.info("GetAll() was called: %s" % iface)
|
||||
return self._get_properties(iface)
|
||||
|
||||
# pylint: disable-msg=C0103,C0322
|
||||
@dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
in_signature="ss", out_signature="v")
|
||||
def Get(self, iface, property):
|
||||
"""Return the value of the given property provided by the given
|
||||
interface.
|
||||
"""
|
||||
logging.info("Get() was called: %s, %s" % (iface, property))
|
||||
return self._get_properties(iface)[property]
|
||||
|
||||
def _set_property(self, iface, name, value, sender):
|
||||
"""Helper to set a property on the properties D-Bus interface."""
|
||||
'''
|
||||
if iface == UPDATER_DBUS_INTERFACE:
|
||||
if name == "ShutdownInstall":
|
||||
self.parent.configs_uncover.setValue("InstallMode","shutdown_install",str(bool(value)))
|
||||
elif name == "P2pBootstrap":
|
||||
self.parent.apt_p2p_config.set_bootstrap(str(value))
|
||||
else:
|
||||
raise dbus.exceptions.DBusException("Unknown or read only "
|
||||
"property: %s" % name)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException("Unknown interface: %s" %
|
||||
iface)
|
||||
'''
|
||||
|
||||
def _get_properties(self, iface):
|
||||
"""Helper get the properties of a D-Bus interface."""
|
||||
if iface == UPDATER_DBUS_INTERFACE:
|
||||
return {
|
||||
"CurentOriginRefs": dbus.String(""),
|
||||
"RollbackDeployment":dbus.String(""),
|
||||
}
|
||||
else:
|
||||
return {}
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from gi.repository import Gio
|
||||
from gettext import gettext as _
|
||||
from SystemUpdater.Core.errors import *
|
||||
from SystemUpdater.Core.enums import *
|
||||
|
||||
class UpdatesAvailable():
|
||||
"""
|
||||
Represent the (potentially partial) results of an unattended-upgrades
|
||||
run
|
||||
"""
|
||||
|
||||
# 更新的缓存数据保存位置
|
||||
UPDATE_AVAILABLE_DATA = "/var/cache/kylin-system-updater/update_available_data.json"
|
||||
|
||||
def __init__(self,parent):
|
||||
self.parent = parent
|
||||
|
||||
self.error_code = ''
|
||||
self.exit = None
|
||||
|
||||
self.is_upgradable = False
|
||||
self.available_checksum = None
|
||||
self.available_refs = None
|
||||
self.available_metadata = None
|
||||
|
||||
def cancelled():
|
||||
logging.info("Task has been cancelled...")
|
||||
self.cancellable = Gio.Cancellable.new()
|
||||
self.cancellable.connect(cancelled)
|
||||
|
||||
def _output_resolver_pkgs(self,pkgs):
|
||||
OUTPUT_JSON = "/var/lib/kylin-system-updater/json/requires_upgrade_pkgs.json"
|
||||
try:
|
||||
output_upgrade = {}
|
||||
|
||||
pkg_string = ''
|
||||
for pkg in pkgs:
|
||||
pkg_string = pkg_string + ' ' + str(pkg)
|
||||
|
||||
output_upgrade.update({"packages":pkg_string})
|
||||
|
||||
with open(OUTPUT_JSON, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_upgrade, f, ensure_ascii=False, indent=4)
|
||||
|
||||
logging.info("Generate Jsonfile(%s) to complete... ",OUTPUT_JSON)
|
||||
logging.info("Update Packages list to config file...")
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
|
||||
def _write_local(self):
|
||||
try:
|
||||
output_upgrade = {}
|
||||
output_upgrade.update({"steps_queue":self.steps_queue})
|
||||
output_upgrade.update({"_problem_resolver":self._problem_resolver})
|
||||
output_upgrade.update({"updating_data":self.updating_data})
|
||||
output_upgrade.update({"upgrade_singles":self.upgrade_singles})
|
||||
output_upgrade.update({"upgrade_groups":self.upgrade_groups})
|
||||
output_upgrade.update({"upgrade_steps":self.upgrade_steps})
|
||||
output_upgrade.update({"device_status":self.device_status})
|
||||
output_upgrade.update({"shutdown_install":self.shutdown_install})
|
||||
output_upgrade.update({"signal_trigger":self.signal_trigger})
|
||||
output_upgrade.update({"_available":self._available})
|
||||
|
||||
#6 产生JSON文件
|
||||
with open(self.UPDATE_AVAILABLE_DATA, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_upgrade, f, ensure_ascii=False, indent=4)
|
||||
logging.info("Write Upgrade data to local json(%s) in shutdown model...",self.UPDATE_AVAILABLE_DATA)
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
def read_local(self):
|
||||
#读取组JSON文件
|
||||
try:
|
||||
with open(self.UPDATE_AVAILABLE_DATA,'r') as f:
|
||||
data = json.load(f)
|
||||
self.steps_queue = data["steps_queue"]
|
||||
self._problem_resolver = data["_problem_resolver"]
|
||||
self.updating_data = data["updating_data"]
|
||||
self.upgrade_singles = data["upgrade_singles"]
|
||||
self.upgrade_groups = data["upgrade_groups"]
|
||||
self.upgrade_steps = data["upgrade_steps"]
|
||||
self.device_status = data["device_status"]
|
||||
self.shutdown_install = data["shutdown_install"]
|
||||
self.signal_trigger = data["signal_trigger"]
|
||||
self._available = data["_available"]
|
||||
logging.info("Finished: reading upgrade data from the local file...")
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
|
||||
def _get_available(self):
|
||||
return self._available
|
||||
|
||||
def _set_available(self, state):
|
||||
self._available = state
|
||||
self._write_local()
|
||||
|
||||
available = property(_get_available, _set_available)
|
|
@ -0,0 +1,101 @@
|
|||
# UpdateManager.py
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import dbus
|
||||
import logging
|
||||
import dbus.service
|
||||
import traceback
|
||||
from gettext import gettext as _
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
from gi.repository import GLib
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
|
||||
from .UpgradeStrategiesDbus import UpgradeStrategiesDbusController,UPDATER_DBUS_INTERFACE,UPDATER_DBUS_PATH,UPDATER_DBUS_SERVICE
|
||||
from .Core.Database import Sqlite3Server
|
||||
from .Core.loop import mainloop
|
||||
|
||||
from SystemUpdater.Core.UpdaterConfigParser import UpgradeConfig
|
||||
|
||||
STRATEGY_IDLE_INTERVAL = 2*60
|
||||
STRATEGY_IDLE_TIMEOUT = 6*60
|
||||
class UpgradeStrategies():
|
||||
def __init__(self,options):
|
||||
try:
|
||||
self.options = options
|
||||
#dbus
|
||||
self.dbusController = self._setup_dbus()
|
||||
#config
|
||||
self.uuconfigs = UpgradeConfig(datadir = "/var/lib/unattended-upgrades/", name = "unattended-upgrades-policy.conf")
|
||||
self.sqlite3_server = Sqlite3Server(self, _no_DataMigration=True)
|
||||
#策略配置接口的超时退出机制
|
||||
self.strategy_timestamp = 0
|
||||
# GLib.timeout_add_seconds(STRATEGY_IDLE_INTERVAL,
|
||||
# self._check_strategy_inactivity)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
traceback.print_exc()
|
||||
|
||||
def run(self):
|
||||
"""Start the daemon and listen for calls."""
|
||||
logging.info("Waiting for calls...")
|
||||
try:
|
||||
mainloop.run()
|
||||
except KeyboardInterrupt:
|
||||
self.dbusController.Quit(None)
|
||||
|
||||
def _setup_dbus(self):
|
||||
# check if there is another g-a-i already and if not setup one
|
||||
# listening on dbus
|
||||
bus = dbus.SystemBus()
|
||||
try:
|
||||
bus_name = dbus.service.BusName(UPDATER_DBUS_SERVICE,
|
||||
bus,
|
||||
do_not_queue=True)
|
||||
logging.info("Initiate dbus success ...")
|
||||
return UpgradeStrategiesDbusController(self, bus_name)
|
||||
except dbus.exceptions.NameExistsException:
|
||||
if self.options.replace is False:
|
||||
logging.critical("Another daemon is already running")
|
||||
sys.exit(1)
|
||||
logging.warning("Replacing already running daemon")
|
||||
|
||||
retry_reboot_times = 0
|
||||
the_other_guy = bus.get_object(UPDATER_DBUS_SERVICE,
|
||||
UPDATER_DBUS_PATH)
|
||||
the_other_guy.Quit(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
timeout=300)
|
||||
time.sleep(1)
|
||||
while True:
|
||||
retry_reboot_times = retry_reboot_times + 1
|
||||
#当重试次数超过5次时退出程序
|
||||
if retry_reboot_times > 5:
|
||||
logging.critical("Reboot backend is Failed...")
|
||||
sys.exit(1)
|
||||
try:
|
||||
bus_name = dbus.service.BusName(UPDATER_DBUS_SERVICE,
|
||||
bus,
|
||||
do_not_queue=True)
|
||||
logging.warning("Replacing already running daemon to Success...")
|
||||
return UpgradeStrategiesDbusController(self, bus_name)
|
||||
except dbus.exceptions.NameExistsException:
|
||||
the_other_guy = bus.get_object(UPDATER_DBUS_SERVICE,
|
||||
UPDATER_DBUS_PATH)
|
||||
the_other_guy.Quit(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
timeout=300)
|
||||
logging.error("Dbus has not withdrawn and retry reboot times:%d...",retry_reboot_times)
|
||||
time.sleep(1)
|
||||
|
||||
def _check_strategy_inactivity(self):
|
||||
logging.info("Checking for inactivity in Strategies daemon ...")
|
||||
timestamp = self.strategy_timestamp
|
||||
if timestamp == 0:
|
||||
self.strategy_timestamp = time.time()
|
||||
return True
|
||||
#超时退出
|
||||
if self.strategy_timestamp != 0 and time.time() - self.strategy_timestamp > STRATEGY_IDLE_TIMEOUT:
|
||||
logging.warning("Quitting due to inactivity")
|
||||
self.dbusController.Quit(None)
|
||||
return False
|
||||
return True
|
|
@ -0,0 +1,610 @@
|
|||
#!/usr/bin/python3
|
||||
import os
|
||||
import dbus
|
||||
import dbus.service
|
||||
import logging
|
||||
import subprocess
|
||||
from gettext import gettext as _
|
||||
from .Core.loop import mainloop
|
||||
from SystemUpdater.Core.utils import get_proc_from_dbus_name
|
||||
|
||||
UPDATER_DBUS_INTERFACE = 'com.kylin.UpgradeStrategies.interface'
|
||||
UPDATER_DBUS_PATH = '/com/kylin/UpgradeStrategies'
|
||||
UPDATER_DBUS_SERVICE = 'com.kylin.UpgradeStrategies'
|
||||
RUN_UNATTENDED_UPGRADE = '/var/run/unattended-upgrades.pid'
|
||||
SYSTEM_VERSION = '/etc/kylin-version/kylin-system-version.conf'
|
||||
|
||||
#颜色设置
|
||||
COLORLOG_SUFFIX = "\033[0m"
|
||||
|
||||
# Define some foreground colors
|
||||
BLACK = 30
|
||||
RED = 31
|
||||
GREEN = 32
|
||||
YELLOW = 33
|
||||
BLUE = 34
|
||||
MAGENTA = 35
|
||||
CYAN = 36
|
||||
WHITE = 37
|
||||
|
||||
#字体颜色
|
||||
FRONT_COLOR_SEQ = "\033[1;%dm"
|
||||
#背景颜色
|
||||
BACK_COLOR_SEQ = "\033[%d;1m"
|
||||
|
||||
COLORLOG_PREFIX = FRONT_COLOR_SEQ % GREEN
|
||||
COLORMETHOR_PREFIX = FRONT_COLOR_SEQ % CYAN
|
||||
|
||||
UU_UPGRADE_MODE_AUTOMATIC_DOWNLOAD = 0
|
||||
UU_UPGRADE_MODE_MANUAL = 1
|
||||
UU_UPGRADE_MODE_AUTOMATIC_INSTALL = 2
|
||||
UU_UPGRADE_MODE_BEFORE_SHUTDOWN = 3
|
||||
|
||||
|
||||
#dbus 建立
|
||||
class UpgradeStrategiesDbusController(dbus.service.Object):
|
||||
""" this is a helper to provide the UpdateManagerIFace """
|
||||
|
||||
P2P_DEDAULT_PATH = "/etc/default/apt-p2p"
|
||||
RETURN_SUCCESS_CODE = 0
|
||||
RETURN_SUCCESS_DESC = ""
|
||||
|
||||
RETURN_UNKNOWN_CODE = -1
|
||||
RETURN_UNKNOWN_DESC = ""
|
||||
|
||||
def __init__(self, parent, bus_name,
|
||||
object_path=UPDATER_DBUS_PATH):
|
||||
dbus.service.Object.__init__(self, bus_name, object_path)
|
||||
self.parent = parent
|
||||
self.bus = dbus.SystemBus()
|
||||
|
||||
self.transaction = None
|
||||
|
||||
def __check_change__(self, _config = None, _section = "", _option = "", _value = ""):
|
||||
if _config == None:
|
||||
return False
|
||||
if _value == _config.getWithDefault(_section,_option,_value," "):
|
||||
return True
|
||||
return False
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,
|
||||
in_signature="", out_signature="",
|
||||
sender_keyword="caller_name")
|
||||
def Quit(self, caller_name):
|
||||
"""Request a shutdown of the daemon."""
|
||||
#如果在下载就请求 取消
|
||||
logging.info("Quitting was requested")
|
||||
logging.debug("Quitting main loop...")
|
||||
mainloop.quit()
|
||||
logging.debug("Exit")
|
||||
|
||||
## dbus接口: 开启或关闭预下载功能
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='s', out_signature='is',sender_keyword='sender')
|
||||
def ChangingP2PStatus(self,_status,sender = None):
|
||||
status = str(_status)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' ChangingP2PStatus, _status = %s , sender name: %s',status,sender_name)
|
||||
|
||||
if os.path.exists(self.P2P_DEDAULT_PATH):
|
||||
if status == "enable":
|
||||
with open(self.P2P_DEDAULT_PATH, 'w+') as configfile:
|
||||
configfile.write("#enable=true\n")
|
||||
#第一次进行检查是否已经开启
|
||||
args = ["systemctl","is-enabled","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode != 0:
|
||||
logging.info("Apt-p2p service is not runing and will be enable...")
|
||||
#第二次进行重启
|
||||
args = ["systemctl","enable","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode == 0:
|
||||
logging.info("Service Enable Execute successfully")
|
||||
#第三次进行重启
|
||||
args = ["systemctl","restart","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode == 0:
|
||||
logging.info("Restart Execute successfully")
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
else:
|
||||
logging.error(str(p.stdout))
|
||||
logging.error("Failed to execute reboot")
|
||||
return self.RETURN_UNKNOWN_CODE,str(p.stdout)
|
||||
else:
|
||||
logging.error(str(p.stdout))
|
||||
logging.error("Failed to execute enable")
|
||||
return self.RETURN_UNKNOWN_CODE,str(p.stdout)
|
||||
else:
|
||||
logging.info("Apt-p2p service has been enabled and not need to reabled...")
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
|
||||
elif status == "disable":
|
||||
with open(self.P2P_DEDAULT_PATH, 'w+') as configfile:
|
||||
configfile.write("enable=false\n")
|
||||
|
||||
args = ["systemctl","is-enabled","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode == 0:
|
||||
logging.info("Apt-p2p service is runing and will be disable...")
|
||||
args = ["systemctl","disable","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode == 0:
|
||||
logging.info("Service disable Execute successfully")
|
||||
|
||||
args = ["systemctl","stop","apt-p2p.service"]
|
||||
p = subprocess.run(args, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
|
||||
if p.returncode == 0:
|
||||
logging.info("Stop Execute successfully")
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
else:
|
||||
logging.error(str(p.stdout))
|
||||
logging.error("Failed to execute Stop")
|
||||
return self.RETURN_UNKNOWN_CODE,str(p.stdout)
|
||||
else:
|
||||
logging.error(str(p.stdout))
|
||||
logging.error("Failed to execute disable")
|
||||
return self.RETURN_UNKNOWN_CODE,str(p.stdout)
|
||||
else:
|
||||
logging.info("Apt-p2p service has been disabled and not need to redisabled...")
|
||||
return self.RETURN_SUCCESS_CODE,self.RETURN_SUCCESS_DESC
|
||||
else:
|
||||
logging.warning("error: input value _status=%s",status)
|
||||
else:
|
||||
logging.warning("apt-p2p function is not install...")
|
||||
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='b', out_signature='b',sender_keyword='sender')
|
||||
def SetUpgradeStrategyState(self,state,sender=None):
|
||||
state=bool(state)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetUpdateStrategyState, upgrade strategy state is %r, sender name: %s .',state,sender_name)
|
||||
try:
|
||||
if state:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "updateStrategiesManager", "strategiesState", "True"):
|
||||
self.parent.uuconfigs.setValue("updateStrategiesManager", "strategiesState", "True", True)
|
||||
self.StrategyChanged("strategiesState","True")
|
||||
else:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "updateStrategiesManager", "strategiesState", "False"):
|
||||
self.parent.uuconfigs.setValue("updateStrategiesManager", "strategiesState", "False", True)
|
||||
self.StrategyChanged("strategiesState","False")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
## 设置更新周期
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='s', out_signature='b',sender_keyword='sender')
|
||||
def SetUpgradeMode(self, mode, sender = None):
|
||||
_mode = str(mode)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetUpgradeMode, mode: %s , sender:%s .',_mode,sender_name)
|
||||
try:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "updateStrategiesManager", "installType", _mode):
|
||||
self.parent.uuconfigs.setValue("updateStrategiesManager", "installType", _mode, True)
|
||||
self.StrategyChanged("installType",_mode)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
## dbus接口: 开启或关闭预下载功能
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='bs', out_signature='b',sender_keyword='sender')
|
||||
def SetPreDownloadState(self, _state, _time, sender = None):
|
||||
state = bool(_state)
|
||||
time = str(_time)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetPreDownloadState, state is %r, time: %s, sender name: %s .',state,time,sender_name)
|
||||
try:
|
||||
if state:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "preDownload", "on"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "preDownload", "on", True)
|
||||
self.PropertyChanged("preDownload","on")
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "preDownloadTime", time):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "preDownloadTime", time, True)
|
||||
self.PropertyChanged("preDownloadTime",time)
|
||||
else:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "preDownload", "off"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "preDownload", "off", True)
|
||||
self.PropertyChanged("preDownload","off")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
## 设置更新周期
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='i', out_signature='b',sender_keyword='sender')
|
||||
def SetUpdateDays(self, days, sender = None):
|
||||
_days = int(days)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetUpdateDays, days: %d , sender:%s .'\
|
||||
,_days,sender_name)
|
||||
try:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "updateDays", _days):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "updateDays", str(_days), True)
|
||||
self.PropertyChanged("updateDays",str(_days))
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
# 设置自动更新时间
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='s', out_signature='bs',sender_keyword='sender')
|
||||
def SetAutoUpgradeRandomRange(self,randomRange,sender=None):
|
||||
_randomRange = str(randomRange)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' SetAutoUpgradeRandomRange will be set value %s, sender: %s .',\
|
||||
_randomRange,sender_name)
|
||||
try:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "randomRange", _randomRange):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "randomRange", _randomRange, True)
|
||||
self.PropertyChanged("randomRange",_randomRange)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return True,"success"
|
||||
|
||||
## 设置是否开启自动重启,以及设置自动重启的时间
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='bs', out_signature='b',sender_keyword='sender')
|
||||
def SetAutomaticReboot(self, status, reboot_time, sender = None):
|
||||
_state = bool(status)
|
||||
_reboot_time = str(reboot_time)
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetAutomaticReboot, status is %r, reboot_time: %s, sender name: %s .'\
|
||||
,_state,_reboot_time,sender_name)
|
||||
try:
|
||||
if _state:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "automaticReboot", "on"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "automaticReboot", "on", True)
|
||||
self.PropertyChanged("automaticReboot","on")
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "automaticRebootTime", _reboot_time):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "automaticRebootTime", _reboot_time, True)
|
||||
self.PropertyChanged("automaticRebootTime",_reboot_time)
|
||||
else:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "automaticReboot", "off"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "automaticReboot", "off", True)
|
||||
self.PropertyChanged("automaticReboot","off")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
## dbus接口: 开启关闭自动更新功能
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='b', out_signature='b')
|
||||
def SetAutoUpgradeState(self, _state):
|
||||
state = bool(_state)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetAutoUpgradeState, state is %r ...',state)
|
||||
try:
|
||||
if state:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "autoUpgradeState", "on"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "autoUpgradeState", "on", True)
|
||||
self.parent.sqlite3_server.insert_into_display("autoupdate_allow", "true")
|
||||
self.PropertyChanged("autoUpgradeState","on")
|
||||
self.ButtonStatusChange("autoUpgradeStatus", "true")
|
||||
else :
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "autoUpgradeState", "off"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "autoUpgradeState", "off", True)
|
||||
self.parent.sqlite3_server.insert_into_display("autoupdate_allow", "false")
|
||||
self.PropertyChanged("autoUpgradeState","off")
|
||||
self.ButtonStatusChange("autoUpgradeStatus", "false")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
## dbus接口: 设置自动更新策略
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='is', out_signature='b')
|
||||
def SetAutoUpgradeMode(self, mode, time):
|
||||
_time = str(time)
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' SetAutoUpgradeMode, mode is %s, time is %s ...',mode,_time)
|
||||
try:
|
||||
if mode == UU_UPGRADE_MODE_AUTOMATIC_DOWNLOAD:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "downloadMode", "timing"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "downloadMode", "timing", True)
|
||||
self.PropertyChanged("downloadMode","timing")
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "downloadTime", str(_time)):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "downloadTime", str(_time), True)
|
||||
self.PropertyChanged("downloadTime",str(_time))
|
||||
self.ButtonStatusChange("autoUpgradeTime", str(_time))
|
||||
elif mode == UU_UPGRADE_MODE_AUTOMATIC_INSTALL:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "installMode", "timing"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "installMode", "timing", True)
|
||||
self.PropertyChanged("installMode","timing")
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "installTime", str(_time)):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "installTime", str(_time), True)
|
||||
self.PropertyChanged("installTime",str(_time))
|
||||
elif mode == UU_UPGRADE_MODE_BEFORE_SHUTDOWN:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "installTime", "bshutdown"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "installMode", "bshutdown", True)
|
||||
self.PropertyChanged("installMode","bshutdown")
|
||||
elif mode == UU_UPGRADE_MODE_MANUAL:
|
||||
if not self.__check_change__(self.parent.uuconfigs, "autoUpgradePolicy", "downloadMode", "manual"):
|
||||
self.parent.uuconfigs.setValue("autoUpgradePolicy", "downloadMode", "manual", True)
|
||||
self.PropertyChanged("downloadMode","manual")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
# # dbus接口:改变apt下载速度
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='sb', out_signature='b',sender_keyword='sender')
|
||||
def SetDownloadspeedMax(self, speed, set,sender = None):
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' SetDownloadspeedMax, speed:%s, set:%r, sender name: %s .'%(speed, set, sender_name))
|
||||
#来重启Aptdeamon
|
||||
if set:
|
||||
with open("/etc/apt/apt.conf.d/80apt-download", "w+") as f:
|
||||
try:
|
||||
f.write("Acquire::http::Dl-Limit" + " \"" + "%s" % str(speed) + "\";\n")
|
||||
f.write("Acquire::https::Dl-Limit" + " \"" + "%s" % str(speed) + "\";\n")
|
||||
#更改数据库值
|
||||
self.parent.sqlite3_server.insert_into_display("download_limit","true")
|
||||
self.parent.sqlite3_server.insert_into_display("download_limit_value",str(speed))
|
||||
#发送信号
|
||||
self.ButtonStatusChange("speed" , str(speed))
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return False
|
||||
else:
|
||||
if os.path.exists("/etc/apt/apt.conf.d/80apt-download"):
|
||||
os.remove("/etc/apt/apt.conf.d/80apt-download")
|
||||
self.parent.sqlite3_server.insert_into_display("download_limit","false")
|
||||
self.ButtonStatusChange("speed", "0")
|
||||
return True
|
||||
else:
|
||||
self.parent.sqlite3_server.insert_into_display("download_limit","false")
|
||||
self.ButtonStatusChange("speed", "0")
|
||||
return True
|
||||
|
||||
# # dbus接口:获取apt下载速度
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, out_signature='bs',sender_keyword='sender')
|
||||
def GetDownloadspeedLimitValue(self,sender = None):
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' GetDownloadspeedLimitValue sender: %s .', sender_name)
|
||||
try:
|
||||
download_limit = self.parent.sqlite3_server.select_from_display("download_limit")
|
||||
if download_limit == "true":
|
||||
download_limit_value = self.parent.sqlite3_server.select_from_display("download_limit_value")
|
||||
return True,str(download_limit_value)
|
||||
else:
|
||||
return False,str("0")
|
||||
except:
|
||||
return False, "0"
|
||||
|
||||
# 是否允许关机前更新
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='ss', out_signature='bs', sender_keyword='sender')
|
||||
def UnattendedUpgradeValue(self, operation, value="false", sender=None):
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' UnattendedUpgradeValue sender:%s ', sender_name)
|
||||
if operation.lower() != "get" and operation.lower() != "set":
|
||||
return False, 'Please input [\"set\", \"value\"] to set. \nor [\"get\"] to get whether updates are allowed before shutdown.'
|
||||
if operation == "set":
|
||||
try:
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' UnattendedUpgradeValue is going to %s [allow_unattended_upgrades_shutdown] value to %s.'%(operation,value))
|
||||
self.parent.sqlite3_server.insert_into_display("allow_unattended_upgrades_shutdown", value.lower())
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False,str(e)
|
||||
else:
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' UnattendedUpgradeValue is going to %s [allow_unattended_upgrades_shutdown] value.'%(operation))
|
||||
try:
|
||||
value = self.parent.sqlite3_server.select_from_display("allow_unattended_upgrades_shutdown")
|
||||
logging.info("[allow_unattended_upgrades_shutdown] value is %s."%(value))
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False,str(e)
|
||||
return True,"success"
|
||||
|
||||
# # 设置自动更新时间
|
||||
# @dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='s', out_signature='bs',sender_keyword='sender')
|
||||
# def SetAutoUpgradePeriod(self, period, sender = None):
|
||||
# sender_name = get_proc_from_dbus_name(sender)
|
||||
# logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' SetAutoUpgradePeriod will be set value %s, SetAutoUpgradePeriod sender: %s.'%(period, sender_name))
|
||||
# try:
|
||||
# self.parent.sqlite3_server.insert_into_display("update_period", period.lower())
|
||||
# except Exception as e:
|
||||
# logging.error(str(e))
|
||||
# return True,"success"
|
||||
|
||||
# 获取数据库值
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='bss', out_signature='s')
|
||||
def GetSetDatabaseInfo(self, gs, table, field):
|
||||
Text = 'NULL'
|
||||
try:
|
||||
if gs: #get
|
||||
if table == 'display':
|
||||
Text = self.parent.sqlite3_server.select_from_display(str(field))
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' GetDatabaseInfo Table:%s Field:%s Text:%s',table,field,Text)
|
||||
else: #set
|
||||
if table == 'display' and "=" in field:
|
||||
field, value = str(field).split("=")
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' SetDatabaseInfo Table:%s Field:%s', table, field)
|
||||
self.parent.sqlite3_server.insert_into_display(field, value)
|
||||
return "success"
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return Text
|
||||
return Text
|
||||
|
||||
## dbus接口: 发送立即更新的信号
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, out_signature='b')
|
||||
def AutoUpgradeAllNow(self):
|
||||
logging.info(COLORMETHOR_PREFIX+'method'+COLORLOG_SUFFIX+' AutoUpgradeAllNow ...')
|
||||
try:
|
||||
self.UpgradeAllNow()
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
# kill 进程
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE, in_signature='i', out_signature='b')
|
||||
def KillProcessSignal(self, pid):
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' KillProcessSignal is %d', pid)
|
||||
try:
|
||||
# 判断文件是否存在
|
||||
if (os.path.exists(RUN_UNATTENDED_UPGRADE)):
|
||||
os.kill(int(pid), 9)
|
||||
logging.info('%s has been killed', pid)
|
||||
else:
|
||||
logging.warning('%s is not exist.', RUN_UNATTENDED_UPGRADE)
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
#设置数据库配置信息
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,in_signature='ss',out_signature='b',sender_keyword='sender')
|
||||
def DatabaseInfoSet(self,field_name,field_value,sender=None):
|
||||
Status = False
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' SetDatabaseInfo,field_name:%s,field_value:%s,caller:%s .',\
|
||||
field_name,field_value,sender_name)
|
||||
Status = self.parent.sqlite3_server.insert_into_display(field_name,field_value)
|
||||
return bool(Status)
|
||||
|
||||
#数据库获取配置信息
|
||||
@dbus.service.method(UPDATER_DBUS_INTERFACE,in_signature='s',out_signature='s',sender_keyword='sender')
|
||||
def DatabaseInfoGet(self,field_name,sender=None):
|
||||
field_value = ''
|
||||
sender_name = get_proc_from_dbus_name(sender)
|
||||
logging.info(COLORMETHOR_PREFIX+'Method'+COLORLOG_SUFFIX+' GetDatabaseInfo field_name:%s caller:%s',field_name,sender_name)
|
||||
field_value = self.parent.sqlite3_server.select_from_display(str(field_name))
|
||||
logging.info("Get field_value:%s",field_value)
|
||||
return field_value
|
||||
|
||||
#限速修改信号
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='ss')
|
||||
def ButtonStatusChange(self, signal_types = '', value=''):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting"+ COLORLOG_SUFFIX + " ButtonStatusChange signal_types = %s, value = %s.",signal_types, value)
|
||||
|
||||
# dbus 信号:用于发送立即更新信号
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE)
|
||||
def UpgradeAllNow(self):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" UpgradeAllNow")
|
||||
|
||||
# dbus 信号:用于发送自动更新配置更改信号
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE)
|
||||
def ChangeUpgradePolicy(self):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" ChangeUpgradePolicy")
|
||||
|
||||
|
||||
#限速修改信号
|
||||
@dbus.service.signal(UPDATER_DBUS_INTERFACE,signature='ss')
|
||||
def ButtonStatusChange(self, signal_types = '', value=''):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting"+ COLORLOG_SUFFIX + " ButtonStatusChange signal_types = %s, value = %s.",signal_types, value)
|
||||
|
||||
|
||||
# signal:属性发生改变
|
||||
@dbus.service.signal(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
signature="ss")
|
||||
def PropertyChanged(self, property, value):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" PropertyChanged: ( %s, %s )" % (property, value))
|
||||
|
||||
# signal:属性发生改变
|
||||
@dbus.service.signal(dbus_interface=UPDATER_DBUS_INTERFACE,
|
||||
signature="ss")
|
||||
def StrategyChanged(self, property, value):
|
||||
logging.info(COLORLOG_PREFIX + "Emitting" + COLORLOG_SUFFIX +" StrategyChanged: ( %s, %s )" % (property, value))
|
||||
|
||||
# WRITABLE_PROPERTIES = ()
|
||||
|
||||
# # pylint: disable-msg=C0103,C0322
|
||||
# @dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
# signature="sa{sv}as")
|
||||
# def PropertiesChanged(self, interface, changed_properties,
|
||||
# invalidated_properties):
|
||||
# """The signal gets emitted if a property of the object's
|
||||
# interfaces changed.
|
||||
|
||||
# :param property: The name of the interface.
|
||||
# :param changed_properties: A dictrionary of changed
|
||||
# property/value pairs
|
||||
# :param invalidated_properties: An array of property names which
|
||||
# changed but the value isn't conveyed.
|
||||
|
||||
# :type interface: s
|
||||
# :type changed_properties: a{sv}
|
||||
# :type invalidated_properties: as
|
||||
# """
|
||||
# logging.info("Emitting PropertiesChanged: %s, %s, %s" %
|
||||
# (interface, changed_properties, invalidated_properties))
|
||||
|
||||
# # pylint: disable-msg=C0103,C0322
|
||||
# @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
|
||||
# in_signature='', out_signature='s',
|
||||
# path_keyword='object_path',
|
||||
# connection_keyword='connection')
|
||||
# def Introspect(self, object_path, connection):
|
||||
# # Inject the properties into the introspection xml data
|
||||
# data = dbus.service.Object.Introspect(self, object_path, connection)
|
||||
# xml = ElementTree.fromstring(data)
|
||||
# for iface in xml.findall("interface"):
|
||||
# props = self._get_properties(iface.attrib["name"])
|
||||
# for key, value in props.items():
|
||||
# attrib = {"name": key}
|
||||
# if key in self.WRITABLE_PROPERTIES:
|
||||
# attrib["access"] = "readwrite"
|
||||
# else:
|
||||
# attrib["access"] = "read"
|
||||
# if isinstance(value, dbus.String):
|
||||
# attrib["type"] = "s"
|
||||
# elif isinstance(value, dbus.UInt32):
|
||||
# attrib["type"] = "u"
|
||||
# elif isinstance(value, dbus.Int32):
|
||||
# attrib["type"] = "i"
|
||||
# elif isinstance(value, dbus.UInt64):
|
||||
# attrib["type"] = "t"
|
||||
# elif isinstance(value, dbus.Int64):
|
||||
# attrib["type"] = "x"
|
||||
# elif isinstance(value, dbus.Boolean):
|
||||
# attrib["type"] = "b"
|
||||
# elif isinstance(value, dbus.Struct):
|
||||
# attrib["type"] = "(%s)" % value.signature
|
||||
# elif isinstance(value, dbus.Dictionary):
|
||||
# attrib["type"] = "a{%s}" % value.signature
|
||||
# elif isinstance(value, dbus.Array):
|
||||
# attrib["type"] = "a%s" % value.signature
|
||||
# else:
|
||||
# raise Exception("Type %s of property %s isn't "
|
||||
# "convertable" % (type(value), key))
|
||||
# iface.append(ElementTree.Element("property", attrib))
|
||||
# new_data = ElementTree.tostring(xml, encoding="UTF-8")
|
||||
# return new_data
|
||||
|
||||
# # pylint: disable-msg=C0103,C0322
|
||||
# @dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
# in_signature="ssv", out_signature="",
|
||||
# sender_keyword="sender")
|
||||
# def Set(self, iface, name, value, sender):
|
||||
# """Set a property.
|
||||
|
||||
# Only the user who intiaited the transaction is
|
||||
# allowed to modify it.
|
||||
|
||||
# :param iface: The interface which provides the property.
|
||||
# :param name: The name of the property which should be modified.
|
||||
# :param value: The new value of the property.
|
||||
|
||||
# :type iface: s
|
||||
# :type name: s
|
||||
# :type value: v
|
||||
# """
|
||||
# logging.info("Set() was called: %s, %s" % (name, value))
|
||||
# return self._set_property(iface, name, value, sender)
|
||||
|
||||
# # pylint: disable-msg=C0103,C0322
|
||||
# @dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
# in_signature="s", out_signature="a{sv}")
|
||||
# def GetAll(self, iface):
|
||||
# """Get all available properties of the given interface."""
|
||||
# logging.info("GetAll() was called: %s" % iface)
|
||||
# return self._get_properties(iface)
|
||||
|
||||
# # pylint: disable-msg=C0103,C0322
|
||||
# @dbus.service.method(dbus.PROPERTIES_IFACE,
|
||||
# in_signature="ss", out_signature="v")
|
||||
# def Get(self, iface, property):
|
||||
# """Return the value of the given property provided by the given
|
||||
# interface.
|
||||
# """
|
||||
# logging.info("Get() was called: %s, %s" % (iface, property))
|
||||
# return self._get_properties(iface)[property]
|
|
@ -0,0 +1,342 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import gi
|
||||
import os,subprocess
|
||||
gi.require_version('OSTree', '1.0')
|
||||
from gi.repository import GLib, Gio, OSTree,GObject
|
||||
from SystemUpdater.Core.errors import *
|
||||
from SystemUpdater.Core.enums import *
|
||||
from gettext import gettext as _
|
||||
|
||||
RETRY_LIMIT = 3
|
||||
ORIGIN_REMOTE_NAME = "openkylin"
|
||||
|
||||
class BackendBaseOstree(GObject.GObject):
|
||||
__gsignals__ = {
|
||||
"transaction-done": (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
(GObject.TYPE_PYOBJECT,)),
|
||||
"download-info": (GObject.SIGNAL_RUN_FIRST,
|
||||
GObject.TYPE_NONE,
|
||||
( GObject.TYPE_INT,
|
||||
GObject.TYPE_INT,
|
||||
GObject.TYPE_INT,
|
||||
GObject.TYPE_INT
|
||||
))
|
||||
}
|
||||
|
||||
def __init__(self,parent,sysroot_path=None,osname=None):
|
||||
GObject.GObject.__init__(self)
|
||||
if sysroot_path:
|
||||
sysroot_path = Gio.File.new_for_path(sysroot_path)
|
||||
|
||||
self.sysroot = OSTree.Sysroot.new(sysroot_path)
|
||||
self.sysroot.set_mount_namespace_in_use()
|
||||
self.sysroot.initialize()
|
||||
self.sysroot.load()
|
||||
|
||||
booted_deployment = self.sysroot.get_booted_deployment()
|
||||
if booted_deployment:
|
||||
self.osname = booted_deployment.get_osname()
|
||||
else:
|
||||
self.osname = osname
|
||||
|
||||
self.merge_deployment = self.sysroot.get_merge_deployment(self.osname)
|
||||
if not self.merge_deployment:
|
||||
pass
|
||||
|
||||
self.origin = self.merge_deployment.get_origin()
|
||||
|
||||
self._async_progress = OSTree.AsyncProgress.new()
|
||||
self._async_progress.connect("changed",self._on_async_progress)
|
||||
|
||||
def run(self,trans):
|
||||
logging.info("Processing transaction")
|
||||
GLib.idle_add(self._run_transaction_idle,trans)
|
||||
|
||||
def _run_transaction_idle(self,trans):
|
||||
"""Run the transaction"""
|
||||
try:
|
||||
self._try_lock()
|
||||
self._run_transaction(self.sysroot,trans)
|
||||
except GLib.Error as error:
|
||||
logging.error(str(error))
|
||||
trans.exit = False
|
||||
self._make_error(error,trans)
|
||||
except UpdateBaseError as excep:
|
||||
trans.exit = False
|
||||
trans.error_code = excep.code
|
||||
except Exception as excep:
|
||||
logging.error(str(excep))
|
||||
trans.exit = False
|
||||
else:
|
||||
trans.exit = True
|
||||
|
||||
finally:
|
||||
self._try_unlock()
|
||||
self._async_progress.finish()
|
||||
logging.info("Finished transaction")
|
||||
|
||||
self._emit_transaction_done(trans)
|
||||
|
||||
return False
|
||||
|
||||
def _run_transaction(self,sysroot,trans):
|
||||
"""This method needs to be implemented by the backends."""
|
||||
pass
|
||||
# raise errors.TransactionFailed(enums.ERROR_NOT_SUPPORTED)
|
||||
|
||||
def _try_lock(self):
|
||||
ret,out_acquired = self.sysroot.try_lock()
|
||||
if not out_acquired:
|
||||
raise UpdateBaseError(ERROR_OTHER_PROGRESS_OCCUPATION)
|
||||
|
||||
def _try_unlock(self):
|
||||
self.sysroot.unlock()
|
||||
|
||||
def _emit_transaction_done(self,trans):
|
||||
"""Emit the transaction-done signal.
|
||||
|
||||
Keyword argument:
|
||||
trans -- the finished transaction
|
||||
"""
|
||||
# logging.debug("Emitting transaction-done: %d",)
|
||||
self.emit("transaction-done",trans)
|
||||
|
||||
def _on_async_progress(self,obj):
|
||||
start_time = obj.get_uint64("start-time")
|
||||
bytes_transferred = obj.get_uint64("bytes-transferred")
|
||||
|
||||
fetched = obj.get_uint("fetched")
|
||||
requested = obj.get_uint("requested")
|
||||
|
||||
# 下载速度
|
||||
elapsed_secs=(GLib.get_monotonic_time()-start_time)/GLib.USEC_PER_SEC
|
||||
bytes_sec = int(bytes_transferred / elapsed_secs)
|
||||
|
||||
if requested <= 2:
|
||||
return
|
||||
|
||||
self.emit("download-info",fetched,requested,bytes_transferred,bytes_sec)
|
||||
|
||||
def _make_error(self,error,trans):
|
||||
if error.code in (0,37):
|
||||
trans.error_code = ERROR_NETWORK_FAILED
|
||||
#取消
|
||||
elif error.code == 19:
|
||||
trans.cancellable.reset()
|
||||
trans.error_code = ERROR_CANCELLED
|
||||
elif error.code == 1:
|
||||
#Remote "kylin" not found (1)
|
||||
trans.exit = True
|
||||
trans.is_upgradable = False
|
||||
|
||||
class UpdateBackend(BackendBaseOstree):
|
||||
|
||||
def __init__(self,parent,sysroot_path=None,osname=None):
|
||||
"""Initialize a new AptWorker instance."""
|
||||
BackendBaseOstree.__init__(self,parent,sysroot_path,osname)
|
||||
|
||||
def _run_transaction(self, sysroot,trans):
|
||||
ostree_repo = sysroot.repo()
|
||||
from_revision = self.merge_deployment.get_csum()
|
||||
|
||||
refspec = self.origin.get_string("origin","refspec")
|
||||
ret,origin_remote,origin_ref = OSTree.parse_refspec(refspec)
|
||||
|
||||
if origin_remote == None:
|
||||
origin_remote = ORIGIN_REMOTE_NAME
|
||||
# raise UpdateBaseError(ERROR_ORIGIN_IS_NONE)
|
||||
|
||||
g_options = GLib.Variant("a{sv}",
|
||||
{ "refs":GLib.Variant("as",[origin_ref]),\
|
||||
"n-network-retries":GLib.Variant("u",RETRY_LIMIT),\
|
||||
"flags":GLib.Variant("i",OSTree.RepoPullFlags.COMMIT_ONLY),\
|
||||
# "timestamp-check":GLib.Variant("b",True),\
|
||||
"depth":GLib.Variant("i",1)
|
||||
})
|
||||
|
||||
logging.info("Start pull metadata refs:%s...",origin_ref)
|
||||
ret = ostree_repo.pull_with_options(origin_remote,g_options,self._async_progress,trans.cancellable)
|
||||
|
||||
origin_refspec = origin_remote+":"+origin_ref
|
||||
ret,new_revision = ostree_repo.resolve_rev(origin_refspec,True)
|
||||
new_ref = origin_ref
|
||||
|
||||
ret,metadata = ostree_repo.load_variant(OSTree.ObjectType.COMMIT,new_revision)
|
||||
|
||||
n_metadata = metadata[0]
|
||||
|
||||
# 检查是否当前分支已经终止,切换到新的分支
|
||||
if OSTree.COMMIT_META_KEY_ENDOFLIFE_REBASE in n_metadata:
|
||||
new_ref = n_metadata[OSTree.COMMIT_META_KEY_ENDOFLIFE_REBASE]
|
||||
# 拉取新分支的元数据
|
||||
g_options = GLib.Variant("a{sv}",
|
||||
{ "refs":GLib.Variant("as",[new_ref]),\
|
||||
"n-network-retries":GLib.Variant("u",RETRY_LIMIT),\
|
||||
"flags":GLib.Variant("i",OSTree.RepoPullFlags.COMMIT_ONLY),\
|
||||
# "timestamp-check":GLib.Variant("b",True),\
|
||||
"depth":GLib.Variant("i",1)
|
||||
})
|
||||
logging.info("From origin ref:%s To new refs:%s...",origin_ref,new_ref)
|
||||
logging.info("Start pull metadata refs:%s...",new_ref)
|
||||
ret = ostree_repo.pull_with_options(origin_remote,g_options,self._async_progress,trans.cancellable)
|
||||
|
||||
origin_refspec = origin_remote+":"+new_ref
|
||||
ret,new_revision = ostree_repo.resolve_rev(origin_refspec,True)
|
||||
|
||||
ret,metadata = ostree_repo.load_variant(OSTree.ObjectType.COMMIT,new_revision)
|
||||
|
||||
# 判断是否有新的更新
|
||||
trans.is_upgradable = from_revision != new_revision
|
||||
trans.available_checksum = new_revision
|
||||
trans.available_refs = new_ref
|
||||
trans.available_metadata = metadata[0]
|
||||
logging.info("Update available refs:%s from revision:%s to %s ",from_revision,new_revision,new_ref)
|
||||
|
||||
class DownloadBackend(BackendBaseOstree):
|
||||
def __init__(self,parent,sysroot_path=None,osname=None):
|
||||
"""Initialize a new AptWorker instance."""
|
||||
BackendBaseOstree.__init__(self,parent,sysroot_path,osname)
|
||||
|
||||
def _run_transaction(self, sysroot,trans):
|
||||
ostree_repo = sysroot.repo()
|
||||
refspec = self.origin.get_string("origin","refspec")
|
||||
ret,origin_remote,origin_ref = OSTree.parse_refspec(refspec)
|
||||
|
||||
if origin_remote == None:
|
||||
origin_remote = ORIGIN_REMOTE_NAME
|
||||
|
||||
g_options = GLib.Variant("a{sv}",
|
||||
{
|
||||
"refs":GLib.Variant("as",[trans.available_refs]),\
|
||||
"n-network-retries":GLib.Variant("u",RETRY_LIMIT),\
|
||||
# "timestamp-check":GLib.Variant("b",True),\
|
||||
# "low-speed-limit-bytes":GLib.Variant("u",10),\
|
||||
# "low-speed-limit-seconds":GLib.Variant("u",20),\
|
||||
"flags":GLib.Variant("i",OSTree.RepoPullFlags.NONE),\
|
||||
"depth":GLib.Variant("i",1)
|
||||
})
|
||||
|
||||
logging.info("start pull data from available_refs:%s...",trans.available_refs)
|
||||
ostree_repo.pull_with_options(origin_remote,g_options,self._async_progress,trans.cancellable)
|
||||
|
||||
# 下载完成后检查下载的元数据的时间戳
|
||||
# upgrader.check_timestamps(ostree_repo,from_revision,trans.available_checksum)
|
||||
|
||||
class DeployBackend(BackendBaseOstree):
|
||||
def __init__(self,parent,sysroot_path=None,osname=None):
|
||||
"""Initialize a new AptWorker instance."""
|
||||
BackendBaseOstree.__init__(self,parent,sysroot_path,osname)
|
||||
|
||||
def _deployment_sanitycheck_true(self,rootfs_path):
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
os.chroot(rootfs_path)
|
||||
os.chdir("/")
|
||||
# 执行命令
|
||||
result = subprocess.run(["/usr/bin/true"],capture_output=True, text=True)
|
||||
os._exit(result.returncode)
|
||||
else:
|
||||
# 等待子进程结束
|
||||
_, exit_code = os.waitpid(pid, 0)
|
||||
logging.info("Command exited with status: %d",os.WEXITSTATUS(exit_code))
|
||||
if os.WIFEXITED(exit_code) != 0:
|
||||
logging.error("Command did not exit normally.")
|
||||
except Exception as e:
|
||||
logging.error(str(e))
|
||||
|
||||
def _run_transaction(self, sysroot,trans):
|
||||
ostree_repo = sysroot.repo()
|
||||
upgrader = OSTree.SysrootUpgrader.new(sysroot)
|
||||
|
||||
# 当前合并部署
|
||||
refspec = self.origin.get_string("origin","refspec")
|
||||
ret,origin_remote,origin_ref = OSTree.parse_refspec(refspec)
|
||||
|
||||
#执行清理任何先前部分失败留下的数据。
|
||||
ret = sysroot.prepare_cleanup(None)
|
||||
|
||||
# 复现旧部署orgin文件 以及修改refspec
|
||||
origin_refspec = origin_remote+":"+trans.available_refs
|
||||
origin_cp = upgrader.dup_origin()
|
||||
origin_cp.set_string("origin","refspec",origin_refspec)
|
||||
|
||||
ret,new_revision = ostree_repo.resolve_rev(origin_refspec,True)
|
||||
|
||||
# 最终完成阶段在关机的时候
|
||||
logging.info("start deploy available_refs:%s new_revision:%s...",trans.available_refs,new_revision)
|
||||
ret,new_deployment = sysroot.stage_tree(None,new_revision,origin_cp,self.merge_deployment,None,None)
|
||||
|
||||
# 健全性检查
|
||||
# rootfs_path = sysroot.get_deployment_dirpath(new_deployment)
|
||||
# self._deployment_sanitycheck_true(rootfs_path)
|
||||
|
||||
ret,metadata = ostree_repo.load_variant(OSTree.ObjectType.COMMIT,new_revision)
|
||||
|
||||
trans.available_checksum = new_revision
|
||||
trans.available_metadata = metadata[0]
|
||||
|
||||
def _start_plymouth_splash(self):
|
||||
try:
|
||||
logging.info("Running plymouth --splash")
|
||||
if os.path.exists("/sbin/plymouthd"):
|
||||
subprocess.run(["/sbin/plymouthd", "--mode=boot","--attach-to-session"],timeout=1)
|
||||
if os.path.exists("/bin/plymouth"):
|
||||
subprocess.Popen(["/bin/plymouth", "show-splash","--wait"])
|
||||
subprocess.call(["/bin/plymouth","system-update","--progress=0"])
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
|
||||
def _check_plymouth_state(self):
|
||||
try:
|
||||
args = ["/bin/plymouth","--ping"]
|
||||
p = subprocess.run(args,timeout=2,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True)
|
||||
if p.returncode == 0:
|
||||
logging.info("Check: Plymouthd state start to success...")
|
||||
else:
|
||||
logging.info("Check: Plymouthd Failed to Boot and Restart boot up again...")
|
||||
self._start_plymouth_splash()
|
||||
except Exception as exc:
|
||||
logging.error(exc)
|
||||
|
||||
def _message_to_plymouth(self,message):
|
||||
subprocess.call(["/bin/plymouth", "message", "--text", message])
|
||||
|
||||
def _progress_to_plymouth(self,progress):
|
||||
tmp = ("--progress=%d"%progress)
|
||||
run_cmd = ["/bin/plymouth","system-update",tmp]
|
||||
subprocess.call(run_cmd)
|
||||
|
||||
class RollbackBackend(BackendBaseOstree):
|
||||
def __init__(self,parent,sysroot_path=None,osname=None):
|
||||
"""Initialize a new AptWorker instance."""
|
||||
BackendBaseOstree.__init__(self,parent,sysroot_path,osname)
|
||||
|
||||
def _run_transaction(self, sysroot,trans):
|
||||
new_deployments = []
|
||||
|
||||
out_pending,out_rollback = sysroot.query_deployments_for(self.osname)
|
||||
|
||||
if out_rollback == None:
|
||||
raise UpdateBaseError(ERROR_NOT_ROLLBAK_DEPLOYMENT)
|
||||
|
||||
rollback_csum = out_rollback.get_csum()
|
||||
|
||||
old_deployments = sysroot.get_deployments()
|
||||
|
||||
new_deployments.append(out_rollback)
|
||||
|
||||
# 部署的列表
|
||||
for deploys in old_deployments:
|
||||
if out_rollback.equal(deploys) != True:
|
||||
new_deployments.append(deploys)
|
||||
|
||||
logging.info("start reollback checksum:%s...",rollback_csum)
|
||||
ret = sysroot.write_deployments(new_deployments,None)
|
||||
|
||||
refspec = new_deployments.get_string("origin","refspec")
|
||||
ret,origin_remote,origin_ref = OSTree.parse_refspec(refspec)
|
||||
|
||||
trans.available_refs = origin_ref
|
|
@ -0,0 +1 @@
|
|||
Dir::Bin::Methods::ftp "ftp";
|
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC
|
||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
|
||||
<vendor>Kylin System Updater</vendor>
|
||||
<vendor_url>www.kylinos.cn</vendor_url>
|
||||
<icon_name>kylin-system-updater</icon_name>
|
||||
|
||||
<!--Kylin Installer Config-->
|
||||
<action id="cn.kylin.installer.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Installer
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="cn.kylin.uninstaller.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Uninstaller
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<!--Kylin System Updater Config-->
|
||||
<action id="cn.kylinos.KylinSystemUpdater.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Installer
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<!--Kylin Software Center Config-->
|
||||
<action id="cn.kylin.software.center.action">
|
||||
<_description>
|
||||
Configuration items added for Kylin Software Center
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<!--Kylin Installer Config-->
|
||||
<action id="cn.kylin.installer.self.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Installer
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_self_keep</allow_any>
|
||||
<allow_inactive>auth_self_keep</allow_inactive>
|
||||
<allow_active>auth_self_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="cn.kylin.uninstaller.self.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Uninstaller
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_self_keep</allow_any>
|
||||
<allow_inactive>auth_self_keep</allow_inactive>
|
||||
<allow_active>auth_self_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<!--Kylin System Updater Config-->
|
||||
<action id="cn.kylinos.KylinSystemUpdater.self.action">
|
||||
<_description>
|
||||
Configuration items added for Kirin Installer
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_self_keep</allow_any>
|
||||
<allow_inactive>auth_self_keep</allow_inactive>
|
||||
<allow_active>auth_self_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<!--Kylin Software Center Config-->
|
||||
<action id="cn.kylin.software.center.self.action">
|
||||
<_description>
|
||||
Configuration items added for Kylin Software Center
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_self_keep</allow_any>
|
||||
<allow_inactive>auth_self_keep</allow_inactive>
|
||||
<allow_active>auth_self_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC
|
||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
|
||||
<vendor>Kylin System Updater Config Manager</vendor>
|
||||
<vendor_url>www.kylinos.cn</vendor_url>
|
||||
<icon_name>kylin-upgrade-strategies</icon_name>
|
||||
|
||||
<action id="com.kylin.UpgradeStrategies.action">
|
||||
<_description>
|
||||
system level settings
|
||||
</_description>
|
||||
<_message>
|
||||
To Change the settings, you need to authenticate.
|
||||
</_message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<!-- Only root can own the service -->
|
||||
<policy user="root">
|
||||
<allow own="com.kylin.UpgradeStrategies"/>
|
||||
<allow send_interface="com.kylin.UpgradeStrategies.interface"/>
|
||||
</policy>
|
||||
|
||||
<!-- Allow anyone to invoke methods on the interfaces -->
|
||||
<policy context="default">
|
||||
<allow send_destination="com.kylin.UpgradeStrategies"
|
||||
send_interface="com.kylin.UpgradeStrategies.interface"/>
|
||||
<allow send_destination="com.kylin.UpgradeStrategies"
|
||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
||||
<allow send_destination="com.kylin.UpgradeStrategies"
|
||||
send_interface="org.freedesktop.DBus.Properties"/>
|
||||
|
||||
</policy>
|
||||
</busconfig>
|
|
@ -0,0 +1,4 @@
|
|||
[D-BUS Service]
|
||||
Name=com.kylin.UpgradeStrategies
|
||||
Exec=/usr/share/kylin-system-updater/kylin-upgrade-strategies
|
||||
User=root
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<!-- Only root can own the service -->
|
||||
<policy user="root">
|
||||
<allow own="com.kylin.systemupgrade"/>
|
||||
<allow send_interface="com.kylin.systemupgrade.interface"/>
|
||||
</policy>
|
||||
|
||||
<!-- Allow anyone to invoke methods on the interfaces -->
|
||||
<policy context="default">
|
||||
<allow send_destination="com.kylin.systemupgrade"
|
||||
send_interface="com.kylin.systemupgrade.interface"/>
|
||||
<allow send_destination="com.kylin.systemupgrade"
|
||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
||||
<allow send_destination="com.kylin.systemupgrade"
|
||||
send_interface="org.freedesktop.DBus.Properties"/>
|
||||
|
||||
</policy>
|
||||
</busconfig>
|
|
@ -0,0 +1,14 @@
|
|||
[whitelist]
|
||||
key1 = /usr/bin/kylin-background-upgrade
|
||||
key2 = /usr/bin/ukui-control-center
|
||||
key3 = /usr/bin/kylin-installer
|
||||
key4 = /usr/bin/kylin-uninstaller
|
||||
key5 = /usr/bin/kylin-software-properties-service
|
||||
key6 = /usr/bin/kylin-source-update
|
||||
key7 = /usr/bin/kylin-source-manager
|
||||
key8 = /usr/bin/kylin-unattended-upgrade
|
||||
key9 = /usr/bin/kylin-software-center
|
||||
key10 = /usr/bin/kylin-printer
|
||||
key11 = /usr/bin/kylin-printer-applet
|
||||
key12 = /usr/bin/hedron-client
|
||||
key13 = /usr/bin/kylin-software-center-plugin-synchrodata
|
|
@ -0,0 +1,25 @@
|
|||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Entries in this file show the compile time defaults.
|
||||
# You can change settings by editing this file.
|
||||
# Defaults can be restored by simply deleting this file.
|
||||
#
|
||||
# See systemd-sleep.conf(5) for details
|
||||
|
||||
[Sleep]
|
||||
AllowSuspend=no
|
||||
AllowHibernation=no
|
||||
#AllowSuspendThenHibernate=yes
|
||||
#AllowHybridSleep=yes
|
||||
#SuspendMode=
|
||||
#SuspendState=mem standby freeze
|
||||
#HibernateMode=platform shutdown
|
||||
#HibernateState=disk
|
||||
#HybridSleepMode=suspend platform shutdown
|
||||
#HybridSleepState=disk
|
||||
#HibernateDelaySec=180min
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
|
||||
# a) it breaks if its not available
|
||||
# b) the string we have here does not need it (because it has no vars)
|
||||
eval_gettext() {
|
||||
if [ -x /usr/bin/gettext ]; then
|
||||
echo $(gettext "$1")
|
||||
else
|
||||
echo "$1"
|
||||
fi
|
||||
}
|
||||
export TEXTDOMAIN=update-notifier
|
||||
export TEXTDOMAINDIR=/usr/share/locale
|
||||
|
||||
case "$DPKG_MAINTSCRIPT_PACKAGE::$DPKG_MAINTSCRIPT_NAME" in
|
||||
linux-image-extra*::postrm)
|
||||
exit 0;;
|
||||
esac
|
||||
|
||||
if [ "$0" = "/etc/kernel/postinst.d/update-notifier" ]; then
|
||||
DPKG_MAINTSCRIPT_PACKAGE=linux-base
|
||||
fi
|
||||
|
||||
# Wake the applet up
|
||||
echo "*** $(eval_gettext "System logout required") ***" > /var/run/logout-required
|
||||
echo "$DPKG_MAINTSCRIPT_PACKAGE" >> /var/run/logout-required.pkgs
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
|
||||
# a) it breaks if its not available
|
||||
# b) the string we have here does not need it (because it has no vars)
|
||||
eval_gettext() {
|
||||
if [ -x /usr/bin/gettext ]; then
|
||||
echo $(gettext "$1")
|
||||
else
|
||||
echo "$1"
|
||||
fi
|
||||
}
|
||||
export TEXTDOMAIN=update-notifier
|
||||
export TEXTDOMAINDIR=/usr/share/locale
|
||||
|
||||
case "$DPKG_MAINTSCRIPT_PACKAGE::$DPKG_MAINTSCRIPT_NAME" in
|
||||
linux-image-extra*::postrm)
|
||||
exit 0;;
|
||||
esac
|
||||
|
||||
if [ "$0" = "/etc/kernel/postinst.d/update-notifier" ]; then
|
||||
DPKG_MAINTSCRIPT_PACKAGE=linux-base
|
||||
fi
|
||||
|
||||
# Wake the applet up
|
||||
echo "*** $(eval_gettext "System restart required") ***" > /var/run/reboot-required
|
||||
echo "$DPKG_MAINTSCRIPT_PACKAGE" >> /var/run/reboot-required.pkgs
|
|
@ -0,0 +1,10 @@
|
|||
/var/log/kylin-system-updater/kylin-system-updater.log.1
|
||||
{
|
||||
weekly
|
||||
missingok
|
||||
rotate 3
|
||||
compress
|
||||
notifempty
|
||||
maxsize 10M
|
||||
copytruncate
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=kylin-system-updater dbus daemon
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
BusName=com.kylin.systemupgrade
|
||||
ExecStart=/usr/share/kylin-system-updater/kylin-system-updater
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,3 @@
|
|||
[SYSTEM]
|
||||
os_version =
|
||||
update_version =
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Do something before lightdm started.
|
||||
Conflicts=getty@tty7.service plymouth-quit.service
|
||||
Before=lightdm.service
|
||||
After=kylin-system-updater.service systemd-user-sessions.service getty@tty7.service plymouth-quit.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/share/kylin-system-updater/kylin-upgrade-poweroff
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,18 @@
|
|||
#此配置文件内的所有配置项,在重新安装时会被替换掉
|
||||
|
||||
[AutoUpgradeConfig]
|
||||
upgradeInterval = 7
|
||||
downloadRandom = 180
|
||||
|
||||
[TestsConfig]
|
||||
check_device_power = True
|
||||
force_dist_upgrade = False
|
||||
|
||||
[ShutdownInstall]
|
||||
# 包含的类型: "success":安装成功 "failed":安装失败 "none":不弹窗,默认状态
|
||||
finished_status = none
|
||||
|
||||
[main debian archive]
|
||||
Origin=Debian
|
||||
Label=Debian
|
||||
delta_uri=http://10.41.116.28
|
|
@ -0,0 +1,29 @@
|
|||
[SystemStatus]
|
||||
abnormal_reboot = False
|
||||
backend_restart = False
|
||||
frontend_restart = False
|
||||
source_restart = False
|
||||
upload_upgrade_log = True
|
||||
upload_installer_log = False
|
||||
[InstallMode]
|
||||
shutdown_install = False
|
||||
manual_install = False
|
||||
auto_install = False
|
||||
|
||||
#目前仅静默更新使用 安装状态存在在检查更新阶段被刷新的情况 在版本号发生变化时切换
|
||||
[LastUpdateInfo]
|
||||
finished_status = success
|
||||
update_version =
|
||||
update_content =
|
||||
|
||||
# 保存上次安装的状态:
|
||||
#1、在升级完成时刷新成功或者失败
|
||||
#2、在检查更新阶段 若推送内容不为空 检查不需要更新 判断为系统为最新 也刷新状态
|
||||
# last_install 字符串类型,"success":上次更新成功 非success时都认为失败例如 "#0202" 错误码
|
||||
[statusForProperties]
|
||||
last_install = success
|
||||
uuid =
|
||||
|
||||
# 前端使用配置文件
|
||||
[UpdateFrontendConf]
|
||||
backup_exist = False
|
|
@ -0,0 +1,44 @@
|
|||
[autoUpgradePolicy]
|
||||
#自动更新的开关
|
||||
autoUpgradeState = off
|
||||
|
||||
#预下载开关
|
||||
preDownload = off
|
||||
|
||||
# 预下载的时间为时间段 例如:10:00-11:00
|
||||
preDownloadTime = 09:00-10:00
|
||||
|
||||
#添加检查更新的周期 以天为单位
|
||||
updateDays = 30
|
||||
|
||||
# timing 为定时下载 manaual手动下载
|
||||
downloadMode = timing
|
||||
|
||||
# 下载的时间为时间段 例如:10:00-11:00
|
||||
downloadTime = 20:00-08:00
|
||||
|
||||
#安装存在定时timing 手动:manual 关机安装bshutdown
|
||||
installMode = bshutdown
|
||||
|
||||
#安装也为时间段 例如:00:00
|
||||
installTime = 08:00-20:00
|
||||
|
||||
#立即更新随机波动范围(单位:分钟)
|
||||
randomRange = 60
|
||||
|
||||
#是否开启自动重启 以及自动重启时间可以调节
|
||||
automaticReboot = off
|
||||
|
||||
#自动重启时间的调节 now为立即重启 重启时间调节 例如00:00
|
||||
automaticRebootTime = now
|
||||
|
||||
#更新前是否进行备份
|
||||
backupbeforeinstall = on
|
||||
|
||||
#下发的策略管控
|
||||
[updateStrategiesManager]
|
||||
# 策略的开关 False:关 True:开
|
||||
strategiesState = False
|
||||
|
||||
# 安装策略 default:默认模式 runtime:运行时安装 pre-poweroff:关机安装
|
||||
installType = default
|
|
@ -0,0 +1,4 @@
|
|||
[TimeStamp]
|
||||
predownload = 2023-7-1 00:00:00
|
||||
download = 2023-7-1 00:00:00
|
||||
install = 2023-7-1 00:00:00
|
|
@ -0,0 +1,657 @@
|
|||
## DBUS接口
|
||||
|
||||
[TOC]
|
||||
|
||||
|
||||
|
||||
### 对应版本信息
|
||||
|
||||
| 软件包 | 目前版本 | 备注 |
|
||||
| :------------------: | :-----------------------------: | :--: |
|
||||
| kylin-system-updater | kylin-system-updater 1.4.16kord | |
|
||||
| aptdaemon | 1.1.1+bzr982-0kylin32.3 | |
|
||||
| | | |
|
||||
|
||||
|
||||
|
||||
### 描述
|
||||
|
||||
实现系统升级以python apt库和aptdeamon的形式
|
||||
|
||||
|
||||
|
||||
### Dbus接口信息
|
||||
|
||||
| 名称 | 含义 |
|
||||
| -------------- | --------------------------------- |
|
||||
| BUS类型 | SYSTEM BUS |
|
||||
| DBUS名称 | com.kylin.systemupgrade |
|
||||
| OBJECT路径 | /com/kylin/systemupgrade |
|
||||
| INTERFACES名称 | com.kylin.systemupgrade.interface |
|
||||
| 属性名称 | org.freedesktop.DBus.Properties |
|
||||
|
||||
|
||||
|
||||
### Apt-p2p配置项设置
|
||||
|
||||
### Dbus接口信息
|
||||
|
||||
| 名称 | 含义 |
|
||||
| -------------- | --------------------------------- |
|
||||
| BUS类型 | SYSTEM BUS |
|
||||
| DBUS名称 | com.kylin.systemupgrade |
|
||||
| OBJECT路径 | /com/kylin/systemupgrade |
|
||||
| INTERFACES名称 | com.kylin.systemupgrade.interface |
|
||||
| 属性名称 | org.freedesktop.DBus.Properties |
|
||||
|
||||
|
||||
|
||||
#### Get
|
||||
|
||||
- `简介:`获取属性的值
|
||||
|
||||
- `入参:` `s`iface:要设置的属性的接口, `s`property:要设置的属性名称
|
||||
|
||||
- `出参:` `Variant`变量
|
||||
|
||||
- `示例:`
|
||||
|
||||
```
|
||||
#获取p2p的配置
|
||||
|
||||
Get(com.kylin.systemupgrade.interface,P2pBootstrap)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Set
|
||||
|
||||
- `简介:`设置属性的值
|
||||
|
||||
- `入参:` `s`iiface:要设置的属性的接口, `s`iproperty:要设置的属性名称 `Variant`value:要设置的值
|
||||
|
||||
- `出参:`
|
||||
|
||||
- `示例:`
|
||||
|
||||
```
|
||||
#设置p2p的配置
|
||||
|
||||
set("com.kylin.systemupgrade.interface","P2pBootstrap",GLib.Variant('s', "test"))
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 方法列表
|
||||
|
||||
| Method Name | Input Args | Output Args | means | 异步任务 |
|
||||
| ------------------ | ---------- | ----------- | --------------------------------- | ------------------ |
|
||||
| UpdateDetect | 无 | b | 更新cache,产生组升级列表JSON文件 | |
|
||||
| DistUpgradeAll | b | b | 全部升级 | |
|
||||
| DistUpgradePartial | b,as | b | 部分升级 | |
|
||||
| DistUpgradeSystem | b | b | 全盘升级 | |
|
||||
| CancelDownload | 无 | b | 取消升级 | |
|
||||
| InsertInstallState | ss | b | 向display表插入数据 | |
|
||||
| GtDownloadspeedLimitValue | 无 | b | 获取当前限速 | |
|
||||
| SetDownloadspeedMax | sb | b | 设置限速 | |
|
||||
| GetBackendStatus | 无 | i | 控制获取后端状态 | |
|
||||
| UnattendedUpgradeValue | ss | bs | 获取是否允许关机前更新 | |
|
||||
| PurgePackages | as | b | 卸载软件包 | |
|
||||
| InstalldebFile | ssbb | b | 安装本地deb包 | |
|
||||
| DataBackendCollect | ss | b | | |
|
||||
| CheckRebootRequired | s | b | 检查是否需要重启的方法,以及弹窗提示 | |
|
||||
|
||||
|
||||
### Method分析
|
||||
|
||||
#### UpdateDetect
|
||||
|
||||
- `简介:`更新cache对象,完成从之后拿到系统中所有可升级的包再经过源过滤、白名单等等的过滤,最后输出当前`可升级的包以及分组(JSON配置 输出目录: /var/lib/kylin-system-updater)
|
||||
|
||||
- `入参:`无
|
||||
- `出参:`True or False 注意:不通过返回值来判断有没有执行成功 通过下面的信号
|
||||
- `对应信号:`
|
||||
- `UpdateDetectStatusChanged:` 更新的进度信息和状态信息
|
||||
- `UpdateDetectFinished:`更新的完成的信号
|
||||
|
||||
|
||||
|
||||
#### DistUpgradePartial
|
||||
|
||||
- `简介:` 升级部分软件包或者分组
|
||||
|
||||
- `入参:` `b:` False模式:只进行获取升级列表以及计算修复依赖关系,以及计算是否存在删除的包,`True模式:`直接进行安装的操作 注意:必须选使用False模式获取升级列表以及计算依赖关系再进行True模式
|
||||
|
||||
`as:` 输入需要升级或者安装的分组 例如 升级系统组:["kylin-update-desktop-system"]
|
||||
|
||||
- `出参:`True or False 注意:不通过返回值来判断有没有执行成功 通过下面的信号
|
||||
|
||||
- `对应信号:`
|
||||
|
||||
- `UpdateDependResloveStatus:` 升级计算依赖修复反馈信号
|
||||
- `UpdateDloadAndInstStaChanged:`升级安装过程的进度信号以及状态
|
||||
- `UpdateInstallFinished:` 升级安装完成的信号
|
||||
|
||||
|
||||
|
||||
#### DistUpgradeAll
|
||||
|
||||
- `简介:`升级全部可升级的分组
|
||||
|
||||
- `入参:` `b:` False模式:只进行获取升级列表以及计算修复依赖关系,以及计算是否存在删除的包,`True模式:`直接进行安装的操作 注意:必须选使用False模式获取升级列表以及计算依赖关系再进行True模式
|
||||
- `出参:`True or False 注意:不通过返回值来判断有没有执行成功 通过下面的信号
|
||||
- `对应信号:`
|
||||
- `UpdateDependResloveStatus:` 升级计算依赖修复反馈信号
|
||||
- `UpdateDloadAndInstStaChanged:`升级安装过程的进度信号以及状态
|
||||
- `UpdateInstallFinished:` 升级安装完成的信号
|
||||
|
||||
|
||||
|
||||
|
||||
#### UpdateDownloadInfo
|
||||
|
||||
- `介绍:` 发送下载包信息信号
|
||||
|
||||
- `出参`: `i:`当前正在下载的项,`i:`所有下载的项,`i:`当前下载的字节,`i:`总的需要下载的字节,`i:`下载速度
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
current_items = 1, total_items = 1, currenty_bytes = 45 kB, total_bytes = 45 kB, current_cps = 0 kB/s
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### GetBackendStatus
|
||||
|
||||
- `介绍:` 获取后端的状态,现在正在处理那些任务
|
||||
|
||||
- `入参:` `s:`当前用户的语言变量 例如传入语言环境变量`LANG` 的值`zh_CN.UTF-8` 就会将升级的语言切换为中文 同理其他也能相应设置
|
||||
|
||||
- `出参`: `i:`当前任务ID,整型数字
|
||||
|
||||
- `状态示例列表:`
|
||||
|
||||
```python
|
||||
ACTION_DEFUALT_STATUS = -1 #默认状态空闲状态
|
||||
ACTION_UPDATE = 0 #处于更新cache状态
|
||||
ACTION_INSTALL = 1 #包括部分升级、全部升级、q
|
||||
ACTION_INSTALL_DEB = 2 #处于安装deb的状态
|
||||
ACTION_CHECK_RESOLVER = 3 #处于计算依赖过程
|
||||
ACTION_DOWNLOADONLY = 4 #单独下载软件包过程
|
||||
ACTION_FIX_BROKEN = 5 #修复依赖的过程
|
||||
ACTION_REMOVE_PACKAGES = 6 #卸载包的状态中
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### UnattendedUpgradeValue
|
||||
|
||||
- `介绍:` 设置或获取是否允许关机前更新
|
||||
|
||||
- `入参`: `s:`operation("get"/"set"),`s:`value将要设置的值
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
operation = "set", value = "false"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### InstalldebFile
|
||||
|
||||
- `简介:`安装本地deb包
|
||||
|
||||
- `入参:` `source:(string)` 安装来源,`path:(string)`本地deb包绝对路径,`_check_local_dep:(bool)`出现依赖问题时是否查询本路径下是否存在满足的包,`_auto_satisfy:(bool)`出现依赖问题时是否通过网络下载并安装依赖包
|
||||
- `出参:`True or False
|
||||
- `对应信号:`
|
||||
- `InstalldebStatusChanged`:安装过程的进度信号以及状态
|
||||
- `InstalldebFinished`:安装完成的信号
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
source = 'kylin-installer', path = '/home/kylin/kylin-video_3.1.0-94.5_amd64.deb', _check_local_dep = 0, _auto_satisfy = 1
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### PurgePackages
|
||||
|
||||
- `简介:`卸载系统中的软件包
|
||||
|
||||
- `入参:` `as:` 需要卸载的包列表 `s:`当前用户的用户名 例如:kylin用户就传入`kylin`字符串
|
||||
|
||||
- `出参:`True or False 出参值不做任何参考意义 `注意:`其中False的时候表示后端正在处理其他任务会报错,其中完成信号也会反馈结果,故不采用方法的返回值来判断错误类型
|
||||
|
||||
- `对应信号:`
|
||||
|
||||
- `PurgePkgStatusChanged:`卸载过程的进度信号以及状态
|
||||
- `PurgePackagesFinished:` 卸载完成的信号
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
_purge_list = ['kylin-video','tree'] cur_user = 'kylin'
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### DataBackendCollect
|
||||
|
||||
- `介绍:` 后端数据采集
|
||||
|
||||
- `入参`: `messageType: ` 消息埋点(string), `uploadMessage: ` 上传数据(json格式字符串),必须包含的字段: "packageName"
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
messageType = "UpdateInfos", uploadMessage = "{\"packageName\":\"kylin-system-updater\",\"source\":\"kylin-system-updater\",\"status\":\"True\",\"errorCode\":\"\",\"versionOld\":\"1.2.13.2kord\",\"versionNew\":\"1.2.17.1kord\"}"
|
||||
|
||||
messageType: 消息埋点(string) "UpdateInfos"、"InstallInfos"、"RemoveInfos"...
|
||||
source: 安装来源 "kylin-installer"、"unattented-upgrade"、"kylin-software-center"、"kylin-system-updater"...
|
||||
status: 安装或卸载状态 "True"/"False"
|
||||
errorCode: 错误信息 ""/"..."
|
||||
versionOld: 旧版本号 "1.2.13.2kord"
|
||||
versionNew: 新版本号 "1.2.17.1kord"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### CheckRebootRequired
|
||||
|
||||
- `介绍:` 检查是否需要重启的方法,以及弹窗提示
|
||||
- `入参`: `s:`标识那个应用调的此接口(如自动更新可填入字符串“autoyupgrade”)
|
||||
- `出参:`True or False 执行的结果
|
||||
|
||||
|
||||
|
||||
#### SetConfigValue
|
||||
|
||||
- `简介:`设置配置文件的值 配置文件的目录`/var/lib/kylin-system-updater/system-updater.conf`
|
||||
|
||||
- `入参:` `section`, `option`,` value` 不管布尔、列表的数据类型都转化成字符串类型来写入
|
||||
|
||||
- 例如传入"InstallModel","shutdown_install","False"
|
||||
|
||||
```
|
||||
[InstallMode]
|
||||
shutdown_install = True
|
||||
manual_install = False
|
||||
auto_install = False
|
||||
pkgs_install =
|
||||
pkgs_upgrade =
|
||||
pkgs_remove =
|
||||
```
|
||||
|
||||
- `出参:`True :设置值成功 False: 设置失败
|
||||
|
||||
#### GetConfigValue
|
||||
|
||||
- `简介:`获取配置文件的值 配置文件的目录`/var/lib/kylin-system-updater/system-updater.conf`
|
||||
|
||||
- `入参:` `section`,` option` 例如传入"InstallModel","shutdown_install"
|
||||
|
||||
- `出参:` `bool:`True :获取值成功 False: 获取失败 `Value:`值都以字符串类型来返回
|
||||
|
||||
```
|
||||
[InstallMode]
|
||||
shutdown_install = True
|
||||
manual_install = False
|
||||
auto_install = False
|
||||
pkgs_install =
|
||||
pkgs_upgrade =
|
||||
pkgs_remove =
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### CheckInstallRequired
|
||||
|
||||
- `简介:`检查当前系统是否需要关机安装或者重启安装
|
||||
- `入参:` 无
|
||||
- `出参:` `int:` 类型返回值 表示当前系统是否需要安装 返回值数值含义如下。简要为0时不需要安装,不为零时需要进行提示安装
|
||||
- `1` 手动更新请求当前系统在关机时进行安装软件包
|
||||
- `2` 自动更新请求当前系统在关机时进行安装软件包
|
||||
- `0` 当前系统不需要进行安装
|
||||
|
||||
|
||||
|
||||
#### FixBrokenDepends
|
||||
|
||||
- `简介:` 修复当前的系统Apt环境,收到`UpdateFixBrokenStatus`后进行调用,类似于调用apt install -f 来进行修复
|
||||
- `入参:` 无
|
||||
- `出参:` True or False 执行的结果 无实际意义
|
||||
- `对应信号:`
|
||||
- `FixBrokenStatusChanged:` 修复依赖的状态信号 可不使用
|
||||
|
||||
|
||||
|
||||
#### MountSquashfsSource
|
||||
|
||||
- `简介:` 挂载离线源squashfs
|
||||
- `入参:` `s:` 挂载文件的位置
|
||||
- `出参:` `b:` True or False 执行的结果,`s:` 字符类型错误信息描述
|
||||
|
||||
|
||||
|
||||
### Signal列表
|
||||
|
||||
| Signal Name | Output Args | means |
|
||||
| ---------------------------- | ----------- | ------------------------ |
|
||||
| UpdateDetectStatusChanged | i,s | 更新进度信息以及状态信息 |
|
||||
| UpdateDetectFinished | b,as,s,s | 更新完成信号 |
|
||||
| UpdateDloadAndInstStaChanged | as,i,s,s | 升级的进度信号以及状态 |
|
||||
| UpdateInstallFinished | b,as,s,s | 升级完成的信号 |
|
||||
| UpdateDownloadInfo | i,i,u,u,i | 发送下载包信息信号 |
|
||||
| UpdateDependResloveStatus | b,b,s | 更新依赖修复信息 |
|
||||
| DistupgradeDependResloveStatus | b,s | 更新全盘修复信息 |
|
||||
| Cancelable | b | 是否可取消 |
|
||||
| UpdateSqlitSingle | | |
|
||||
| FixBrokenStatusChanged | iiisss | 修复依赖的状态信号 |
|
||||
| PurgePackagesFinished | iss | 卸载完成信号 |
|
||||
| PurgePkgStatusChanged | bss | 卸载进度信息以及状态信息 |
|
||||
| RebootLogoutRequired | s | 请求重启或者注销的信号 |
|
||||
| UpdateInstallFinished | b,as,s,s | 下载完成的信号 |
|
||||
|
||||
|
||||
|
||||
### Signal分析
|
||||
|
||||
#### UpdateDetectStatusChanged
|
||||
|
||||
- `介绍:`更新的进度信息和状态信息
|
||||
|
||||
- `出参`:`i:`更新的进度信息从0-100%,`s:`更新的状态信息,
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
progress = 9 , status = 正在解决依赖关系
|
||||
progress = 92 , status = 正在载入软件列表
|
||||
progress = 92 , status = 完成
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### UpdateDetectFinished
|
||||
|
||||
- `介绍:`更新的完成的信号
|
||||
|
||||
- `出参`: `b:`更新是否成功,`as:`可升级的组列表,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
success = True , upgrade_group = ['kylin-update-desktop-system', 'tree', 'texinfo', 'kylin-update-manager', 'dnsmasq-base', 'vino', 'dpkg-dev', 'ghostscript', 'atril', 'wpasupplicant', 'eom', 'eom-common', 'fcitx-bin', 'fcitx-data', 'fcitx-frontend-gtk2', 'wps-office'], error_string = , error_desc =
|
||||
|
||||
error_string = 获取更新软件推送失败,请稍后再进行尝试更新 , error_desc = 推送服务器连接异常
|
||||
|
||||
```
|
||||
|
||||
#### UpdateDependResloveStatus
|
||||
|
||||
- `介绍:`升级计算依赖修复反馈信号
|
||||
|
||||
- `出参`: `b:`修复依赖关系是否成功,`b:`是否存在升级需要卸载的包,`as:`卸载的包列表,`as:`卸载的包的描述信息,`as:`卸载此包的原因 升级安装那些包导致的,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
UpdateDependResloveStatus:resolver_status = True , remove_status = True , remove_pkgs = ['kylin-burner-i18n'],pkg_raw_description = ['Sophisticated CD/DVD burning application - localizations files'] ,delete_desc = ['kylin-burner-i18n 将要被删除,由于升级 kylin-burner'],error_string = , error_desc =
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### UpdateFixBrokenStatus
|
||||
|
||||
- `介绍:`更新检查过程中是否需要修复系统Apt的环境,提示是否存在卸载软件包的情况
|
||||
|
||||
- `出参`: `b:`是否能修复系统环境,`b:`是否存在修复需要卸载的包,`as:`卸载的包列表,`as:`卸载的包的描述信息,`as:`卸载此包的原因,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
UpdateDependResloveStatus:resolver_status = True , remove_status = True , remove_pkgs = ['kylin-burner-i18n'],pkg_raw_description = ['Sophisticated CD/DVD burning application - localizations files'] ,delete_desc = ['kylin-burner-i18n 将要被删除,由于升级 kylin-burner'],error_string = , error_desc =
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### UpdateDloadAndInstStaChanged
|
||||
|
||||
- `介绍:` 升级安装过程的进度信号以及状态
|
||||
|
||||
- `出参`: `as:`当前那些组在升级安装 `i:`更新的进度信息从0-100%,`s:`更新的状态信息 `s:`下载的细节信息
|
||||
|
||||
- ` 示例:`
|
||||
|
||||
```sh
|
||||
groups_list = ['kylin-update-desktop-system'] progress = 15 , status = 下载中 current_details = 下载中 tree
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### UpdateInstallFinished
|
||||
|
||||
- `介绍:` 升级安装完成的信号
|
||||
|
||||
- `出参`: `b:`升级是否成功,`as:`可升级的组列表,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
pdateInstallFinished success = True , upgrade_group = ['tree'], error_string = 系统升级完成。 , error_desc =
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### UpdateDownloadFinished
|
||||
|
||||
- `介绍:` 下载完成的信号
|
||||
|
||||
- `出参`: `b:`下载是否成功,`as:`可升级的组列表,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
pdateInstallFinished success = True , upgrade_group = ['tree'], error_string = 系统升级完成。 , error_desc =
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### FixBrokenStatusChanged
|
||||
|
||||
- `介绍:` 修复依赖过程中的状态反馈信号
|
||||
|
||||
- `出参`: `i:`修复依赖是否完成 `i:`修复依赖过程是否成功`注意:只有修复完成时,修复依赖是否成功才有意义`,`i:`修复的进度信息 `s:`修复的状态信息 `s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- ` 示例:`
|
||||
|
||||
```sh
|
||||
emit FixBrokenStatusChanged finished = False , success = True,progress = 66 , status = 正在应用更改,error_string = , error_desc =
|
||||
```
|
||||
|
||||
-
|
||||
|
||||
|
||||
|
||||
#### PurgePkgStatusChanged
|
||||
|
||||
- `介绍:`卸载的进度信息和状态信息以及状态的细节信息
|
||||
|
||||
- `出参`:`i:`卸载的进度信息从0-100%,`s:`卸载的状态信息,`s:`卸载的细节信息
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
INFO:emit PurgePkgStatusChanged progress = 63 , status = 正在应用更改 ,current_details = 正在准备删除 kylin-video
|
||||
INFO:emit PurgePkgStatusChanged progress = 76 , status = 正在应用更改 ,current_details = 正在卸载 kylin-video
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### PurgePackagesFinished
|
||||
|
||||
- `介绍:`卸载的完成的信号
|
||||
|
||||
- `出参`: `b:`卸载是否成功,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
#卸载完成
|
||||
PurgePackagesFinished success = True , error_string = 卸载完成。 , error_desc =
|
||||
|
||||
#卸载失败
|
||||
PurgePackagesFinished success = False , error_string = 软件包不存在 , error_desc = 检查包名的拼写是否正确,以及是否启用了相应的仓库。
|
||||
PurgePackagesFinished success = False , error_string = 软件包没有安装 , error_desc = 不需要进行卸载。
|
||||
|
||||
#卸载失败 由于正在处理其他任务也同样会报错
|
||||
PurgePackagesFinished success = False , error_string = 其他任务正在更新升级中,请稍后再卸载。 , error_desc =
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### InstalldebStatusChanged
|
||||
|
||||
- `介绍:`安装的进度信息和状态信息以及状态的细节信息
|
||||
|
||||
- `出参`:`i:`安装的进度信息从0-100%,`s:`安装的状态信息,`s:`安装的细节信息
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
InstalldebStatusChanged progress = 57 , status = 正在应用更改 ,current_details = 正在配置 python3-bandit
|
||||
InstalldebStatusChanged progress = 57 , status = 正在应用更改 ,current_details = python3-bandit 已安装
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### InstalldebFinished
|
||||
|
||||
- `介绍:`安装的完成的信号
|
||||
|
||||
- `出参`: `b:`安装是否成功,`s:`产生错误的结果,`s:`产生错误的原因
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
#安装完成
|
||||
InstalldebFinished success = True , error_string = , error_desc =
|
||||
|
||||
#安装失败 缺少依赖的
|
||||
InstalldebFinished success = False , error_string = bandit dependency is not satisfied , error_desc = python3-bandit
|
||||
|
||||
#安装失败 选择从网络拉依赖 网络断开 报网络错误
|
||||
InstalldebFinished success = False , error_string = 下载软件包文件失败 , error_desc = 检查您的网络连接。
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### RebootLogoutRequired
|
||||
|
||||
- `介绍:`请求重启和注销的信号
|
||||
|
||||
- `出参`: `s:` "reboot" 表示重启 "logout"表示注销
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
Emitting RebootLogoutRequired required_status = reboot
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### InstallDetectStatus
|
||||
|
||||
- `介绍:`下载安装前的状态检查
|
||||
|
||||
- `出参`: `b:`检查出错时为`False`,没有错误`success`,`s:`产生错误的码
|
||||
|
||||
- 错误码示例:
|
||||
|
||||
```python
|
||||
ERROR_NOT_DISK_SPACE = "error-not-disk-space"
|
||||
```
|
||||
|
||||
- `示例:`
|
||||
|
||||
```sh
|
||||
#表示出现磁盘已满的错误z
|
||||
InstallDetectStatus success = False , error_code = "error-not-disk-space"
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
后端日志:`/var/log/kylin-system-updater/kylin-system-updater.log.1`
|
||||
|
||||
### 更新过程报错信息总结
|
||||
|
||||
| 错误信息 | 错误原因 | 解决办法 |
|
||||
| -------------------- | ------------------------------------------------------------ | ---------------------------------------- |
|
||||
| 下载软件仓库信息失败 | 源存在问题,使用apt update检查,若存在报错则更新管理器无问题 | 检查源是否可以使用 |
|
||||
| 无法访问源管理服务器 | 源管理服务器存在问题 | 源管理服务器是否可用或者检查源服务器配置 |
|
||||
| 软件索引已经损坏 | 当前系统中cache被破坏,apt无法使用 | 终端检查错误原因进行解决 |
|
||||
| 无法初始化软件包信息 | apt存在某些问题 | 具体错误原因查看日志相应解决 |
|
||||
| 无法获取组配置软件包 | 源中不存在kylin-update-desktop-config | 将此包放入源仓库或者写配置文件不强制安装 |
|
||||
| 无法读取推送升级列表 | 读取推送列表出现问题 | 检查important.list是否存在 |
|
||||
| 获取软件推送失败 | 老版本文案同 无法访问源管理服务器解决 | |
|
||||
|
||||
|
||||
|
||||
### 安装过程报错信息总结
|
||||
|
||||
| 错误信息 | 错误原因 | 解决办法 |
|
||||
| ------------------ | ------------------------------ | ---------------------------------- |
|
||||
| 软件包操作失败 | 被升级的软件包有问题 | 检查后端log日志查看那个包存在问题 |
|
||||
| 下载软件包文件失败 | 网络原因的或者这个软件包的仓库 | 检查网络以及源仓库 |
|
||||
| 磁盘空间不足 | 磁盘的空间不足 | 查看日志那些目录空间不足 |
|
||||
| 不能计算升级 | 无法计算依赖关系 | 检查日志那个包出现的问题,相应解决 |
|
||||
| | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from SystemUpdater.UpdateManager import UpdateManager
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import dbus
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import gettext
|
||||
|
||||
from SystemUpdater.Core.LogManager import get_logfile as logfile
|
||||
|
||||
gettext.bindtextdomain('kylin-system-updater', '/usr/share/locale')
|
||||
gettext.textdomain('kylin-system-updater')
|
||||
_ = gettext.gettext
|
||||
|
||||
#定义日志的格式
|
||||
FORMAT = "%(asctime)s [%(levelname)s]: %(message)s"
|
||||
|
||||
FORMAT_DEBUG = '%(asctime)-15s %(levelname)s(%(filename)s:%(lineno)d):%(message)s'
|
||||
|
||||
def signal_handler_term(signal, frame):
|
||||
# type: (int, object) -> None
|
||||
logging.warning("SIGTERM received, will stop")
|
||||
app.dbus_send.Quit(None)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Begin parsing of options
|
||||
parser = OptionParser()
|
||||
parser.add_option ("-d", "--debug", action="store_true", default=False,
|
||||
help=_("Show debug messages"))
|
||||
parser.add_option("-r", "--replace",
|
||||
default=False,
|
||||
action="store_true", dest="replace",
|
||||
help=_("Quit and replace an already running "
|
||||
"daemon"))
|
||||
parser.add_option("", "--sysroot", default=None,
|
||||
action="store", type="string", dest="sysroot",
|
||||
help=_("Import sysroot path in the given path"))
|
||||
parser.add_option("", "--os", default=None,
|
||||
action="store", type="string", dest="os",
|
||||
help=_("Import os name in the given string"))
|
||||
parser.add_option("-p", "--prohibit-shutdown",
|
||||
default=False,
|
||||
action="store_true", dest="prohibit_shutdown",
|
||||
help=_("close auto shutdown"))
|
||||
parser.add_option("--no-check-network",
|
||||
default=True,
|
||||
action="store_false", dest="check_network",
|
||||
help=_("Quit and close check network"))
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if os.getuid() != 0:
|
||||
print(_("You need to be root to run this application"))
|
||||
sys.exit(1)
|
||||
|
||||
# ensure that we are not killed when the terminal goes away e.g. on
|
||||
# shutdown
|
||||
signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
||||
signal.signal(signal.SIGINT,signal_handler_term)
|
||||
|
||||
if options.debug:
|
||||
logging.basicConfig(format=FORMAT,level=logging.INFO,datefmt='%m-%d,%H:%M:%S')
|
||||
else:
|
||||
logging.basicConfig(format=FORMAT,level=logging.INFO,datefmt='%m-%d,%H:%M:%S',filename = logfile(),filemode = 'a')
|
||||
|
||||
logging.info('kylin-system-updater starting ...')
|
||||
|
||||
app = UpdateManager(options)
|
||||
|
||||
app.run()
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from SystemUpdater.UpgradeStrategies import UpgradeStrategies
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import dbus
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import gettext
|
||||
|
||||
from SystemUpdater.Core.LogManager import upgrade_strategies_logfile as logfile
|
||||
|
||||
gettext.bindtextdomain('kylin-system-updater', '/usr/share/locale')
|
||||
gettext.textdomain('kylin-system-updater')
|
||||
_ = gettext.gettext
|
||||
|
||||
#定义日志的格式
|
||||
FORMAT = "%(asctime)s [%(levelname)s]: %(message)s"
|
||||
|
||||
FORMAT_DEBUG = '%(asctime)-15s %(levelname)s(%(filename)s:%(lineno)d):%(message)s'
|
||||
|
||||
def signal_handler_term(signal, frame):
|
||||
# type: (int, object) -> None
|
||||
logging.warning("SIGTERM received, will stop")
|
||||
app.dbusController.Quit(None)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Begin parsing of options
|
||||
parser = OptionParser()
|
||||
parser.add_option ("-d", "--debug", action="store_true", default=False,
|
||||
help=_("Show debug messages"))
|
||||
parser.add_option("-r", "--replace",
|
||||
default=False,
|
||||
action="store_true", dest="replace",
|
||||
help=_("Quit and replace an already running "
|
||||
"daemon"))
|
||||
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if os.getuid() != 0:
|
||||
print(_("You need to be root to run this application"))
|
||||
sys.exit(1)
|
||||
|
||||
# set debconf to NON_INTERACTIVE
|
||||
os.environ["DEBIAN_FRONTEND"] = "noninteractive"
|
||||
os.environ["TERM"] = "xterm"
|
||||
os.environ["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
#当不存在语言变量时 默认显示中文
|
||||
if not "LANGUAGE" in os.environ:
|
||||
os.environ["LANGUAGE"] = "zh_CN.UTF-8"
|
||||
|
||||
#当不存在语言变量时 默认显示中文
|
||||
if not "LANG" in os.environ:
|
||||
os.environ["LANG"] = "zh_CN.UTF-8"
|
||||
|
||||
#做一些规范处理
|
||||
if os.environ["LANGUAGE"] == "en":
|
||||
os.environ["LANGUAGE"] = "en_US.UTF-8"
|
||||
if os.environ["LANGUAGE"] == "zh_CN:en" or os.environ["LANGUAGE"] == "zh_CN:zh":
|
||||
os.environ["LANGUAGE"] = "zh_CN.UTF-8"
|
||||
|
||||
# ensure that we are not killed when the terminal goes away e.g. on
|
||||
# shutdown
|
||||
signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
||||
signal.signal(signal.SIGINT,signal_handler_term)
|
||||
|
||||
if options.debug:
|
||||
logging.basicConfig(format=FORMAT,level=logging.INFO,datefmt='%m-%d,%H:%M:%S')
|
||||
else:
|
||||
logging.basicConfig(format=FORMAT,level=logging.DEBUG,datefmt='%m-%d,%H:%M:%S',filename = logfile(),filemode = 'a')
|
||||
|
||||
|
||||
logging.info('Updater Config Manager Daemon(LANGUAGE:%s LANG:%s) starting ...',os.environ["LANGUAGE"],os.environ["LANG"])
|
||||
|
||||
app = UpgradeStrategies(options)
|
||||
app.run()
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
/usr/bin/dbus-monitor --system "type=method_call,interface='org.freedesktop.login1.Manager',path='/org/freedesktop/login1',member='Reboot'" "type=method_call,interface='org.freedesktop.login1.Manager',path='/org/freedesktop/login1',member='PowerOff'" >>/tmp/monitor-dbus-upgrade.log 2>&1 &
|
|
@ -0,0 +1,6 @@
|
|||
2021-09-16 XueYi Luo <luoxueyi@kylinos.cn>
|
||||
|
||||
* zh_CN.po: Updated Simplified Chinese translation.
|
||||
* zh_HK.po: Updated translation for HongKong,china.
|
||||
* zh_TW.po: Updated translation for Taiwan,China.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
top_srcdir=`pwd`/..
|
||||
|
||||
DOMAIN=kylin-system-updater
|
||||
PO_FILES := $(wildcard *.po)
|
||||
CONTACT=sebastian.heinlein@web.de
|
||||
XGETTEXT_ARGS = --msgid-bugs-address=$(CONTACT)
|
||||
XGETTEXT_ARGS += --keyword=unicode_gettext:2 --keyword=unicode_ngettext:2,3
|
||||
XGETTEXT_ARGS += --language=python
|
||||
|
||||
all: update-po
|
||||
|
||||
# update the pot
|
||||
$(DOMAIN).pot:
|
||||
XGETTEXT_ARGS="$(XGETTEXT_ARGS)" intltool-update -p -g $(DOMAIN)
|
||||
|
||||
# merge the new stuff into the po files
|
||||
merge-po: $(PO_FILES)
|
||||
XGETTEXT_ARGS="$(XGETTEXT_ARGS)" intltool-update -r -g $(DOMAIN);
|
||||
|
||||
# create mo from the pos
|
||||
%.mo : %.po
|
||||
mkdir -p mo/$(subst .po,,$<)/LC_MESSAGES/
|
||||
msgfmt $< -o mo/$(subst .po,,$<)/LC_MESSAGES/$(DOMAIN).mo
|
||||
|
||||
# dummy target
|
||||
update-po: $(DOMAIN).pot merge-po $(patsubst %.po,%.mo,$(wildcard *.po))
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[encoding: UTF-8]
|
||||
SystemUpdater/backend/BackendOstreeNext.py
|
||||
SystemUpdater/backend/__init__.py
|
||||
SystemUpdater/UpdateManager.py
|
||||
SystemUpdater/Core/MyCache.py
|
||||
SystemUpdater/Core/UpdateList.py
|
||||
SystemUpdater/Core/OriginFilter.py
|
||||
SystemUpdater/Core/Database.py
|
||||
SystemUpdater/UpdateManagerDbus.py
|
||||
SystemUpdater/Core/enums.py
|
|
@ -0,0 +1,238 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: kylinos.cn\n"
|
||||
"POT-Creation-Date: 2012-06-14 00:53+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "Unable to access the source management server, please try again later"
|
||||
msgstr "འདྲི་རྩད་ཀྱི་འབྱུང་ཁུངས་དོ་དམ་ཞབས་ཞུའི་ཡོ་བྱད་ལ་འཚམས་འདྲི་བྱེད་ཐབས་མེད་པས་རྗེས་སུ་ཡང་བསྐྱར"
|
||||
|
||||
msgid "Access to the source management server timed out, please try again later"
|
||||
msgstr "འཚམས་འདྲིའི་འབྱུང་ཁུངས་ཀྱི་དོ་དམ་ཞབས་ཞུའི་ཡོ་བྱད་དུས་ལས་བརྒལ་བས་རྗེས་སུ་ཡང་བསྐྱར་ཚོད་ལྟ་བྱེད་རོགས"
|
||||
|
||||
msgid "Check if your network requires authentication?"
|
||||
msgstr "ཁྱེད་ཀྱི་དྲ་རྒྱར་ཞིབ་བཤེར་བྱེད་དགོས་སམ།"
|
||||
|
||||
msgid "Check your source public key signature"
|
||||
msgstr "ཁྱེད་ཀྱི་འབྱུང་ཁུངས་ལ་ཞིབ་བཤེར་བྱས་ནས་མིང་རྟགས་བཀོད།"
|
||||
|
||||
msgid "update important list occur Exception"
|
||||
msgstr "ལག་ཏུ་བླངས་ནས་རྒྱུན་ལྡན་མིན་པ་བྱུང་ན་རྗེས་སུ་ཡང་བསྐྱར་ཚོད་ལྟ་ཞིག་གནང་རོགས།"
|
||||
|
||||
msgid "You need to be root to run this application"
|
||||
msgstr "ཁྱོད་ལ་rootཡི་དབང་ཚད་ལྟར་འཁོར་སྐྱོད་བྱེད་དགོས།"
|
||||
|
||||
msgid "There is an exception in the update package."
|
||||
msgstr "ཁུག་མ་གསར་སྒྱུར་བྱས་པ་རྒྱུན་ལྡན་མིན་པ་ཞིག་རེད"
|
||||
|
||||
msgid "You request the removal of a system-essential package."
|
||||
msgstr "ཁྱེད་ཀྱིས་མ་ལག་ཅིག་གི་དགོས་ངེས་ཀྱི་མཉེན་ཆས་ཁུག་མ་ཞིག་བསུབ་དགོས་པའི་བླང་བྱ་"
|
||||
|
||||
msgid "This update cannot detect the upgradeable package."
|
||||
msgstr "ཐེངས་འདིའི་གསར་སྒྱུར་གྱིས་རིམ་འཕར་ཐུབ་པའི་མཉེན་ཆས་ཁུག་མར་ཞིབ་དཔྱད་ཚད་ལེན་བྱེད་ཐབས་མེད།"
|
||||
|
||||
msgid "read important list failed"
|
||||
msgstr "རིམ་པ་སྤོར་བའི་རེའུ་མིག་ཀློག་ཐབས་བྲལ་བས་རྗེས་སུ་ཡང་བསྐྱར་ཚོད་ལྟ་ཞིག་བྱེད་རོགས།"
|
||||
|
||||
msgid "Priority Upgrade Package being updated"
|
||||
msgstr "ཁག་བགོས་ཀྱི་བཀོད་སྒྲིག་གསར་སྒྱུར་བྱེད་བཞིན་ཡོད།"
|
||||
|
||||
msgid "Exceptions of Priority Upgrade."
|
||||
msgstr "དམིགས་སུ་བཀར་ནས་དམིགས་སུ་བཀར་ནས་རིམ་པ"
|
||||
|
||||
msgid "Due to the presence of deleted packages."
|
||||
msgstr "བསུབ་པའི་མཉེན་ཆས་ཁུག་མ་ཡོད་པའི་རྐྱེན་གྱིས།"
|
||||
|
||||
msgid "The system update configuration file is read abnormally, please check if the system update configuration file format is correct."
|
||||
msgstr "མ་ལག་གསར་སྒྱུར་བཀོད་སྒྲིག་ཡིག་ཆ་རྒྱུན་ལྡན་མིན་པས། ཞིབ་བཤེར་མ་ལག་གི་བཀོད་སྒྲིག་ཡིག་ཆའི་རྣམ་གཞག་ཡང་དག་ཡིན་མིན་ལ་ཞིབ་བཤེར་གནང་རོགས།"
|
||||
|
||||
msgid "Installation progress: "
|
||||
msgstr "སྒྲིག་སྦྱོར་མྱུར་ཚད་གཤམ་གསལ། "
|
||||
|
||||
msgid "Installation successful, about to shut down"
|
||||
msgstr "སྒྲིག་སྦྱོར་ལེགས་འགྲུབ་བྱུང་བ་དང་འགག་སྒོ་ལས་སྒྲོལ་གྲབས་ཡོད་"
|
||||
|
||||
msgid "Installation failed, about to shut down"
|
||||
msgstr "སྒྲིག་སྦྱོར་བྱས་ནས་ཕམ་ཉེས་བྱུང་ན་སྒོ་རྒྱག་ལ་ཉེ།"
|
||||
|
||||
msgid "groups JSON ConfigPkgs install failed"
|
||||
msgstr "ཁག་བགོས་ཀྱིས་ཡིག་ཆ་སྒྲིག་སྦྱོར་བྱེད་ཐབས་མེད།"
|
||||
|
||||
msgid "Installtion timeout to exit Due to inactivity"
|
||||
msgstr "སྒྲིག་སྦྱོར་བྱེད་སྐབས་ཕྱིར་འཐེན་བྱས་པའི་རྐྱེན་གྱིས་རེད།"
|
||||
|
||||
msgid "Command execution error"
|
||||
msgstr "ཚགས་པར་འདོན་ནོར་ཤོར་བའི་བཀའ་ཕབ་པ།"
|
||||
|
||||
msgid "Unsupported architecture"
|
||||
msgstr "སྒྲོམ་གཞི་དང་མི་མཐུན་པ།"
|
||||
|
||||
msgid "Other Error"
|
||||
msgstr "ནོར་འཁྲུལ་གཞན་དག་བཅས་ཡིན"
|
||||
|
||||
msgid "dependency is not satisfied"
|
||||
msgstr "འབྲེལ་བ་མི་ཚིམ་པར་བརྟེན་དགོས།"
|
||||
|
||||
msgid "dependency is not satisfied will download"
|
||||
msgstr "འབྲེལ་བ་མི་ཚིམ་པར་བརྟེན་དགོས།"
|
||||
|
||||
msgid "Disk space is insufficient, please clean the disk and then upgrade"
|
||||
msgstr "ཁབ་ལེན་གྱི་བར་སྟོང་མི་འདང་བས་ཁབ་ལེན་སྡེར་མ་གཙང་བཤེར་བྱས་རྗེས་རིམ་སྤར་གསར་སྒྱུར་བྱེད་རོགས།"
|
||||
|
||||
msgid "Network anomaly, can't check for updates!"
|
||||
msgstr "དྲ་རྒྱ་རྒྱུན་ལྡན་མིན་པས་ཞིབ་བཤེར་གསར་སྒྱུར་བྱེད་ཐབས་མེད།"
|
||||
|
||||
msgid "Check for update exceptions!"
|
||||
msgstr "རྒྱུན་ལྡན་མིན་པར་ཞིབ་བཤེར་བྱེད་པ།"
|
||||
|
||||
msgid "Check for update exceptions,fix system APT environment error."
|
||||
msgstr "ཞིབ་བཤེར་གསར་སྒྱུར་མ་ལག་APTཡི་ཁོར་ཡུག་ལ་ནོར་འཁྲུལ་བྱུང་བ་རེད།"
|
||||
|
||||
msgid "The system APT environment is abnormal, please check the system APT environment."
|
||||
msgstr "མ་ལག་APTཡི་ཁོར་ཡུག་རྒྱུན་ལྡན་མིན་པར་ཉམས་གསོ་བྱེད་པར་མ་ལག་APTཡི་ཁོར་ཡུག་ལ་ཞིབ་བཤེར་གནང་རོགས།"
|
||||
|
||||
msgid "Priority upgrade status exception."
|
||||
msgstr "དམིགས་སུ་བཀར་ནས་རིམ་པ་འཕར་བའི་རྣམ་པ་རྒྱུན་ལྡན་མིན་པ"
|
||||
|
||||
msgid "Upgrade configuration acquisition exception."
|
||||
msgstr "རིམ་སྤར་བཀོད་སྒྲིག་ལ་རྒྱུན་ལྡན་མིན་པའི་གྲུབ་འབྲས་ཐོབ་པ་རེད།"
|
||||
|
||||
msgid "Please check your network connection and retry."
|
||||
msgstr "ཁྱེད་ཀྱི་དྲ་རྒྱ་འབྲེལ་མཐུད་བྱས་རྗེས་ཡང་བསྐྱར་ཚོད་ལྟ་ཞིག་བྱེད་རོགས།"
|
||||
|
||||
msgid "Please check your source list and retry."
|
||||
msgstr "ཁྱེད་ཀྱི་འབྱུང་ཁུངས་རེའུ་མིག་ལ་ཞིབ་བཤེར་བྱས་རྗེས་ཡང་བསྐྱར་ཚོད་ལྟ་བྱོས།"
|
||||
|
||||
msgid "Checking network connection"
|
||||
msgstr "དྲ་རྒྱ་སྦྲེལ་མཐུད་བྱེད་པར་ཞིབ་བཤེར་བྱ་དགོས།"
|
||||
|
||||
msgid "Updating Source Template"
|
||||
msgstr "འབྱུང་ཁུངས་གསར་སྒྱུར་བྱེད་པའི་མ་དཔེའི་ནང་།"
|
||||
|
||||
msgid "Update Manager upgrade is complete, please restart the setting panel before performing the system update."
|
||||
msgstr "དོ་དམ་ཡོ་བྱད་རིམ་སྤར་ལེགས་འགྲུབ་བྱུང་བ་དང་། གསར་བཅོས་བྱས་རྗེས་སླར་ཡང་མ་ལག་གསར་སྒྱུར་བྱེད་རོགས།"
|
||||
|
||||
msgid "Uninstallation completed"
|
||||
msgstr "ཕབ་ལེན་ལེགས་འགྲུབ་བྱུང་བ།"
|
||||
|
||||
msgid "Package validation failed and installation was rejected."
|
||||
msgstr "མཉེན་ཆས་ཚོད་ལྟས་ར་སྤྲོད་བྱས་ནས་ཕམ་ཁ་བྱུང་བས་སྒྲིག་སྦྱོར་དང་ལེན་མ་བྱས"
|
||||
|
||||
msgid "Other tasks are being updated and upgraded, please uninstall them later."
|
||||
msgstr "ལས་འགན་གཞན་དག་གསར་སྒྱུར་རིམ་སྤོར་བྱེད་བཞིན་པའི་སྒང་ཡིན་"
|
||||
|
||||
#: ../aptdaemon/worker/aptworker.py:1353
|
||||
msgid "The following packages have unmet dependencies:"
|
||||
msgstr "གཤམ་གསལ་གྱི་མཉེན་ཆས་ཁུག་མ་ཡིད་ཚིམ་པའི་གཞན་རྟེན་གྱི་འབྲེལ་བ།"
|
||||
|
||||
#: ../aptdaemon/worker/aptworker.py:1406
|
||||
msgid "but it is a virtual package"
|
||||
msgstr "འོན་ཀྱང་དེ་ནི་རྟོག་བཟོའི་མཉེན་ཆས་ཁུག་མ་རེད།"
|
||||
|
||||
#: ../aptdaemon/worker/aptworker.py:1409
|
||||
msgid "but it is not installed"
|
||||
msgstr "但是 %s 没有安装"
|
||||
|
||||
#: ../aptdaemon/worker/aptworker.py:1411
|
||||
msgid "but it is not going to be installed"
|
||||
msgstr "但是无法安装 %s"
|
||||
|
||||
#. TRANSLATORS: %s is a version number
|
||||
#: ../aptdaemon/worker/aptworker.py:1415
|
||||
#, python-format
|
||||
msgid "but %s is installed"
|
||||
msgstr "但是 %s 已经安装"
|
||||
|
||||
#. TRANSLATORS: %s is a version number
|
||||
#: ../aptdaemon/worker/aptworker.py:1419
|
||||
#, python-format
|
||||
msgid "but %s is to be installed"
|
||||
msgstr "但是将要安装 %s"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:763
|
||||
msgid "Kylin System Updater"
|
||||
msgstr "ཝེ།སྒྲིག་ཆས་གསར་སྒྱུར་བྱེད་དགོས།"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:609
|
||||
msgid "Kylin Installer"
|
||||
msgstr "ཝེ།སྒྲིག་ཆས་སྒྲིག་སྦྱོར་བྱེད་དགོས།"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:610
|
||||
msgid "Kylin Uninstaller"
|
||||
msgstr "ཝེ།བཏགས་ཆས་"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:611
|
||||
msgid "Kylin Background Upgrade"
|
||||
msgstr "ཁ་རོག་གེར་གསར་སྒྱུར་བྱེད་པ།"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:612
|
||||
msgid "Kylin Software Center"
|
||||
msgstr "མཉེན་ཆས་ཚོང་ཁང་།"
|
||||
|
||||
#: ../SystemUpdater/UpdateManagerDbus.py:355
|
||||
msgid " requires authentication to uninstall software packages."
|
||||
msgstr "མཉེན་ཆས་ཀྱི་ཁུག་མ་འདོན་པར་བདེན་དཔང་ར་སྤྲོད་བྱེད་དགོས།"
|
||||
|
||||
#. 验签失败,提权
|
||||
#: ../SystemUpdater/UpdateManager.py:463
|
||||
msgid " requires authentication to install software packages."
|
||||
msgstr "མཉེན་ཆས་ཀྱི་ཁུག་མ་སྒྲིག་སྦྱོར་བྱེད་པར་བདེན་དཔང་ར་སྤྲོད་བྱེད"
|
||||
|
||||
#: ../SystemUpdater/Core/utils.py:750
|
||||
msgid "Authentication success."
|
||||
msgstr "བདེན་དཔང་ར་སྤྲོད་ལེགས་འགྲུབ་བྱུང་"
|
||||
|
||||
#: ../SystemUpdater/Core/utils.py:753
|
||||
msgid "Authentication failure."
|
||||
msgstr "བདེན་དཔང་ར་སྤྲོད་ཕམ་སོང་།"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:101
|
||||
msgid "Deb format exception, read local deb file error."
|
||||
msgstr "མཉེན་ཆས་ཀྱི་ཁུག་མའི་རྣམ་གཞག་རྒྱུན་ལྡན་མིན་པས་ཕམ་ཁ་བླངས།"
|
||||
|
||||
#: ../SystemUpdater/Core/enums.py:102
|
||||
msgid "Install deb error."
|
||||
msgstr "མཉེན་ཆས་སྒྲིག་སྦྱོར་བྱས་པ་ཕམ་སོང་།"
|
||||
|
||||
msgid "Upgrade System"
|
||||
msgstr "ཁྱོན་ཡོངས་ནས་རིམ་སྤར་བྱ་དགོས།"
|
||||
|
||||
msgid "kylin-unattended-upgrade"
|
||||
msgstr "རང་འགུལ་གྱིས་གསར་སྒྱུར་བྱེད་དགོས།"
|
||||
|
||||
msgid "Please check the system time and synchronize the system time before updating."
|
||||
msgstr "མ་ལག་གི་དུས་ཚོད་ལ་ཞིབ་བཤེར་གནང་རོགས། དུས་མཉམ་དུ་མ་ལག་གི་དུས་ཚོད་རྗེས་སུ་གསར་སྒྱུར་བྱེད་དགོས"
|
||||
|
||||
msgid "The package is unsigned, refuses to install."
|
||||
msgstr "མཉེན་ཆས་ཀྱི་ཁུག་མར་མིང་རྟགས་མ་བཀོད་པས་སྒྲིག་སྦྱོར་དང་ལེན་མི་བྱེད།"
|
||||
|
||||
msgid "Program exception, please contact the administrator to solve."
|
||||
msgstr "གོ་རིམ་ལག་བསྟར་རྒྱུན་ལྡན་མིན་པར་དོ་དམ་པ་དང་འབྲེལ་གཏུག་བྱས་ནས་ཐག་གཅོད"
|
||||
|
||||
msgid "Exceptions to running the check script."
|
||||
msgstr "འཁོར་སྐྱོད་ཞིབ་བཤེར་གྱི་རྐང་པར་རྒྱུན་ལྡན་མིན་པ་བྱུང་།"
|
||||
|
||||
msgid "Application installation control policy not enabled ."
|
||||
msgstr "ཉེར་སྤྱོད་སྒྲིག་སྦྱོར་དོ་དམ་ཚོད་འཛིན་བྱེད་འགོ་ཚུགས་མེད་པ།"
|
||||
|
||||
msgid "Installation failed! Application is not in the software whitelist list!"
|
||||
msgstr "སྒྲིག་སྦྱོར་ཕམ་པ། མཉེན་ཆས་ནི་མིང་ཐོའི་རེའུ་མིག་དཀར་པོ་ན་ཡོད་དམ།"
|
||||
|
||||
msgid "Installation failed! Application is in the software blacklist list!"
|
||||
msgstr "སྒྲིག་སྦྱོར་ཕམ་པ། མཉེན་ཆས་མིང་ཐོའི་ནང་དུ་ཡོད།"
|
||||
|
||||
msgid "Application installation in unknown mode ."
|
||||
msgstr "ཉེར་སྤྱོད་སྒྲིག་སྦྱོར་དང་དོ་དམ་ཚོད་འཛིན་གྱི་ཐབས་ཇུས་མི་ཤེས་པ།"
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
#!/bin/sh
|
||||
#系统升级收集bug日志使用
|
||||
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
echo "当前执行权限是root,请使用普通权限来执行"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "系统升级收集BUG日志使用..."
|
||||
|
||||
#建立收集的log目录
|
||||
mkdir updaterlog
|
||||
#记录一些基本信息
|
||||
date >> updaterlog/base-info
|
||||
dpkg -l | grep kylin-system-updater >> updaterlog/base-info
|
||||
echo $1 >> updaterlog/base-info
|
||||
echo "记录BUG产生时间(系统当前时间)以及升级相关的版本信息:"
|
||||
cat updaterlog/base-info
|
||||
|
||||
cp /etc/apt/sources.list updaterlog || true
|
||||
cp -r /etc/apt/apt.conf.d updaterlog || true
|
||||
cp -r /var/log/syslog updaterlog || true
|
||||
cp -r /usr/share/kylin-update-desktop-config/config/ updaterlog || true
|
||||
cp -r /var/log/kylin-system-updater/ updaterlog || true
|
||||
|
||||
#收集apt的日志
|
||||
cp -r /var/log/apt updaterlog || true
|
||||
cp -r /var/log/dpkg.log updaterlog || true
|
||||
cp -r /var/log/kylin-unattended-upgrades/ updaterlog || true
|
||||
cp -r ~/.config/kylin-background-upgrade/ updaterlog || true
|
||||
|
||||
#激活
|
||||
cp -r ~/.log/kylin-activation/ updaterlog || true
|
||||
|
||||
#收集前端日志
|
||||
cp -r ~/.log/kylin-update-frontend-notifysend.log updaterlog >/dev/null 2>&1 || true
|
||||
cp -r ~/.log/ukui-control-center.log updaterlog >/dev/null 2>&1 || true
|
||||
cp -r ~/.log/ukui-notification-daemon.log updaterlog >/dev/null 2>&1 || true
|
||||
cp -r ~/.config/ukui-session/ updaterlog >/dev/null 2>&1 || true
|
||||
cp -r /tmp/kylin-updateresult-notify.log updaterlog >/dev/null 2>&1 || true
|
||||
|
||||
outputName="$(date +%m-%d,%H-%M-%S)-updaterLog.tar.gz"
|
||||
|
||||
#将所有的日志进行打包
|
||||
tar -czvf updaterLog.tar.gz updaterlog >/dev/null
|
||||
|
||||
#删除收集的日志目录
|
||||
rm -rf updaterlog
|
||||
|
||||
#将文件存储到桌面
|
||||
if [ ! -d ~/桌面 ]; then
|
||||
mv updaterLog.tar.gz ~/Desktop/$outputName
|
||||
echo 输出位置:~/Desktop/$outputName
|
||||
else
|
||||
mv updaterLog.tar.gz ~/桌面/$outputName
|
||||
echo 输出位置:~/桌面/$outputName
|
||||
fi
|
||||
|
||||
echo "系统更新日志收集完毕..."
|
||||
echo "\033[1;31m注意:\033[0m 1、请确保Bug复现的时间与执行脚本收集日志时间相近,以此能根据脚本执行时间快速定位到问题的相关日志..."
|
||||
echo " 2、若Bug复现的时间与现在时间相差较远时,请手动输入大概复现时间。例如 report-updater-bug 月-日,时-分"
|
||||
echo "请将桌面下\033[5;32;49;1m $outputName \033[0m日志文件提交到禅道... "
|
|
@ -0,0 +1,15 @@
|
|||
[build_i18n]
|
||||
domain=kylin-system-updater
|
||||
|
||||
# xml_files=[("share/metainfo/",
|
||||
# ("data/update-manager.appdata.xml.in",)),
|
||||
# ]
|
||||
|
||||
[sdist]
|
||||
formats = bztar
|
||||
|
||||
[nosetests]
|
||||
match=test
|
||||
|
||||
# [install]
|
||||
# skip-build=0
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
|
||||
from distutils.core import setup
|
||||
from DistUtilsExtra.command import (
|
||||
build_extra, build_i18n, build_help)
|
||||
|
||||
disabled = []
|
||||
class CustomBuild(build_extra.build_extra):
|
||||
def run(self):
|
||||
build_extra.build_extra.run(self)
|
||||
|
||||
setup(
|
||||
packages=[ 'SystemUpdater',
|
||||
'SystemUpdater.backend',
|
||||
'SystemUpdater.Core'
|
||||
],
|
||||
cmdclass={ "build": CustomBuild,
|
||||
"build_i18n": build_i18n.build_i18n
|
||||
# "build_help": build_help.build_help
|
||||
}
|
||||
)
|
|
@ -1,3 +1,21 @@
|
|||
kylin-system-updater (3.0.0.0-ok2) nile; urgency=medium
|
||||
|
||||
* BUG:无
|
||||
* 需求号: 无
|
||||
* 其他改动说明: 同时兼容可变系统更新包以及不可变系统更新包
|
||||
* 其他改动影响域:系统更新
|
||||
|
||||
-- wangsong <wangsong@kylinos.cn> Tue, 12 Dec 2023 20:40:24 +0800
|
||||
|
||||
kylin-system-updater (3.0.0.0-ok1) nile; urgency=medium
|
||||
|
||||
* BUG:无
|
||||
* 需求号: 无
|
||||
* 其他改动说明: 引入基于不可变系统的系统更新
|
||||
* 其他改动影响域:系统更新
|
||||
|
||||
-- wangsong <wangsong@kylinos.cn> Mon, 04 Dec 2023 11:36:30 +0800
|
||||
|
||||
kylin-system-updater (2.0.5.15-ok9) yangtze; urgency=medium
|
||||
|
||||
* BUG:issues/I8305P【控制面板】【更新】d-feet设置参数开启"自动更新"后,日志中显示download time及install time可以下载更新包成功安装失败
|
||||
|
|
|
@ -43,9 +43,33 @@ Depends: ${python3:Depends},
|
|||
python3-crypto,
|
||||
sqlite3,
|
||||
kylin-update-frontend
|
||||
Breaks:
|
||||
Recommends: python3-launchpadlib
|
||||
Breaks: kylin-system-updater-immutable
|
||||
Conflicts: kylin-system-updater-immutable
|
||||
Suggests: gir1.2-dbusmenu-glib-0.4,
|
||||
gir1.2-unity-5.0,
|
||||
gir1.2-unity-5.0
|
||||
|
||||
Package: kylin-system-updater-immutable
|
||||
Architecture: all
|
||||
Depends: ${python3:Depends},
|
||||
${misc:Depends},
|
||||
policykit-1,
|
||||
python3-dbus,
|
||||
python3-psutil,
|
||||
python3-gi (>= 3.8),
|
||||
python3-yaml,
|
||||
aptdaemon (>=1.1.1+bzr982-0kylin32.3k5.2),
|
||||
python3-distro-info,
|
||||
python3-apscheduler,
|
||||
python3-crypto,
|
||||
ostree,
|
||||
gir1.2-ostree-1.0,
|
||||
libostree-1-1,
|
||||
sqlite3
|
||||
Recommends: python3-launchpadlib
|
||||
Breaks: kylin-system-updater
|
||||
Conflicts: kylin-system-updater
|
||||
Suggests: gir1.2-dbusmenu-glib-0.4,
|
||||
gir1.2-unity-5.0
|
||||
Description: dbus daemon that manages apt updates.
|
||||
dbus daemon that manages apt updates. Provides DBUS interfaces to UKCC.
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/dh-exec
|
||||
#backend-immutable
|
||||
backend-immutable/data/kylin-system-updater.db /usr/share/kylin-system-updater/
|
||||
backend-immutable/report-updater-bug /usr/bin
|
||||
backend-immutable/data/30kylin-system-updater /etc/apt/apt.conf.d/
|
||||
backend-immutable/data/com.kylin.systemupgrade.conf /etc/dbus-1/system.d/
|
||||
#backend-immutable/data/com.kylin.systemupgrade.limit /etc/dbus-1/conf/
|
||||
backend-immutable/data/kylin-system-updater.service /usr/lib/systemd/system/
|
||||
#backend-immutable/data/kylin-upgrade-poweroff.service /usr/lib/systemd/system/
|
||||
backend-immutable/data/kylin-logout-required /usr/share/kylin-system-updater/
|
||||
backend-immutable/data/kylin-reboot-required /usr/share/kylin-system-updater/
|
||||
backend-immutable/kylin-system-updater /usr/share/kylin-system-updater/
|
||||
backend-immutable/monitor-reboot /usr/share/kylin-system-updater/
|
||||
backend-immutable/SystemUpdater/*.py /usr/share/kylin-system-updater/SystemUpdater/
|
||||
backend-immutable/SystemUpdater/backend/*.py /usr/share/kylin-system-updater/SystemUpdater/backend/
|
||||
backend-immutable/SystemUpdater/Core/*.py /usr/share/kylin-system-updater/SystemUpdater/Core/
|
||||
backend-immutable/build/mo/* /usr/share/locale/
|
||||
backend-immutable/data/system-updater-defaults.conf /var/lib/kylin-system-updater/
|
||||
backend-immutable/data/system-updater-coverable.conf /var/lib/kylin-system-updater/
|
||||
backend-immutable/data/inhibit-sleep.conf /var/lib/kylin-system-updater/
|
||||
backend-immutable/data/unattended-upgrades-policy.conf /var/lib/unattended-upgrades/
|
||||
backend-immutable/data/unattended-upgrades-timestamp /var/lib/unattended-upgrades/
|
||||
backend-immutable/data/cn.kylinos.KylinSystemUpdater.policy /usr/share/polkit-1/actions/
|
||||
backend-immutable/data/kylin-system-version.conf /etc/kylin-version/
|
||||
|
||||
#configDaemon
|
||||
backend-immutable/kylin-upgrade-strategies /usr/share/kylin-system-updater/
|
||||
backend-immutable/data/com.kylin.UpgradeStrategies.conf /etc/dbus-1/system.d/
|
||||
backend-immutable/data/com.kylin.UpgradeStrategies.service /usr/share/dbus-1/system-services/
|
||||
backend-immutable/data/cn.kylinos.UpgradeStrategies.policy /usr/share/polkit-1/actions/
|
||||
backend-immutable/data/kylin-system-updater /etc/logrotate.d
|
||||
|
||||
#uu
|
||||
unattended-upgrades/*.service /lib/systemd/system/
|
||||
unattended-upgrades/notify /usr/bin/
|
||||
unattended-upgrades/*.desktop /etc/xdg/autostart/
|
||||
unattended-upgrades/kylin-unattended-upgrade /usr/bin
|
||||
unattended-upgrades/kylin-unattended-upgrade-shutdown /usr/bin
|
||||
unattended-upgrades/kylin-unattended-upgrades /etc/apt/apt.conf.d/
|
||||
unattended-upgrades/logrotate.d/* /etc/logrotate.d/
|
||||
|
Loading…
Reference in New Issue