Merge branch 'backend_manual' of gitlab2.kylin.com:kylin-desktop/update-manager-group/kylin-system-updater into backend_manual
This commit is contained in:
commit
a7a1de97ac
|
@ -9,6 +9,7 @@ __all__ = (
|
||||||
"ERROR_REMOVE_ESSENTIAL_PACKAGES","ERROR_NOT_DISK_SPACE","ERROR_NOT_CONFIGPKG_DEPENDENCIES","ERROR_NOT_SELFPKG_DEPENDENCIES",
|
"ERROR_REMOVE_ESSENTIAL_PACKAGES","ERROR_NOT_DISK_SPACE","ERROR_NOT_CONFIGPKG_DEPENDENCIES","ERROR_NOT_SELFPKG_DEPENDENCIES",
|
||||||
"ERROR_NOT_FIX_SYSTEM","ERROR_READ_LOCAL_DEB","ERROR_LOCAL_DEB_FORMAT","ERROR_INSTALL_DEB_BASE","ERROR_LOAD_CONFIG_FAILED",
|
"ERROR_NOT_FIX_SYSTEM","ERROR_READ_LOCAL_DEB","ERROR_LOCAL_DEB_FORMAT","ERROR_INSTALL_DEB_BASE","ERROR_LOAD_CONFIG_FAILED",
|
||||||
"ERROR_UPDATE_KEY_SIGNATURES","ERROR_UPDATE_NET_AUTHENTICATION","ERROR_UPDATE_NOTREAD_SOURCES","PRIORITY_UPGRADE_SUCCCESSED",
|
"ERROR_UPDATE_KEY_SIGNATURES","ERROR_UPDATE_NET_AUTHENTICATION","ERROR_UPDATE_NOTREAD_SOURCES","PRIORITY_UPGRADE_SUCCCESSED",
|
||||||
|
"ERROR_UPDATE_INVALID_TIME",
|
||||||
|
|
||||||
"get_error_description_from_enum", "get_error_string_from_enum", "get_source_name_from_enum", "get_caller_from_enum")
|
"get_error_description_from_enum", "get_error_string_from_enum", "get_source_name_from_enum", "get_caller_from_enum")
|
||||||
|
|
||||||
|
@ -19,11 +20,12 @@ _ = gettext.gettext
|
||||||
|
|
||||||
PRIORITY_UPGRADE_SUCCCESSED = "priority-upgrade-successed"
|
PRIORITY_UPGRADE_SUCCCESSED = "priority-upgrade-successed"
|
||||||
|
|
||||||
#更新阶段
|
#apt update阶段出现的错误解析
|
||||||
ERROR_UPDATE_DEFAULT_FAILED = "error-update-default-failed"
|
ERROR_UPDATE_DEFAULT_FAILED = "error-update-default-failed"
|
||||||
ERROR_UPDATE_KEY_SIGNATURES = "The following signatures"
|
ERROR_UPDATE_KEY_SIGNATURES = "The following signatures"
|
||||||
ERROR_UPDATE_NET_AUTHENTICATION ="does the network require authentication?"
|
ERROR_UPDATE_NET_AUTHENTICATION ="does the network require authentication?"
|
||||||
ERROR_UPDATE_NOTREAD_SOURCES = "The list of sources could not be read"
|
ERROR_UPDATE_NOTREAD_SOURCES = "The list of sources could not be read"
|
||||||
|
ERROR_UPDATE_INVALID_TIME = "(invalid for another"
|
||||||
|
|
||||||
ERROR_UPDATE_SOURCE_FAILED = "error-update-source-failed"
|
ERROR_UPDATE_SOURCE_FAILED = "error-update-source-failed"
|
||||||
ERROR_NETWORK_FAILED = "error-network-failed"
|
ERROR_NETWORK_FAILED = "error-network-failed"
|
||||||
|
@ -81,6 +83,7 @@ _DESCS_ERROR = {
|
||||||
ERROR_NETWORK_FAILED: _("Please check your network connection and retry."),
|
ERROR_NETWORK_FAILED: _("Please check your network connection and retry."),
|
||||||
ERROR_UPDATE_KEY_SIGNATURES: _("Check your source public key signature"),
|
ERROR_UPDATE_KEY_SIGNATURES: _("Check your source public key signature"),
|
||||||
ERROR_UPDATE_NOTREAD_SOURCES: _("Please check your source list and retry."),
|
ERROR_UPDATE_NOTREAD_SOURCES: _("Please check your source list and retry."),
|
||||||
|
ERROR_UPDATE_INVALID_TIME: _("Please check the system time and synchronize the system time before updating."),
|
||||||
ERROR_UPDATE_NET_AUTHENTICATION: _("Check if your network requires authentication?"),
|
ERROR_UPDATE_NET_AUTHENTICATION: _("Check if your network requires authentication?"),
|
||||||
ERROR_NOT_GROUPS_CONFIG: _("Unable to get group configuration package, Please check if the configuration package exists in the software source repository."),
|
ERROR_NOT_GROUPS_CONFIG: _("Unable to get group configuration package, Please check if the configuration package exists in the software source repository."),
|
||||||
ERROR_NOT_INIT_PACKAGESINFIO: _("An unresolvable problem occurred while initializing the package."),
|
ERROR_NOT_INIT_PACKAGESINFIO: _("An unresolvable problem occurred while initializing the package."),
|
||||||
|
|
|
@ -59,9 +59,6 @@ from ctypes import *
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
# 禁止关机锁文件路径
|
# 禁止关机锁文件路径
|
||||||
FILELOCK_PATH = "/tmp/lock/"
|
|
||||||
SHUTDOWN_BLOCK_FILELOCK = "kylin-update.lock"
|
|
||||||
inhibit_lock = None
|
|
||||||
VERIFY_SO = "libkylin_signtool.so"
|
VERIFY_SO = "libkylin_signtool.so"
|
||||||
|
|
||||||
class ExecutionTime(object):
|
class ExecutionTime(object):
|
||||||
|
|
|
@ -354,7 +354,7 @@ class InstallBackendAptdaemon(InstallBackend):
|
||||||
if progress > 51 and progress < 90 and self.on_install_stage == False:
|
if progress > 51 and progress < 90 and self.on_install_stage == False:
|
||||||
logging.info("The process is now in the installtion phase")
|
logging.info("The process is now in the installtion phase")
|
||||||
self.on_install_stage = True
|
self.on_install_stage = True
|
||||||
self._start_install_lock()
|
self._start_install_lock(_("Kylin System Updater"))
|
||||||
|
|
||||||
#只处理从下载切换到安装时出现的网络问题
|
#只处理从下载切换到安装时出现的网络问题
|
||||||
#当网络波动时下载某些软件包失败时属于异常状态进行重试时 不发送后续进度 等待重试正常是 进行下载安装
|
#当网络波动时下载某些软件包失败时属于异常状态进行重试时 不发送后续进度 等待重试正常是 进行下载安装
|
||||||
|
|
|
@ -10,6 +10,8 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
|
import shutil
|
||||||
|
import fcntl
|
||||||
import threading
|
import threading
|
||||||
from apt import Cache
|
from apt import Cache
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
@ -234,8 +236,6 @@ class InstallBackend():
|
||||||
delete_pkgs = []
|
delete_pkgs = []
|
||||||
#被删除包的描述
|
#被删除包的描述
|
||||||
raw_description = []
|
raw_description = []
|
||||||
#那些包升级导致删除包 全盘升级不包含
|
|
||||||
delete_desc = []
|
|
||||||
|
|
||||||
#判断是否配置aptdaemon的限速
|
#判断是否配置aptdaemon的限速
|
||||||
self.window_main.check_conifg_aptdeamon()
|
self.window_main.check_conifg_aptdeamon()
|
||||||
|
@ -246,16 +246,8 @@ class InstallBackend():
|
||||||
#获取要升级和安装的包列表
|
#获取要升级和安装的包列表
|
||||||
pkgs_install,pkgs_upgrade = self._make_pkgs_list(self.cache,self.upgrade_data.groups_pkgs,self.now_upgrade.upgrade_groups,self.now_upgrade.single_pkgs)
|
pkgs_install,pkgs_upgrade = self._make_pkgs_list(self.cache,self.upgrade_data.groups_pkgs,self.now_upgrade.upgrade_groups,self.now_upgrade.single_pkgs)
|
||||||
#计算解决依赖关系
|
#计算解决依赖关系
|
||||||
delete_pkgs,delete_desc = self._make_problem_resolver(self.cache,pkgs_install,pkgs_upgrade,self.upgrade_data.adjust_pkgs)
|
self._make_problem_resolver(self.cache,pkgs_install,pkgs_upgrade,self.upgrade_data.adjust_pkgs)
|
||||||
pkgs_install,pkgs_upgrade,pkgs_remove,pkgs_downgrade = self._get_mark_from_cache(self.cache,self.upgrade_data.adjust_pkgs,self.action_mode)
|
pkgs_install,pkgs_upgrade,pkgs_remove,pkgs_downgrade = self._get_mark_from_cache(self.cache,self.upgrade_data.adjust_pkgs,self.action_mode)
|
||||||
|
|
||||||
if len(pkgs_remove) != len(delete_pkgs):
|
|
||||||
logging.warning("Simulation of the deletion package list:%s",str(delete_pkgs))
|
|
||||||
logging.warning("ProblemResolver of the deletion package list:%s",str(pkgs_remove))
|
|
||||||
delete_desc = []
|
|
||||||
self.update_essential.check_white(pkgs_remove)
|
|
||||||
else:
|
|
||||||
pkgs_remove = delete_pkgs
|
|
||||||
else:
|
else:
|
||||||
# 使用全盘升级 全盘使用dist-upgrade
|
# 使用全盘升级 全盘使用dist-upgrade
|
||||||
if self.cache.get_changes():
|
if self.cache.get_changes():
|
||||||
|
@ -263,25 +255,26 @@ class InstallBackend():
|
||||||
self.cache._depcache.upgrade(True)
|
self.cache._depcache.upgrade(True)
|
||||||
pkgs_install,pkgs_upgrade,pkgs_remove,pkgs_downgrade = self._get_mark_from_cache(self.cache,self.upgrade_data.adjust_pkgs,self.action_mode)
|
pkgs_install,pkgs_upgrade,pkgs_remove,pkgs_downgrade = self._get_mark_from_cache(self.cache,self.upgrade_data.adjust_pkgs,self.action_mode)
|
||||||
|
|
||||||
|
logging.warning("ProblemResolver of the deletion package list:%s",str(pkgs_remove))
|
||||||
|
self.update_essential.check_white(pkgs_remove)
|
||||||
logging.info("RESOLVER install:%d , upgrade:%d remove:%d pkgs_downgrade:%d",len(pkgs_install),len(pkgs_upgrade),\
|
logging.info("RESOLVER install:%d , upgrade:%d remove:%d pkgs_downgrade:%d",len(pkgs_install),len(pkgs_upgrade),\
|
||||||
len(pkgs_remove),len(pkgs_downgrade))
|
len(pkgs_remove),len(pkgs_downgrade))
|
||||||
is_remove_pkgs = len(pkgs_remove) != 0
|
is_remove_pkgs = len(pkgs_remove) != 0
|
||||||
|
|
||||||
|
# 数据上报
|
||||||
self.window_main.collector.Generate_Msg(self.now_upgrade.upgrade_groups+self.now_upgrade.single_pkgs, self.action_mode)
|
self.window_main.collector.Generate_Msg(self.now_upgrade.upgrade_groups+self.now_upgrade.single_pkgs, self.action_mode)
|
||||||
errorCode = ""
|
errorCode = ""
|
||||||
if is_remove_pkgs:
|
if is_remove_pkgs:
|
||||||
errorCode = _("Need remove pkgs: ")+", ".join(pkgs_remove)
|
errorCode = _("Need remove pkgs: ")+", ".join(pkgs_remove)
|
||||||
for ul in self.window_main.collector.upgrade_list:
|
for ul in self.window_main.collector.upgrade_list:
|
||||||
self.window_main.collector.Upgrade_Process_Msg(self.action, {"appname":ul, "status":is_remove_pkgs, "errorCode":errorCode})
|
self.window_main.collector.Upgrade_Process_Msg(self.action, {"appname":ul, "status":is_remove_pkgs, "errorCode":errorCode})
|
||||||
|
|
||||||
#添加关于删除包的描述信息
|
#补充删除包的描述信息,删除描述
|
||||||
|
delete_desc = []
|
||||||
for pkg in pkgs_remove:
|
for pkg in pkgs_remove:
|
||||||
pkg_obj = self.cache[pkg]
|
pkg_obj = self.cache[pkg]
|
||||||
raw_description.append(getattr(pkg_obj.candidate, "summary", ''))
|
raw_description.append(getattr(pkg_obj.candidate, "summary", ''))
|
||||||
#补充删除描述
|
delete_desc.append('')
|
||||||
if pkgs_remove != [] and delete_desc == []:
|
|
||||||
for pkg in pkgs_remove:
|
|
||||||
delete_desc.append('')
|
|
||||||
|
|
||||||
if self.action_mode != self.MODE_INSTALL_SYSTEM:
|
if self.action_mode != self.MODE_INSTALL_SYSTEM:
|
||||||
self.window_main.dbusController.UpdateDependResloveStatus(True,is_remove_pkgs,pkgs_remove,raw_description,delete_desc,'','')
|
self.window_main.dbusController.UpdateDependResloveStatus(True,is_remove_pkgs,pkgs_remove,raw_description,delete_desc,'','')
|
||||||
|
@ -332,7 +325,7 @@ class InstallBackend():
|
||||||
self.fix_incomplete()
|
self.fix_incomplete()
|
||||||
#卸载包
|
#卸载包
|
||||||
elif self.action == self.ACTION_REMOVE_PACKAGES:
|
elif self.action == self.ACTION_REMOVE_PACKAGES:
|
||||||
self._start_install_lock()
|
self._start_install_lock(_("Kylin System Updater"))
|
||||||
self.purge_packages(partial_upgrade_list)
|
self.purge_packages(partial_upgrade_list)
|
||||||
elif self.action == self.ACTION_CLEAN:
|
elif self.action == self.ACTION_CLEAN:
|
||||||
self.clean()
|
self.clean()
|
||||||
|
@ -545,9 +538,6 @@ class InstallBackend():
|
||||||
|
|
||||||
#将获取本次升级的包 进行计算依赖关系 解决依赖问题
|
#将获取本次升级的包 进行计算依赖关系 解决依赖问题
|
||||||
def _make_problem_resolver(self,cache,pkgs_install = [],pkgs_upgrade = [],adjust_pkgs = []):
|
def _make_problem_resolver(self,cache,pkgs_install = [],pkgs_upgrade = [],adjust_pkgs = []):
|
||||||
#计算出来的需要删除的包列表
|
|
||||||
delete_pkgs = []
|
|
||||||
delete_desc = []
|
|
||||||
try:
|
try:
|
||||||
logging.info("ProblemResolver install:%d , upgrade:%d",len(pkgs_install),len(pkgs_upgrade))
|
logging.info("ProblemResolver install:%d , upgrade:%d",len(pkgs_install),len(pkgs_upgrade))
|
||||||
logging.info("Start calculating dependencies...")
|
logging.info("Start calculating dependencies...")
|
||||||
|
@ -586,7 +576,7 @@ class InstallBackend():
|
||||||
resolver.protect(pkg_cache)
|
resolver.protect(pkg_cache)
|
||||||
|
|
||||||
resolver.resolve()
|
resolver.resolve()
|
||||||
return delete_pkgs,delete_desc
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(str(e))
|
logging.error(str(e))
|
||||||
pkg_string = ''
|
pkg_string = ''
|
||||||
|
@ -785,6 +775,8 @@ class InstallBackend():
|
||||||
error_desc = get_error_description_from_enum(ERROR_UPDATE_NET_AUTHENTICATION)
|
error_desc = get_error_description_from_enum(ERROR_UPDATE_NET_AUTHENTICATION)
|
||||||
elif ERROR_UPDATE_NOTREAD_SOURCES in self.aptd_base.error_details:
|
elif ERROR_UPDATE_NOTREAD_SOURCES in self.aptd_base.error_details:
|
||||||
error_desc = get_error_description_from_enum(ERROR_UPDATE_NOTREAD_SOURCES)
|
error_desc = get_error_description_from_enum(ERROR_UPDATE_NOTREAD_SOURCES)
|
||||||
|
elif ERROR_UPDATE_INVALID_TIME in self.aptd_base.error_details:
|
||||||
|
error_desc = get_error_description_from_enum(ERROR_UPDATE_INVALID_TIME)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
#开始生成列表
|
#开始生成列表
|
||||||
|
@ -1088,9 +1080,13 @@ def get_backend(*args, **kwargs):
|
||||||
"aptdaemon or synaptic")
|
"aptdaemon or synaptic")
|
||||||
|
|
||||||
class InhibitShutdownLock():
|
class InhibitShutdownLock():
|
||||||
|
# 禁止关机锁文件路径
|
||||||
|
FILELOCK_PATH = "/tmp/lock/"
|
||||||
|
SHUTDOWN_BLOCK_FILELOCK = "kylin-update.lock"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.inhibit_lock = None
|
self.inhibit_lock = None
|
||||||
|
self.pidfile = None
|
||||||
|
|
||||||
#安装时禁止关机 进行加锁
|
#安装时禁止关机 进行加锁
|
||||||
def lock(self, caller='Kylin System Updater'):
|
def lock(self, caller='Kylin System Updater'):
|
||||||
|
@ -1111,6 +1107,8 @@ class InhibitShutdownLock():
|
||||||
'block')),
|
'block')),
|
||||||
None, 0, -1, None, None)
|
None, 0, -1, None, None)
|
||||||
self.inhibit_lock = Gio.UnixInputStream(fd=fdlist.steal_fds()[var[0]])
|
self.inhibit_lock = Gio.UnixInputStream(fd=fdlist.steal_fds()[var[0]])
|
||||||
|
|
||||||
|
self.LockedPreventShutdown()
|
||||||
logging.info("Shutdown Has been locked...")
|
logging.info("Shutdown Has been locked...")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
|
@ -1118,6 +1116,7 @@ class InhibitShutdownLock():
|
||||||
#解锁禁止关机
|
#解锁禁止关机
|
||||||
def unlock(self):
|
def unlock(self):
|
||||||
try:
|
try:
|
||||||
|
self.unLockedEnableShutdown()
|
||||||
if self.inhibit_lock != None:
|
if self.inhibit_lock != None:
|
||||||
self.inhibit_lock.close()
|
self.inhibit_lock.close()
|
||||||
self.inhibit_lock == None
|
self.inhibit_lock == None
|
||||||
|
@ -1125,4 +1124,59 @@ class InhibitShutdownLock():
|
||||||
else:
|
else:
|
||||||
logging.info("Not locked and Quitting ...")
|
logging.info("Not locked and Quitting ...")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("unlock failed." + str(e))
|
logging.error("unlock failed." + str(e))
|
||||||
|
|
||||||
|
#安装时禁止关机 进行加锁
|
||||||
|
def LockedPreventShutdown(self):
|
||||||
|
|
||||||
|
#不为空是表示以及被锁
|
||||||
|
if self.pidfile != None:
|
||||||
|
logging.error("self.pidfile file disc not is None,Has been locked...")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not os.path.exists(self.FILELOCK_PATH):
|
||||||
|
#不存在创建
|
||||||
|
logging.info("File(%s) is not exists and will be create",self.FILELOCK_PATH)
|
||||||
|
os.makedirs(self.FILELOCK_PATH)
|
||||||
|
else:
|
||||||
|
#当目录存在时进行删除 不删除进行创建文件的话会报错
|
||||||
|
# file cannot be locked.[Errno 11] Resource temporarily unavailable
|
||||||
|
# 资源被占用报错
|
||||||
|
shutil.rmtree(self.FILELOCK_PATH)
|
||||||
|
logging.info("File(%s) is exists and will be delete and create",self.FILELOCK_PATH)
|
||||||
|
os.makedirs(self.FILELOCK_PATH)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.pidfile = open(os.path.join(self.FILELOCK_PATH, self.SHUTDOWN_BLOCK_FILELOCK), "w+")
|
||||||
|
fcntl.flock(self.pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("file cannot be locked." + str(e))
|
||||||
|
self.pidfile.close()
|
||||||
|
self.pidfile = None
|
||||||
|
return False
|
||||||
|
|
||||||
|
#解锁禁止关机
|
||||||
|
def unLockedEnableShutdown(self):
|
||||||
|
#未加锁退出
|
||||||
|
if not self.pidfile:
|
||||||
|
logging.info("Not locked and Quitting ...")
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
fcntl.flock(self.pidfile, fcntl.LOCK_UN)
|
||||||
|
self.pidfile.close()
|
||||||
|
self.pidfile = None
|
||||||
|
|
||||||
|
# Fix 修复权限问题 当普通用户无法使用 所以直接删除目录
|
||||||
|
if os.path.exists(self.FILELOCK_PATH):
|
||||||
|
shutil.rmtree(self.FILELOCK_PATH)
|
||||||
|
logging.info('Emptying the lockPath(%s) is complete...',self.FILELOCK_PATH)
|
||||||
|
else:
|
||||||
|
logging.info("Emptying the lockPath(%s) is Failed...",self.FILELOCK_PATH)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("unlock failed." + str(e))
|
||||||
|
self.pidfile.close()
|
||||||
|
self.pidfile = None
|
||||||
|
return False
|
|
@ -1,13 +1,13 @@
|
||||||
|
|
||||||
[autoUpgradePolicy]
|
[autoUpgradePolicy]
|
||||||
#自动更新的开关
|
#自动更新的开关
|
||||||
autoUpgradeState = on
|
autoUpgradeState = off
|
||||||
|
|
||||||
#预下载开关
|
#预下载开关
|
||||||
preDownload = on
|
preDownload = off
|
||||||
|
|
||||||
# 预下载的时间为时间段 例如:10:00-11:00
|
# 预下载的时间为时间段 例如:10:00-11:00
|
||||||
preDownloadTime = 10:00-11:00
|
preDownloadTime = 10:00
|
||||||
|
|
||||||
#添加检查更新的周期 以天为单位
|
#添加检查更新的周期 以天为单位
|
||||||
updateDays = 1
|
updateDays = 1
|
||||||
|
@ -16,10 +16,10 @@ updateDays = 1
|
||||||
downloadMode = timing
|
downloadMode = timing
|
||||||
|
|
||||||
# 下载的时间为时间段 例如:10:00-11:00
|
# 下载的时间为时间段 例如:10:00-11:00
|
||||||
downloadTime = 10:00-11:00
|
downloadTime = 10:00
|
||||||
|
|
||||||
#安装存在定时timing 手动:manual 关机安装bshutdown
|
#安装存在定时timing 手动:manual 关机安装bshutdown
|
||||||
installMode = bshutdown
|
installMode = timing
|
||||||
|
|
||||||
#安装也为时间段 例如:00:00
|
#安装也为时间段 例如:00:00
|
||||||
installTime = 10:00
|
installTime = 10:00
|
||||||
|
|
|
@ -2754,4 +2754,7 @@ msgid "Upgrade System"
|
||||||
msgstr "全盘升级"
|
msgstr "全盘升级"
|
||||||
|
|
||||||
msgid "kylin-unattended-upgrade"
|
msgid "kylin-unattended-upgrade"
|
||||||
msgstr "自动更新"
|
msgstr "自动更新"
|
||||||
|
|
||||||
|
msgid "Please check the system time and synchronize the system time before updating."
|
||||||
|
msgstr "请检查系统时间,同步系统时间后再进行更新。"
|
|
@ -2687,4 +2687,7 @@ msgid "Upgrade System"
|
||||||
msgstr "全盤升級"
|
msgstr "全盤升級"
|
||||||
|
|
||||||
msgid "kylin-unattended-upgrade"
|
msgid "kylin-unattended-upgrade"
|
||||||
msgstr "自動更新"
|
msgstr "自動更新"
|
||||||
|
|
||||||
|
msgid "Please check the system time and synchronize the system time before updating."
|
||||||
|
msgstr "請檢查系統時間,同步系統時間后再進行更新。"
|
|
@ -2719,4 +2719,7 @@ msgid "Upgrade System"
|
||||||
msgstr "全盤升級"
|
msgstr "全盤升級"
|
||||||
|
|
||||||
msgid "kylin-unattended-upgrade"
|
msgid "kylin-unattended-upgrade"
|
||||||
msgstr "自動更新"
|
msgstr "自動更新"
|
||||||
|
|
||||||
|
msgid "Please check the system time and synchronize the system time before updating."
|
||||||
|
msgstr "請檢查系統時間,同步系統時間后再進行更新。"
|
Loading…
Reference in New Issue