openlp/openlp/core/version.py

203 lines
8.5 KiB
Python
Raw Normal View History

2017-06-17 08:51:01 +00:00
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 OpenLP Developers #
# --------------------------------------------------------------------------- #
# 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; version 2 of the License. #
# #
# 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 #
###############################################################################
"""
2017-09-09 05:19:22 +00:00
The :mod:`openlp.core.version` module downloads the version details for OpenLP.
2017-06-17 08:51:01 +00:00
"""
2016-04-04 19:53:54 +00:00
import logging
import os
import platform
import sys
import time
from datetime import date
2016-04-04 19:53:54 +00:00
from distutils.version import LooseVersion
from subprocess import Popen, PIPE
2017-09-09 05:19:22 +00:00
import requests
2016-04-04 19:53:54 +00:00
from PyQt5 import QtCore
2017-10-07 07:05:07 +00:00
from openlp.core.common.applocation import AppLocation
from openlp.core.common.settings import Settings
2017-09-09 05:19:22 +00:00
from openlp.core.threading import run_thread
2016-07-01 21:17:20 +00:00
2016-04-04 19:53:54 +00:00
log = logging.getLogger(__name__)
APPLICATION_VERSION = {}
CONNECTION_TIMEOUT = 30
CONNECTION_RETRIES = 2
2017-09-09 05:19:22 +00:00
class VersionWorker(QtCore.QObject):
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
A worker class to fetch the version of OpenLP from the website. This is run from within a thread so that it
doesn't affect the loading time of OpenLP.
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
new_version = QtCore.pyqtSignal(dict)
no_internet = QtCore.pyqtSignal()
quit = QtCore.pyqtSignal()
def __init__(self, last_check_date, current_version):
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
Constructor for the version check worker.
2016-04-04 19:53:54 +00:00
2017-09-09 05:19:22 +00:00
:param string last_check_date: The last day we checked for a new version of OpenLP
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
log.debug('VersionWorker - Initialise')
super(VersionWorker, self).__init__(None)
self.last_check_date = last_check_date
self.current_version = current_version
2016-04-04 19:53:54 +00:00
2017-09-09 05:19:22 +00:00
def start(self):
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
Check the latest version of OpenLP against the version file on the OpenLP site.
**Rules around versions and version files:**
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
* If a version number's minor version is an odd number, it is a development release.
* If a version number's minor version is an even number, it is a stable release.
2016-04-04 19:53:54 +00:00
"""
2017-09-09 05:19:22 +00:00
log.debug('VersionWorker - Start')
# I'm not entirely sure why this was here, I'm commenting it out until I hit the same scenario
time.sleep(1)
2017-09-09 05:19:22 +00:00
download_url = 'http://www.openlp.org/files/version.txt'
if self.current_version['build']:
2017-09-09 05:19:22 +00:00
download_url = 'http://www.openlp.org/files/nightly_version.txt'
elif int(self.current_version['version'].split('.')[1]) % 2 != 0:
2017-09-09 05:19:22 +00:00
download_url = 'http://www.openlp.org/files/dev_version.txt'
headers = {
'User-Agent': 'OpenLP/{version} {system}/{release}; '.format(version=self.current_version['full'],
2017-09-09 05:19:22 +00:00
system=platform.system(),
release=platform.release())
}
remote_version = None
retries = 0
while retries < 3:
try:
response = requests.get(download_url, headers=headers)
remote_version = response.text
log.debug('New version found: %s', remote_version)
break
except IOError:
2017-09-09 05:19:22 +00:00
log.exception('Unable to connect to OpenLP server to download version file')
retries += 1
else:
self.no_internet.emit()
if remote_version and LooseVersion(remote_version) > LooseVersion(self.current_version['full']):
2017-09-09 05:19:22 +00:00
self.new_version.emit(remote_version)
self.quit.emit()
def update_check_date():
"""
Save when we last checked for an update
"""
Settings().setValue('core/last version test', date.today().strftime('%Y-%m-%d'))
2017-09-09 05:19:22 +00:00
def check_for_update(parent):
"""
Run a thread to download and check the version of OpenLP
:param MainWindow parent: The parent object for the thread. Usually the OpenLP main window.
"""
last_check_date = Settings().value('core/last version test')
if date.today().strftime('%Y-%m-%d') <= last_check_date:
2017-09-09 05:19:22 +00:00
log.debug('Version check skipped, last checked today')
return
worker = VersionWorker(last_check_date, get_version())
2017-09-09 05:19:22 +00:00
worker.new_version.connect(parent.on_new_version)
worker.quit.connect(update_check_date)
2017-09-09 05:19:22 +00:00
# TODO: Use this to figure out if there's an Internet connection?
# worker.no_internet.connect(parent.on_no_internet)
run_thread(parent, worker, 'version')
def get_version():
2016-04-04 19:53:54 +00:00
"""
Returns the application version of the running instance of OpenLP::
{'full': '1.9.4-bzr1249', 'version': '1.9.4', 'build': 'bzr1249'}
"""
global APPLICATION_VERSION
if APPLICATION_VERSION:
return APPLICATION_VERSION
if '--dev-version' in sys.argv or '-d' in sys.argv:
# NOTE: The following code is a duplicate of the code in setup.py. Any fix applied here should also be applied
# there.
# Get the revision of this tree.
bzr = Popen(('bzr', 'revno'), stdout=PIPE)
tree_revision, error = bzr.communicate()
tree_revision = tree_revision.decode()
code = bzr.wait()
if code != 0:
raise Exception('Error running bzr log')
# Get all tags.
bzr = Popen(('bzr', 'tags'), stdout=PIPE)
output, error = bzr.communicate()
code = bzr.wait()
if code != 0:
raise Exception('Error running bzr tags')
tags = list(map(bytes.decode, output.splitlines()))
if not tags:
tag_version = '0.0.0'
tag_revision = '0'
else:
# Remove any tag that has "?" as revision number. A "?" as revision number indicates, that this tag is from
# another series.
tags = [tag for tag in tags if tag.split()[-1].strip() != '?']
# Get the last tag and split it in a revision and tag name.
tag_version, tag_revision = tags[-1].split()
# If they are equal, then this tree is tarball with the source for the release. We do not want the revision
# number in the full version.
if tree_revision == tag_revision:
full_version = tag_version.strip()
else:
full_version = '{tag}-bzr{tree}'.format(tag=tag_version.strip(), tree=tree_revision.strip())
2016-04-04 19:53:54 +00:00
else:
# We're not running the development version, let's use the file.
2017-08-01 20:59:41 +00:00
file_path = str(AppLocation.get_directory(AppLocation.VersionDir))
2016-04-04 19:53:54 +00:00
file_path = os.path.join(file_path, '.version')
version_file = None
try:
version_file = open(file_path, 'r')
full_version = str(version_file.read()).rstrip()
except IOError:
log.exception('Error in version file.')
full_version = '0.0.0-bzr000'
finally:
if version_file:
version_file.close()
bits = full_version.split('-')
APPLICATION_VERSION = {
'full': full_version,
'version': bits[0],
'build': bits[1] if len(bits) > 1 else None
}
if APPLICATION_VERSION['build']:
log.info('Openlp version {version} build {build}'.format(version=APPLICATION_VERSION['version'],
build=APPLICATION_VERSION['build']))
2016-04-04 19:53:54 +00:00
else:
log.info('Openlp version {version}'.format(version=APPLICATION_VERSION['version']))
2016-04-04 19:53:54 +00:00
return APPLICATION_VERSION