|
4 | 4 | import gettext |
5 | 5 | import locale |
6 | 6 | import os |
| 7 | +import shlex |
7 | 8 | import shutil |
8 | 9 | import subprocess |
9 | 10 | import warnings |
|
23 | 24 | # 3. Local application/library specific imports. |
24 | 25 | 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 |
25 | 26 |
|
| 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 | + |
26 | 128 | setproctitle.setproctitle("webapp-manager") |
27 | 129 |
|
28 | 130 | # i18n |
@@ -362,9 +464,18 @@ def on_edit_button(self, widget): |
362 | 464 | self.isolated_switch.set_active(self.selected_webapp.isolate_profile) |
363 | 465 | self.privatewindow_switch.set_active(self.selected_webapp.privatewindow) |
364 | 466 |
|
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) |
368 | 479 | self.on_browser_changed(self.selected_webapp) |
369 | 480 |
|
370 | 481 | model = self.category_combo.get_model() |
|
0 commit comments