Skip to content

Commit

Permalink
New version detection system, with update summary.
Browse files Browse the repository at this point in the history
Updated version check now uses GitHub's release system and doesn't rely
any more on the version.py file, which is only used internally and for
binary purposes.
A version information dialog has been added, which reports the contents
of the release data on GitHub.
python-midi module has been moved to bigglesworth/libs/ along with the
markdown module used for the version information parsing.
  • Loading branch information
MaurizioB committed May 21, 2017
1 parent 53de6fc commit a483333
Show file tree
Hide file tree
Showing 21 changed files with 3,035 additions and 60 deletions.
78 changes: 48 additions & 30 deletions bigglesworth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
def process_args():
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--sysex', help='Print output SysEx messages to the terminal', action='store_true')
parser.add_argument('--rtmidi', help='Use rtmidi interface (mandatory for Windows)', action='store_true')
parser.add_argument('-l', '--library-limit', metavar='N', type=int, help='Limit library to N sounds')
parser.add_argument('--rtmidi', help='Use rtmidi interface (mandatory for OSX/Windows, not recommended for Linux)', action='store_true')
parser.add_argument('-l', '--library-limit', metavar='N', type=int, help=argparse.SUPPRESS)
parser.add_argument('-w', '--wavetable', metavar='WTFILE', nargs='?', const=True, help='Open Wavetable editor (with optional WTFILE)')
parser.add_argument('-e', '--editor', metavar='BXXX', nargs='?', const=True, help='Open Sound editor (with INIT sound or optional sound XXX from bank B, eg. A001)')
res, unknown = parser.parse_known_args()
Expand Down Expand Up @@ -130,6 +130,8 @@ def __init__(self, app, args):
self.deviceAction.triggered.connect(self.device_request)
self.globalsAction = self.librarian.globalsAction
self.globalsAction.triggered.connect(self.globals_request)
self.updateCheckAction = self.librarian.updateCheckAction
self.updateCheckAction.triggered.connect(lambda: self.update_check(silent=False))

self.midi_duplex_state_change.connect(self.globalsAction.setEnabled)

Expand Down Expand Up @@ -286,8 +288,12 @@ def __init__(self, app, args):
if args.editor:
self.startup_show_editor(args.editor)

if self.settings.gGeneral.get_ShowUpdates(True):
self.startup_version_check()
self.version_request_dialog = VersionRequestDialog(self.librarian)
self.updated_dialog = UpdatedDialog(self, self.librarian)
self.updated_dialog.never_chk.toggled.connect(lambda state: self.settings.gGeneral.set_StartupUpdateCheck(not state))
self.create_version_request()
if self.startup_version_check:
self.update_check(silent=True)
# QtGui.QMessageBox.information(self.librarian, 'Test build', 'This is a test build!!! Have fun!')

def wavetable_show(self, uid=None):
Expand Down Expand Up @@ -316,7 +322,6 @@ def new_wavetable(self, uid=None, wavetable_data=None):
wavetable_window.newWavetableAction.triggered.connect(lambda _: self.new_wavetable())
return wavetable_window


def startup_show_editor(self, data):
def show_editor():
self.loader.loaded.disconnect(show_editor)
Expand All @@ -338,31 +343,32 @@ def show_editor():
prog = 127
sound = bank, prog

def startup_version_check(self, active=False):
def open_site(url):
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))
dialog.accept()
self.version_check = VersionCheck(self)
def create_version_request(self, silent=True):
self.version_request = VersionRequest(self)
self.version_thread = QtCore.QThread()
self.version_check.moveToThread(self.version_thread)
self.version_thread.started.connect(self.version_check.run)
self.version_check.done.connect(self.version_thread.quit)
self.version_thread.start()
dialog = QtGui.QMessageBox(
QtGui.QMessageBox.Information, 'New version',
'A new version is available, go to the <a href="https://github.com/MaurizioB/Bigglesworth">website</a> for updates!',
QtGui.QMessageBox.Ok,
self.librarian
)
labels = dialog.findChildren(QtGui.QLabel)
label = [l for l in labels if l.text().startsWith('A new version')][0]
label.setOpenExternalLinks(False)
label.linkActivated.connect(open_site)
layout = dialog.layout()
never_chk = QtGui.QCheckBox('Never display this message again')
never_chk.toggled.connect(lambda state: self.settings.gGeneral.set_ShowUpdates(not state))
layout.addWidget(never_chk, layout.rowCount(), 0, 1, layout.columnCount())
self.version_check.update.connect(lambda update: dialog.exec_() if update else None)
self.version_request.moveToThread(self.version_thread)
self.version_thread.started.connect(self.version_request.run)
self.version_request.done.connect(self.version_thread.quit)
self.version_request.done.connect(self.version_request_dialog.hide)
self.version_request.error.connect(self.version_request_dialog.hide)
self.version_request_dialog.rejected.connect(self.version_request.stop)

def update_check(self, silent=False):
if not self.version_thread.isRunning():
if self.version_thread.isFinished():
self.create_version_request(silent)
self.version_thread.start()
try:
self.version_request.updated.disconnect()
except:
pass
if not silent:
self.version_request_dialog.show()
self.version_request.setSilent(False)
self.version_request.updated.connect(lambda updated, content: self.updated_dialog.exec_(content))
self.updated_dialog.never_chk.setVisible(False)
else:
self.version_request.updated.connect(lambda updated, content: self.updated_dialog.exec_(content) if updated else None)

def show_settings(self):
self.settings_dialog.exec_()
Expand Down Expand Up @@ -434,6 +440,19 @@ def blofeld_id(self, value):
def source_library(self):
return self.settings.gGeneral.get_Source_Library('personal')

@property
def startup_version_check(self):
try:
return self._startup_version_check
except:
self._startup_version_check = self.settings.gGeneral.get_StartupUpdateCheck(True)
return self._startup_version_check

@startup_version_check.setter
def startup_version_check(self, value):
self.settings.gGeneral.set_StartupUpdateCheck(value)
self._startup_version_check = value

@property
def library_doubleclick(self):
try:
Expand Down Expand Up @@ -1135,7 +1154,6 @@ def sound_drop_event(self, event):
def rename(sound_range):
first = min(sound_range)
last = max(sound_range)
# print first, last
for row in range(first, last+1):
bank, prog = divmod(row, 128)
self.blofeld_model.item(row, BANK).setText(uppercase[bank])
Expand Down
128 changes: 103 additions & 25 deletions bigglesworth/classes.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,144 @@
# *-* coding: utf-8 *-*

import urllib2
import re
import pickle
import simplejson

from uuid import uuid4
from os import path, makedirs
from itertools import chain
from shutil import copy
from string import uppercase, ascii_letters
from PyQt4 import QtCore, QtGui

import midifile
from bigglesworth.libs import midifile
from bigglesworth.libs import markdown2
from bigglesworth.const import *
from bigglesworth import version
from bigglesworth.version import *

pow21 = 2**21

class VersionCheck(QtCore.QObject):
url = 'https://github.com/MaurizioB/Bigglesworth/raw/master/bigglesworth/version.py'
v_maj = version.MAJ_VERSION
v_min = version.MIN_VERSION
v_rev = version.REV_VERSION
class VersionRequest(QtCore.QObject):
release_url = 'https://api.github.com/repos/MaurizioB/Bigglesworth/releases'
res = QtCore.pyqtSignal(object)
error = QtCore.pyqtSignal()
done = QtCore.pyqtSignal()
update = QtCore.pyqtSignal(bool)
updated = QtCore.pyqtSignal(bool, object)

def __init__(self, main):
QtCore.QObject.__init__(self)
self.main = main
self.silent = True
self.timer = QtCore.QTimer()
self.timer.setInterval(30000)
self.timer.timeout.connect(self.error.emit)

def run(self):
self.ignore = False
self.timer.start()
try:
try:
res = urllib2.urlopen(self.url)
res = urllib2.urlopen(self.release_url)
self.timer.stop()
exec(res.read())
self.check(MAJ_VERSION, MIN_VERSION, REV_VERSION)
self.check(simplejson.loads(res.read()))
except:
self.timer.stop()
self.error.emit()
except:
self.timer.stop()
self.error.emit()
self.done.emit()

def check(self, v_maj, v_min, v_rev):
# print 'Current: {}.{}.{}'.format(self.v_maj, self.v_min, self.v_rev)
# print '{}.{}.{}'.format(v_maj, v_min, v_rev)
# print type(self.v_maj), type(v_maj)
if (self.v_maj, self.v_min, self.v_rev) == (v_maj, v_min, v_rev):
self.update.emit(False)
return
current = (self.v_maj << 32) + (self.v_min << 16) + self.v_rev
remote = (v_maj << 32) + (v_min << 16) + v_rev
if current > remote:
self.update.emit(False)
if not self.ignore:
self.done.emit()

def stop(self):
self.ignore = True

def check(self, contents):
def newer_check(check_txt):
check_maj, check_min, check_rev = map(int, check_txt.split('.'))
if check_maj > MAJ_VERSION:
return True
if check_min > MIN_VERSION:
return True
if check_rev > REV_VERSION:
return True
return False

html = ''
previous = []
older = []
latest = contents[0]['tag_name']
is_newer = False

if not newer_check(latest):
if self.silent:
self.updated.emit(False, None)
return
html += '<div="summary"><h1>You are running the latest version!</h1>'
else:
self.update.emit(True)
is_newer = True
html += '<div="summary"><h1>A new version is available!</h1>'
html += '<a href="#{tag}">Read more about version {tag}</a>'.format(tag=latest)
for release in contents[1:]:
tag = release['tag_name']
if newer_check(tag):
previous.append(tag)
else:
older.append(tag)
if previous:
html += '<h3>Previous versions (yet newer than the current:)</h3><ul>'
for tag in previous:
html += '<li><a href="#{tag}">{tag}</a></li>'.format(tag=tag)
html += '</ul>'
if older:
html += '<h3>Older versions:</h3><ul>'
for tag in older:
html += '<li><a href="#{tag}">{tag}</a></li>'.format(tag=tag)
html += '</ul>'
html += '</div><hr />'

older_tag = False
for i, release in enumerate(contents):
tag = release['tag_name']
# if tag != latest and not newer_check(tag) and not older_tag:
if tag != latest and not older_tag:
html += '<font color="gray">'
html += '<h2>Older versions:</h2>'
older_tag = True
name = release['name']
if name.startswith(tag):
name = name[len(tag):].lstrip(' - ')
html += '<a name={tag}></a><div class="version">{tag}<span style="font-weight: normal;"> - {name}</span></div>'.format(tag=tag, name=name)
date = QtCore.QDateTime.fromString(release['published_at'], 'yyyy-MM-ddTHH:mm:ssZ').toString('dd/MM/yyyy')
html += u'<div class="release">Release date: {date}<br />'.format(date=unicode(date.toUtf8(), encoding='utf-8'))
html += 'Availability: <ul>'
html += '<li>Linux (source): <a href="{tar}">tar</a>, <a href="{zip}">zip</a></li>'
for asset in release['assets']:
file_name = asset['name'].lower()
if file_name.endswith('.exe') or file_name.endswith('.msi'):
os = 'Windows'
elif file_name.endswith('.dmg'):
os = 'OSX'
html += u'<li>{os}: <a href="{url}">Direct link</a></li>'.format(os=os, url=asset['browser_download_url'])
html += '</ul>'
html += '</div>'
md = markdown2.Markdown(extras=['cuddled-lists'])
body = md.convert(re.sub(r'(?<=[a-zA-Z0-9\.\;])\r?\n(?<![a-zA-Z0-9])', ' \n', release['body']))
html += u'<div class="content">{body}</div>'.format(body=body)
if i < len(contents) - 1:
html += '<hr />'
else:
html += '<br />'
if older_tag:
html += '</font>'
self.updated.emit(is_newer, html)

def setSilent(self, silent):
self.silent = silent

def release_check(self, res):
pass


class Wavetable(QtCore.QObject):
Expand Down
1 change: 1 addition & 0 deletions bigglesworth/dialogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
from bigglesworth.dialogs.file_open import *
from bigglesworth.dialogs.wave_import import *
from bigglesworth.dialogs.wavetable_list import *
from bigglesworth.dialogs.update import *
2 changes: 1 addition & 1 deletion bigglesworth/dialogs/file_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from bigglesworth.classes import Sound, Wavetable
from bigglesworth.const import *
from bigglesworth import midifile
from bigglesworth.libs import midifile


ALLFILE = MIDFILE|SYXFILE
Expand Down
2 changes: 1 addition & 1 deletion bigglesworth/dialogs/midi_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from bigglesworth.utils import load_ui, setBold
from bigglesworth.const import sound_headers, categories, Params, BANK, NAME, PROG, CATEGORY, STORED, ValuesRole, EditedRole
from bigglesworth.classes import Sound
from bigglesworth import midifile
from bigglesworth.libs import midifile

_UNCHANGED, _MINIMUM, _MAXIMUM = None, 0, -1

Expand Down
6 changes: 6 additions & 0 deletions bigglesworth/dialogs/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ def exec_(self):
self.blofeld_autoconnect_chk.setChecked(self.main.blofeld_autoconnect)
self.remember_connections_chk.setChecked(self.main.remember_connections)

#General
self.startup_version_chk.setChecked(self.main.startup_version_check)

#EXEC
res = QtGui.QDialog.exec_(self)
if not res: return
Expand Down Expand Up @@ -167,3 +170,6 @@ def exec_(self):
self.main.blofeld_id = self.deviceID_spin.value()
self.main.blofeld_autoconnect = self.blofeld_autoconnect_chk.isChecked()
self.main.remember_connections = self.remember_connections_chk.isChecked()

self.main.startup_version_check = self.startup_version_chk.isChecked()

35 changes: 34 additions & 1 deletion bigglesworth/dialogs/settings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,9 @@
<string>MIDI</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>4</number>
</property>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
Expand Down Expand Up @@ -752,6 +755,36 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="app_tab">
<attribute name="title">
<string>Application settings</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_12">
<property name="margin">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="startup_version_chk">
<property name="text">
<string>Check for updates on startup</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
Expand Down Expand Up @@ -883,8 +916,8 @@
</connections>
<buttongroups>
<buttongroup name="editor_appearance_efx_arp_group"/>
<buttongroup name="midi_backend_group"/>
<buttongroup name="editor_appearance_filter_matrix_group"/>
<buttongroup name="preset_group"/>
<buttongroup name="midi_backend_group"/>
</buttongroups>
</ui>
Loading

0 comments on commit a483333

Please sign in to comment.