Skip to content

Commit 2c68a38

Browse files
committed
Fix update dialog crashing the app when the WebView backend is unusable
On Linux (wxGTK), wx.html2.WebView is backed by WebKitGTK. In the AppImage the bundled Ubuntu build of WebKitGTK fails to spawn its helper processes on other distributions, which aborts the whole application a few seconds after startup (issue #2740). On distributions without webkit2gtk-4.0, even importing wx.html2 fails, which breaks startup from source as well. Never use the WebView on wxGTK and fall back to a plain text release notes widget there. On other platforms guard the WebView creation and fall back to plain text when no backend is available. Also guard ShowUpdateBox so a dialog failure can no longer take down startup, default empty release notes bodies to an empty string and put the release tag in the dialog title instead of a literal '{}'. Behavior on Windows and macOS is unchanged.
1 parent ab5ddaf commit 2c68a38

2 files changed

Lines changed: 109 additions & 39 deletions

File tree

gui/mainFrame.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,16 @@ def getCommandForFit(self, fitID) -> wx.CommandProcessor:
242242
return Fit.getCommandProcessor(fitID)
243243

244244
def ShowUpdateBox(self, release, version):
245-
with UpdateDialog(self, release, version) as dlg:
246-
dlg.ShowModal()
245+
# This runs right after startup, so any failure here must not be able
246+
# to take the whole application down with it
247+
try:
248+
with UpdateDialog(self, release, version) as dlg:
249+
dlg.ShowModal()
250+
except (KeyboardInterrupt, SystemExit):
251+
raise
252+
except Exception as e:
253+
pyfalog.error("Caught exception while showing the update notification dialog")
254+
pyfalog.error(e)
247255

248256
def LoadPreviousOpenFits(self):
249257
sFit = Fit.getInstance()

gui/updateDialog.py

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
import wx
2222
# noinspection PyPackageRequirements
2323
import dateutil.parser
24+
from logbook import Logger
2425
from service.settings import UpdateSettings as svc_UpdateSettings
25-
import wx.html2
2626
import webbrowser
2727
import re
2828
import markdown2
2929

30+
pyfalog = Logger(__name__)
31+
3032
_t = wx.GetTranslation
3133

3234
# HTML template. We link to a bootstrap cdn for quick and easy css, and include some additional teaks.
@@ -51,8 +53,8 @@ class UpdateDialog(wx.Dialog):
5153

5254
def __init__(self, parent, release, version):
5355
super().__init__(
54-
parent, id=wx.ID_ANY, title="pyfa {}" + _t("Update Available"), pos=wx.DefaultPosition,
55-
size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE)
56+
parent, id=wx.ID_ANY, title="pyfa {} - {}".format(release['tag_name'], _t("Update Available")),
57+
pos=wx.DefaultPosition, size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE)
5658

5759
self.UpdateSettings = svc_UpdateSettings.getInstance()
5860
self.releaseInfo = release
@@ -61,42 +63,22 @@ def __init__(self, parent, release, version):
6163
mainSizer = wx.BoxSizer(wx.VERTICAL)
6264

6365
releaseDate = dateutil.parser.parse(self.releaseInfo['published_at'])
66+
releaseNotes = self.releaseInfo.get('body') or ''
6467
notesSizer = wx.BoxSizer(wx.HORIZONTAL)
65-
self.browser = wx.html2.WebView.New(self)
66-
self.browser.Bind(wx.html2.EVT_WEBVIEW_NEWWINDOW, self.OnNewWindow)
67-
68-
link_patterns = [
69-
(re.compile(r"#(\d+)", re.I), r"https://github.com/pyfa-org/Pyfa/issues/\1"),
70-
(re.compile(r"@(\w+)", re.I), r"https://github.com/\1")
71-
]
72-
73-
markdowner = markdown2.Markdown(
74-
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
75-
link_patterns=link_patterns)
76-
77-
release_markup = markdowner.convert(self.releaseInfo['body'])
78-
79-
# run the text through markup again, this time with the hashing pattern. This is required due to bugs in markdown2:
80-
# https://github.com/trentm/python-markdown2/issues/287
81-
link_patterns = [
82-
(re.compile("([0-9a-f]{6,40})", re.I), r"https://github.com/pyfa-org/Pyfa/commit/\1"),
83-
]
8468

85-
markdowner = markdown2.Markdown(
86-
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
87-
link_patterns=link_patterns)
88-
89-
# The space here is required, again, due to bug. Again, see https://github.com/trentm/python-markdown2/issues/287
90-
release_markup = markdowner.convert(' ' + release_markup)
91-
92-
self.browser.SetPage(html_tmpl.format(
93-
self.releaseInfo['tag_name'],
94-
releaseDate.strftime('%B %d, %Y'),
95-
"<p class='text-danger'><b>This is a pre-release, be prepared for unstable features</b></p>" if version.is_prerelease else "",
96-
release_markup
97-
), "")
98-
99-
notesSizer.Add(self.browser, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
69+
self.browser = self.createNotesBrowser(releaseDate, releaseNotes, version)
70+
if self.browser is None:
71+
header = "pyfa {} ({})".format(self.releaseInfo['tag_name'], releaseDate.strftime('%B %d, %Y'))
72+
lines = [header, '=' * len(header), '']
73+
if version.is_prerelease:
74+
lines += [_t("This is a pre-release, be prepared for unstable features"), '']
75+
lines.append(releaseNotes)
76+
self.notesText = wx.TextCtrl(
77+
self, wx.ID_ANY, '\n'.join(lines), wx.DefaultPosition, wx.DefaultSize,
78+
wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_WORDWRAP)
79+
notesSizer.Add(self.notesText, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
80+
else:
81+
notesSizer.Add(self.browser, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
10082
mainSizer.Add(notesSizer, 1, wx.EXPAND, 5)
10183

10284
self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, _t("Don't remind me again for this release"),
@@ -131,6 +113,86 @@ def __init__(self, parent, release, version):
131113

132114
self.Centre(wx.BOTH)
133115

116+
@staticmethod
117+
def webViewAvailable():
118+
"""
119+
On wxGTK the wx.html2.WebView widget is backed by WebKitGTK, which cannot
120+
be instantiated reliably on every Linux setup. In particular, the AppImage
121+
bundles an Ubuntu build of WebKitGTK that fails to spawn its helper
122+
processes on other distributions, aborting the whole application
123+
(see https://github.com/pyfa-org/Pyfa/issues/2740). Never use the WebView
124+
there; on other platforms make sure a backend can be loaded at all.
125+
"""
126+
if 'wxGTK' in wx.PlatformInfo:
127+
return False
128+
try:
129+
from wx import html2
130+
return html2.WebView.IsBackendAvailable(html2.WebViewBackendDefault)
131+
except (KeyboardInterrupt, SystemExit):
132+
raise
133+
except Exception as e:
134+
pyfalog.warning("Could not check WebView backend availability: {}", e)
135+
return False
136+
137+
def createNotesBrowser(self, releaseDate, releaseNotes, version):
138+
"""
139+
Build the WebView displaying the release notes. Returns None when the
140+
WebView cannot be used, so the caller can fall back to plain text.
141+
"""
142+
if not self.webViewAvailable():
143+
return None
144+
145+
from wx import html2
146+
try:
147+
browser = html2.WebView.New(self)
148+
except (KeyboardInterrupt, SystemExit):
149+
raise
150+
except Exception as e:
151+
pyfalog.warning("Could not create WebView for the update dialog: {}", e)
152+
return None
153+
154+
browser.Bind(html2.EVT_WEBVIEW_NEWWINDOW, self.OnNewWindow)
155+
156+
link_patterns = [
157+
(re.compile(r"#(\d+)", re.I), r"https://github.com/pyfa-org/Pyfa/issues/\1"),
158+
(re.compile(r"@(\w+)", re.I), r"https://github.com/\1")
159+
]
160+
161+
markdowner = markdown2.Markdown(
162+
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
163+
link_patterns=link_patterns)
164+
165+
release_markup = markdowner.convert(releaseNotes)
166+
167+
# run the text through markup again, this time with the hashing pattern. This is required due to bugs in markdown2:
168+
# https://github.com/trentm/python-markdown2/issues/287
169+
link_patterns = [
170+
(re.compile("([0-9a-f]{6,40})", re.I), r"https://github.com/pyfa-org/Pyfa/commit/\1"),
171+
]
172+
173+
markdowner = markdown2.Markdown(
174+
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
175+
link_patterns=link_patterns)
176+
177+
# The space here is required, again, due to bug. Again, see https://github.com/trentm/python-markdown2/issues/287
178+
release_markup = markdowner.convert(' ' + release_markup)
179+
180+
try:
181+
browser.SetPage(html_tmpl.format(
182+
self.releaseInfo['tag_name'],
183+
releaseDate.strftime('%B %d, %Y'),
184+
"<p class='text-danger'><b>This is a pre-release, be prepared for unstable features</b></p>" if version.is_prerelease else "",
185+
release_markup
186+
), "")
187+
except (KeyboardInterrupt, SystemExit):
188+
raise
189+
except Exception as e:
190+
pyfalog.warning("Could not load release notes into WebView: {}", e)
191+
browser.Destroy()
192+
return None
193+
194+
return browser
195+
134196
def OnClose(self, e):
135197
self.Close()
136198

0 commit comments

Comments
 (0)