|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
| 5 | +import argparse |
5 | 6 | import os |
6 | 7 | import platform |
7 | 8 | import re |
|
30 | 31 | Path(__file__).resolve().parent / "_unix_pipe_chromium_wrapper.py" |
31 | 32 | ) |
32 | 33 |
|
| 34 | +_packaged_chromium_libs = Path(__file__).resolve().parent / "packaged_chromium_libs" |
| 35 | + |
33 | 36 | _logger = logistro.getLogger(__name__) |
34 | 37 |
|
| 38 | +_parser = argparse.ArgumentParser(add_help=False) |
| 39 | +_g = _parser.add_mutually_exclusive_group() |
| 40 | +_g.add_argument( |
| 41 | + "--ldd-fail", |
| 42 | + action="store_true", |
| 43 | + dest="ldd_fail", |
| 44 | + default="LDD_FAIL" in os.environ, |
| 45 | + help="Will cause to fail if not right deps.", |
| 46 | +) |
| 47 | + |
| 48 | +_g.add_argument( |
| 49 | + "--force-packaged-deps", |
| 50 | + action="store_true", |
| 51 | + dest="force_deps", |
| 52 | + default="FORCE_PACKAGED_DEPS" in os.environ, |
| 53 | + help="Will force us to try local deps.", |
| 54 | +) |
| 55 | + |
| 56 | +_args, _ = _parser.parse_known_args() |
| 57 | + |
35 | 58 |
|
36 | 59 | def _is_exe(path: str | Path) -> bool: |
37 | 60 | try: |
@@ -85,6 +108,61 @@ def logger_parser( |
85 | 108 | # we just eliminate their stamp, we dont' extract it |
86 | 109 | return True |
87 | 110 |
|
| 111 | + def _need_libs(self) -> bool: # noqa: C901 complexity |
| 112 | + if self.skip_local: |
| 113 | + _logger.debug( |
| 114 | + "If we HAVE to skip local.", |
| 115 | + ) |
| 116 | + if _args.force_deps: |
| 117 | + _logger.warning( |
| 118 | + "We can NOT force deps in these security conditions, " |
| 119 | + "we must use locals.", |
| 120 | + ) |
| 121 | + return False |
| 122 | + _logger.debug("Checking for libs needed.") |
| 123 | + if platform.system() != "Linux": |
| 124 | + _logger.debug("We're not in linux, so no need for check.") |
| 125 | + if _args.ldd_fail: |
| 126 | + _logger.warning("You asked for ldd-fail but we're not on linux.") |
| 127 | + if _args.force_deps: |
| 128 | + _logger.warning("You asked for packages deps but we're not on linux.") |
| 129 | + return False |
| 130 | + if _args.force_deps: |
| 131 | + _logger.debug("Force using packaged deps.") |
| 132 | + return True |
| 133 | + p = None |
| 134 | + try: |
| 135 | + _logger.debug(f"Trying ldd {self.path}") |
| 136 | + p = subprocess.run( # noqa: S603, validating run with variables |
| 137 | + [ # noqa: S607 path is all we have |
| 138 | + "ldd", |
| 139 | + str(self.path), |
| 140 | + ], |
| 141 | + capture_output=True, |
| 142 | + timeout=5, |
| 143 | + check=True, |
| 144 | + ) |
| 145 | + except BaseException as e: |
| 146 | + msg = "ldd failed." |
| 147 | + if _args.ldd_fail: |
| 148 | + _logger.exception(msg) |
| 149 | + raise |
| 150 | + else: |
| 151 | + stderr = p.stderr.decode() if p and p.stderr else None |
| 152 | + _logger.warning( |
| 153 | + msg # noqa: G003 + in log |
| 154 | + + f" e: {e}, stderr: {stderr}", |
| 155 | + ) |
| 156 | + return True |
| 157 | + if b"not found" in p.stdout: |
| 158 | + msg = "Found deps missing in chrome" |
| 159 | + if _args.ldd_fail: |
| 160 | + raise RuntimeError(msg + f" {p.stdout.decode()}") |
| 161 | + _logger.debug(msg + f" {p.stdout.decode()}") # noqa: G003 + in log |
| 162 | + return True |
| 163 | + _logger.debug("No problems found with dependencies") |
| 164 | + return False |
| 165 | + |
88 | 166 | def __init__( |
89 | 167 | self, |
90 | 168 | channel: ChannelInterface, |
@@ -144,12 +222,15 @@ def __init__( |
144 | 222 | "please see documentation.", |
145 | 223 | ) |
146 | 224 | _logger.info(f"Found chromium path: {self.path}") |
| 225 | + |
147 | 226 | self._channel = channel |
148 | 227 | if not isinstance(channel, Pipe): |
149 | 228 | raise NotImplementedError("Websocket style channels not implemented yet.") |
150 | 229 |
|
151 | 230 | self._is_isolated = "snap" in str(self.path) |
152 | 231 |
|
| 232 | + def pre_open(self) -> None: |
| 233 | + """Prepare browser for opening.""" |
153 | 234 | self.tmp_dir = TmpDirectory( |
154 | 235 | path=self._tmp_dir_path, |
155 | 236 | sneak=self._is_isolated, |
@@ -247,8 +328,14 @@ def get_cli(self) -> Sequence[str]: |
247 | 328 |
|
248 | 329 | def get_env(self) -> MutableMapping[str, str]: |
249 | 330 | """Return the env needed for chromium.""" |
250 | | - _logger.debug("Returning env: same env, no modification.") |
251 | | - return os.environ.copy() |
| 331 | + env = os.environ.copy() |
| 332 | + if self._need_libs(): |
| 333 | + original = env.get("LD_LIBRARY_PATH", "") |
| 334 | + env["LD_LIBRARY_PATH"] = f"{_packaged_chromium_libs!s}:{original}" |
| 335 | + _logger.debug( |
| 336 | + f"Added LD_LIBRARY_PATH={env['LD_LIBRARY_PATH']!s} to env vars.", |
| 337 | + ) |
| 338 | + return env |
252 | 339 |
|
253 | 340 | def clean(self) -> None: |
254 | 341 | """Clean up any leftovers form browser, like tmp files.""" |
|
0 commit comments