Skip to content

Commit 71c76ef

Browse files
Fix IndexError when editing legacy webapps missing browser metadata
Commit 247f167 added browser restoration during edit but assumed X-WebApp-Browser always exists. Legacy desktop files miss that key, so on_edit_button hits IndexError at line 366, the GTK main loop stalls, and CPU usage spikes. Match by Exec when the name lookup fails, and fall back if nothing fits. Editing now completes and rewrites the desktop file with fresh metadata. Fix #345
1 parent a49ec21 commit 71c76ef

File tree

1 file changed

+114
-3
lines changed

1 file changed

+114
-3
lines changed

usr/lib/webapp-manager/webapp-manager.py

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import gettext
55
import locale
66
import os
7+
import shlex
78
import shutil
89
import subprocess
910
import warnings
@@ -23,6 +24,107 @@
2324
# 3. Local application/library specific imports.
2425
from common import _async, idle, WebAppManager, download_favicon, ICONS_DIR, BROWSER_TYPE_FIREFOX, BROWSER_TYPE_FIREFOX_FLATPAK, BROWSER_TYPE_ZEN_FLATPAK, BROWSER_TYPE_FIREFOX_SNAP
2526

27+
28+
def _strip_leading_env(tokens):
29+
"""Remove leading env invocations and KEY=VALUE assignments."""
30+
31+
def _consume_env_opts(index):
32+
while index < len(tokens) and tokens[index].startswith("-"):
33+
option = tokens[index]
34+
index += 1
35+
if option == "--":
36+
return index
37+
if option.startswith("-u") and option not in ("-u", "--unset"):
38+
continue
39+
if option.startswith("-C") and option not in ("-C", "--chdir"):
40+
continue
41+
if option.startswith("-S") and option not in ("-S", "--split-string"):
42+
try:
43+
extra = shlex.split(option[2:])
44+
except ValueError:
45+
extra = []
46+
if extra:
47+
tokens[index:index] = extra
48+
continue
49+
if option in ("-u", "--unset", "-C", "--chdir", "-S", "--split-string") and index < len(tokens):
50+
if option in ("-S", "--split-string"):
51+
try:
52+
extra = shlex.split(tokens[index])
53+
except ValueError:
54+
extra = []
55+
index += 1
56+
if extra:
57+
tokens[index:index] = extra
58+
else:
59+
index += 1
60+
elif option.startswith("--unset="):
61+
continue
62+
elif option.startswith("--chdir="):
63+
continue
64+
elif option.startswith("--split-string="):
65+
try:
66+
extra = shlex.split(option.split("=", 1)[1])
67+
except ValueError:
68+
extra = []
69+
if extra:
70+
tokens[index:index] = extra
71+
continue
72+
while index < len(tokens) and "=" in tokens[index] and not tokens[index].startswith("-"):
73+
index += 1
74+
return index
75+
76+
idx = 0
77+
while idx < len(tokens):
78+
token = tokens[idx]
79+
if token == "env" or os.path.basename(token) == "env":
80+
idx = _consume_env_opts(idx + 1)
81+
continue
82+
if token == "--":
83+
idx += 1
84+
continue
85+
if "=" in token and not token.startswith("--") and not token.startswith("-"):
86+
idx += 1
87+
continue
88+
break
89+
return tokens[idx:]
90+
91+
92+
def _extract_exec_binary(exec_line):
93+
"""Return the executable invoked by a desktop Exec line."""
94+
if not exec_line:
95+
return None
96+
try:
97+
tokens = shlex.split(exec_line)
98+
except ValueError:
99+
return None
100+
if not tokens:
101+
return None
102+
tokens = _strip_leading_env(tokens)
103+
if not tokens:
104+
return None
105+
if len(tokens) >= 3 and tokens[1] == "-c" and os.path.basename(tokens[0]) == "sh":
106+
try:
107+
inner_tokens = shlex.split(tokens[2])
108+
except ValueError:
109+
return None
110+
inner_tokens = _strip_leading_env(inner_tokens)
111+
if not inner_tokens:
112+
return None
113+
return inner_tokens[0]
114+
return tokens[0]
115+
116+
117+
def _exec_matches(browser_exec_path, exec_binary):
118+
if not exec_binary:
119+
return False
120+
if browser_exec_path == exec_binary:
121+
return True
122+
if os.path.isabs(browser_exec_path) and os.path.basename(browser_exec_path) == exec_binary:
123+
return True
124+
if os.path.isabs(exec_binary) and os.path.basename(exec_binary) == browser_exec_path:
125+
return True
126+
return False
127+
26128
setproctitle.setproctitle("webapp-manager")
27129

28130
# i18n
@@ -362,9 +464,18 @@ def on_edit_button(self, widget):
362464
self.isolated_switch.set_active(self.selected_webapp.isolate_profile)
363465
self.privatewindow_switch.set_active(self.selected_webapp.privatewindow)
364466

365-
web_browsers = map(lambda i: i[0], self.browser_combo.get_model())
366-
selected_browser_index = [idx for idx, x in enumerate(web_browsers) if x.name == self.selected_webapp.web_browser][0]
367-
self.browser_combo.set_active(selected_browser_index)
467+
web_browsers = list(map(lambda i: i[0], self.browser_combo.get_model()))
468+
matching_indexes = [idx for idx, x in enumerate(web_browsers)
469+
if x.name == self.selected_webapp.web_browser]
470+
if not matching_indexes and self.selected_webapp.exec:
471+
exec_binary = _extract_exec_binary(self.selected_webapp.exec)
472+
if exec_binary:
473+
matching_indexes = [idx for idx, x in enumerate(web_browsers)
474+
if _exec_matches(x.exec_path, exec_binary)]
475+
if matching_indexes:
476+
self.browser_combo.set_active(matching_indexes[0])
477+
elif web_browsers:
478+
self.browser_combo.set_active(0)
368479
self.on_browser_changed(self.selected_webapp)
369480

370481
model = self.category_combo.get_model()

0 commit comments

Comments
 (0)