176 lines
6.8 KiB
Python
176 lines
6.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vi:si:et:sw=4:sts=4:ts=4
|
|
|
|
|
|
from contextlib import closing
|
|
import json
|
|
import os
|
|
import tarfile
|
|
import urllib.request, urllib.error, urllib.parse
|
|
import shutil
|
|
import subprocess
|
|
|
|
import ed25519
|
|
import ox
|
|
from oxtornado import actions
|
|
|
|
import settings
|
|
|
|
|
|
ENCODING='base64'
|
|
|
|
def verify(release):
|
|
vk = ed25519.VerifyingKey(settings.OML_UPDATE_KEY, encoding=ENCODING)
|
|
value = []
|
|
for module in sorted(release['modules']):
|
|
value += [str('%s/%s' % (release['modules'][module]['version'], release['modules'][module]['sha1']))]
|
|
value = '\n'.join(value)
|
|
value = value.encode()
|
|
sig = release['signature'].encode()
|
|
try:
|
|
vk.verify(sig, value, encoding=ENCODING)
|
|
except ed25519.BadSignatureError:
|
|
return False
|
|
return True
|
|
|
|
def get(url, filename=None):
|
|
request = urllib.request.Request(url, headers={
|
|
'User-Agent': settings.USER_AGENT
|
|
})
|
|
with closing(urllib.request.urlopen(request)) as u:
|
|
if not filename:
|
|
data = u.read()
|
|
return data
|
|
else:
|
|
dirname = os.path.dirname(filename)
|
|
if dirname and not os.path.exists(dirname):
|
|
os.makedirs(dirname)
|
|
with open(filename, 'wb') as fd:
|
|
data = u.read(4096)
|
|
while data:
|
|
fd.write(data)
|
|
data = u.read(4096)
|
|
|
|
def check():
|
|
if settings.release:
|
|
release_data = get(settings.server.get('release_url', 'http://downloads.openmedialibrary.com/release.json'))
|
|
release = json.loads(release_data.decode('utf-8'))
|
|
old = current_version('openmedialibrary')
|
|
new = release['modules']['openmedialibrary']['version']
|
|
return verify(release) and old < new
|
|
return False
|
|
|
|
def current_version(module):
|
|
return settings.release['modules'][module]['version'] if module in settings.release['modules'] else ""
|
|
|
|
def download():
|
|
if not os.path.exists(os.path.join(settings.config_path, 'release.json')):
|
|
return True
|
|
release_data = get(settings.server.get('release_url'))
|
|
release = json.loads(release_data.decode('utf-8'))
|
|
if verify(release):
|
|
ox.makedirs(settings.updates_path)
|
|
os.chdir(os.path.dirname(settings.base_dir))
|
|
current_files = {'release.json'}
|
|
for module in release['modules']:
|
|
if release['modules'][module]['version'] > current_version(module):
|
|
module_tar = os.path.join(settings.updates_path, release['modules'][module]['name'])
|
|
base_url = settings.server.get('release_url').rsplit('/', 1)[0]
|
|
url = '/'.join([base_url, release['modules'][module]['name']])
|
|
if not os.path.exists(module_tar):
|
|
print('downloading', os.path.basename(module_tar))
|
|
get(url, module_tar)
|
|
if ox.sha1sum(module_tar) != release['modules'][module]['sha1']:
|
|
os.unlink(module_tar)
|
|
return False
|
|
current_files.add(os.path.basename(module_tar))
|
|
with open(os.path.join(settings.updates_path, 'release.json'), 'wb') as fd:
|
|
fd.write(release_data)
|
|
for f in set(next(os.walk(settings.updates_path))[2])-current_files:
|
|
os.unlink(os.path.join(settings.updates_path, f))
|
|
return True
|
|
return True
|
|
|
|
def install():
|
|
if not os.path.exists(os.path.join(settings.updates_path, 'release.json')):
|
|
return True
|
|
if not os.path.exists(os.path.join(settings.config_path, 'release.json')):
|
|
return True
|
|
with open(os.path.join(settings.updates_path, 'release.json')) as fd:
|
|
release = json.load(fd)
|
|
old = current_version('openmedialibrary')
|
|
new = release['modules']['openmedialibrary']['version']
|
|
if verify(release) and old < new:
|
|
os.chdir(os.path.dirname(settings.base_dir))
|
|
for module in release['modules']:
|
|
if release['modules'][module]['version'] > current_version(module):
|
|
module_tar = os.path.join(settings.updates_path, release['modules'][module]['name'])
|
|
if os.path.exists(module_tar) and ox.sha1sum(module_tar) == release['modules'][module]['sha1']:
|
|
#tar fails if old platform is moved before extract
|
|
new = '%s_new' % module
|
|
ox.makedirs(new)
|
|
os.chdir(new)
|
|
tar = tarfile.open(module_tar)
|
|
tar.extractall()
|
|
tar.close()
|
|
os.chdir(os.path.dirname(settings.base_dir))
|
|
module_old = '%s_old' % module
|
|
if os.path.exists(module):
|
|
shutil.move(module, module_old)
|
|
shutil.move(os.path.join(new, module), module)
|
|
if os.path.exists(module_old):
|
|
shutil.rmtree(module_old)
|
|
shutil.rmtree(new)
|
|
else:
|
|
os.unlink(module_tar)
|
|
return False
|
|
shutil.copy(os.path.join(settings.updates_path, 'release.json'), os.path.join(settings.config_path, 'release.json'))
|
|
for cmd in [
|
|
['./ctl', 'stop'],
|
|
['./ctl', 'setup'],
|
|
['./ctl', 'postupdate', '-o', old, '-n', new]
|
|
]:
|
|
subprocess.call(cmd)
|
|
return True
|
|
return True
|
|
|
|
def getVersion(data):
|
|
'''
|
|
check if new version is available
|
|
'''
|
|
response = {
|
|
'current': settings.MINOR_VERSION,
|
|
'upgrade': False,
|
|
}
|
|
if settings.MINOR_VERSION == 'git':
|
|
cmd = ['git', 'rev-parse', '@']
|
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
|
stdout, stderr = p.communicate()
|
|
current = stdout.strip()
|
|
cmd = ['git', 'ls-remote', 'origin', '-h', 'refs/heads/master']
|
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=True)
|
|
stdout, stderr = p.communicate()
|
|
new = stdout.strip()[:40]
|
|
response['update'] = current != new
|
|
else:
|
|
if not os.path.exists(os.path.join(settings.updates_path, 'release.json')):
|
|
return response
|
|
if not os.path.exists(os.path.join(settings.config_path, 'release.json')):
|
|
return response
|
|
with open(os.path.join(settings.updates_path, 'release.json')) as fd:
|
|
release = json.load(fd)
|
|
current = current_version('openmedialibrary')
|
|
response['current'] = current
|
|
new = release['modules']['openmedialibrary']['version']
|
|
response['new'] = new
|
|
response['update'] = current < new
|
|
return response
|
|
actions.register(getVersion, cache=False)
|
|
|
|
def restart(data):
|
|
'''
|
|
restart (and upgrade if upgrades are available)
|
|
'''
|
|
subprocess.Popen([os.path.join(settings.base_dir, 'ctl'), 'restart'], close_fds=True)
|
|
return {}
|
|
actions.register(restart, cache=False)
|