Commit 615c112c authored by Дмитрий Никулин's avatar Дмитрий Никулин Committed by Никита Ефремов

Last system update: change implementation

parent 03eff2b0
...@@ -7,6 +7,7 @@ from settingsd import config ...@@ -7,6 +7,7 @@ from settingsd import config
from settingsd import service from settingsd import service
from settingsd import shared from settingsd import shared
from settingsd.tools.process import execProcess from settingsd.tools.process import execProcess
from file_read_backwards import FileReadBackwards
INTERFACE_NAME = "packageUpdates" INTERFACE_NAME = "packageUpdates"
...@@ -22,8 +23,6 @@ PACKAGE_REGEX = re.compile(r'^(\S+)/\S+') ...@@ -22,8 +23,6 @@ PACKAGE_REGEX = re.compile(r'^(\S+)/\S+')
MULTIPLE_SPACES_REGEX = re.compile(r'\s{2,}') MULTIPLE_SPACES_REGEX = re.compile(r'\s{2,}')
HISTORY_BLOCK_SIZE = 2 ** 16 # bytes
class PackageUpdates(service.FunctionObject) : class PackageUpdates(service.FunctionObject) :
@service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="as") @service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="as")
...@@ -34,21 +33,12 @@ class PackageUpdates(service.FunctionObject) : ...@@ -34,21 +33,12 @@ class PackageUpdates(service.FunctionObject) :
@service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="i") @service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="i")
def get_last_update_date(self): def get_last_update_date(self):
with open('/var/log/apt/history.log', 'r') as apt_history_file: with FileReadBackwards('/var/log/apt/history.log') as apt_history_file:
apt_history_file.seek(0, os.SEEK_END) for block in self._read_apt_blocks(apt_history_file):
file_size = apt_history_file.tell() result = self._try_extract_upgrade_date(block)
full_block_count = file_size // HISTORY_BLOCK_SIZE
block = 0
while True:
offset = 0 if block >= full_block_count else file_size - HISTORY_BLOCK_SIZE * (block + 1)
result = self._try_extract_upgrade_date(apt_history_file, offset, file_size)
if result: if result:
return result.timestamp() return result.timestamp()
return 0
if block < full_block_count:
block += 1
else:
return 0
@service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="") @service.functionMethod(INTERFACE_NAME, in_signature="", out_signature="")
def install_updates(self): def install_updates(self):
...@@ -68,16 +58,15 @@ class PackageUpdates(service.FunctionObject) : ...@@ -68,16 +58,15 @@ class PackageUpdates(service.FunctionObject) :
fields[parts[0].strip()] = parts[1].strip() fields[parts[0].strip()] = parts[1].strip()
return fields return fields
def _parse_apt_operations(self, blocks): def _parse_apt_operation(self, block):
operations = [] fields = self._parse_apt_block(block)
for block in blocks: if all(key in fields for key in ('Start-Date', 'Commandline', 'End-Date')):
fields = self._parse_apt_block(block) return {
if all(key in fields for key in ('Start-Date', 'Commandline', 'End-Date')): 'startDate': self._parse_date(fields['Start-Date']),
operations.append({ 'command': self._parse_command(fields['Commandline'])
'startDate': self._parse_date(fields['Start-Date']), }
'command': self._parse_command(fields['Commandline']) else:
}) raise ValueError('Non-full apt operation block: ' + block)
return operations
def _parse_command(self, commandline): def _parse_command(self, commandline):
words = [w for w in commandline.split(' ') if len(w) and not w.startswith('-')] words = [w for w in commandline.split(' ') if len(w) and not w.startswith('-')]
...@@ -89,22 +78,24 @@ class PackageUpdates(service.FunctionObject) : ...@@ -89,22 +78,24 @@ class PackageUpdates(service.FunctionObject) :
date_str = MULTIPLE_SPACES_REGEX.sub(' ', date_str) date_str = MULTIPLE_SPACES_REGEX.sub(' ', date_str)
return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
def _read_apt_blocks(self, apt_history_file, offset, block_size): def _read_apt_blocks(self, apt_history_file):
apt_history_file.seek(offset, os.SEEK_SET) block = []
data = apt_history_file.read(block_size) for line in apt_history_file:
return data.split('\n\n') if line == '':
if len(block):
def _try_extract_upgrade_date(self, apt_history_file, offset, file_size): yield '\n'.join(block[::-1])
limit = max(file_size - offset, HISTORY_BLOCK_SIZE * 2) + 1 block = []
for block_size in range(HISTORY_BLOCK_SIZE * 2, limit, HISTORY_BLOCK_SIZE): continue
apt_operation_blocks = self._read_apt_blocks(apt_history_file, offset, block_size)
apt_operations = self._parse_apt_operations(apt_operation_blocks) block.append(line)
if len(apt_operations):
break def _try_extract_upgrade_date(self, block):
operation = self._parse_apt_operation(block)
for operation in apt_operations[::-1]:
if operation['command'] == 'upgrade': if operation['command'] == 'upgrade' or operation['command'] == 'dist-upgrade':
return operation['startDate'] return operation['startDate']
return None
class Service(service.Service) : class Service(service.Service) :
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment