Skip to content

Commit 7c5cf0b

Browse files
author
sazid
committed
Cache unavailable packages so we don't ask for
password from user everytime node runs.
1 parent 39ed9e8 commit 7c5cf0b

2 files changed

Lines changed: 145 additions & 6 deletions

File tree

Framework/Built_In_Automation/Web/Selenium/linux_system.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import os
2+
import re
23
import shutil
34
import subprocess
45
from pathlib import Path
56

67

78
class LinuxSystemHelper:
8-
def __init__(self):
9+
def __init__(self, unavailable_cache_file=None):
910
self.os_release = self._load_os_release()
11+
self.unavailable_cache_file = (
12+
Path(unavailable_cache_file) if unavailable_cache_file else None
13+
)
1014

1115
def _load_os_release(self):
1216
data = {}
@@ -179,3 +183,59 @@ def get_missing_packages(self, packages):
179183
return [
180184
package for package in packages if not self._is_package_installed(package)
181185
]
186+
187+
def _load_unavailable_packages(self):
188+
if not self.unavailable_cache_file or not self.unavailable_cache_file.exists():
189+
return set()
190+
191+
try:
192+
with open(self.unavailable_cache_file, "r") as f:
193+
return {line.strip() for line in f if line.strip()}
194+
except Exception:
195+
return set()
196+
197+
def _save_unavailable_packages(self, packages):
198+
if not self.unavailable_cache_file:
199+
return
200+
201+
try:
202+
self.unavailable_cache_file.parent.mkdir(parents=True, exist_ok=True)
203+
with open(self.unavailable_cache_file, "w") as f:
204+
for package in sorted(packages):
205+
f.write(f"{package}\n")
206+
except Exception:
207+
return
208+
209+
def add_unavailable_packages(self, packages):
210+
package_set = {pkg for pkg in packages if pkg}
211+
if not package_set:
212+
return set()
213+
214+
existing = self._load_unavailable_packages()
215+
updated = existing | package_set
216+
newly_added = updated - existing
217+
if newly_added:
218+
self._save_unavailable_packages(updated)
219+
return newly_added
220+
221+
def filter_cached_unavailable_packages(self, packages):
222+
cached = self._load_unavailable_packages()
223+
allowed = [package for package in packages if package not in cached]
224+
skipped = [package for package in packages if package in cached]
225+
return allowed, skipped
226+
227+
def get_cached_unavailable_packages(self):
228+
return sorted(self._load_unavailable_packages())
229+
230+
def extract_unavailable_packages_from_apt_output(self, output):
231+
patterns = [
232+
r"E:\s+Package '([^']+)' has no installation candidate",
233+
r"E:\s+Unable to locate package\s+(\S+)",
234+
r"Package\s+(\S+)\s+is not available, but is referred to by another package",
235+
]
236+
237+
unavailable = set()
238+
for pattern in patterns:
239+
unavailable.update(re.findall(pattern, output))
240+
241+
return sorted(unavailable)

Framework/Built_In_Automation/Web/Selenium/utils.py

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class ChromeForTesting:
3030
CHROME_BASE_DIR = ZEUZ_NODE_DOWNLOADS_DIR / "chrome_for_testing"
3131
CHROME_VERSIONS_DIR = CHROME_BASE_DIR / "versions"
3232
CHROME_INFO_FILE = CHROME_BASE_DIR / "info.json"
33+
CHROME_LINUX_UNAVAILABLE_DEPS_FILE = CHROME_BASE_DIR / "unavailable_linux_deps.txt"
3334

3435
def __init__(self):
3536
self.system = platform.system().lower()
@@ -41,7 +42,9 @@ def __init__(self):
4142
self.platform_key = "mac-arm64" if self.arch == "arm64" else "mac-x64"
4243
elif self.system == "linux":
4344
self.platform_key = "linux64"
44-
self.linux_helper = LinuxSystemHelper()
45+
self.linux_helper = LinuxSystemHelper(
46+
unavailable_cache_file=self.CHROME_LINUX_UNAVAILABLE_DEPS_FILE
47+
)
4548
self._install_linux_dependencies()
4649
else:
4750
raise OSError(f"Unsupported platform: {self.system}/{self.arch}")
@@ -73,18 +76,94 @@ def _install_linux_dependencies(self):
7376
)
7477
return
7578

79+
install_deps, cached_unavailable = (
80+
self.linux_helper.filter_cached_unavailable_packages(missing_deps)
81+
)
82+
if cached_unavailable:
83+
print(
84+
"Warning: Skipping previously unavailable packages: "
85+
f"{', '.join(cached_unavailable)}"
86+
)
87+
88+
if not install_deps:
89+
print(
90+
"All missing dependencies are marked unavailable. "
91+
"Skipping apt install."
92+
)
93+
return
94+
7695
privilege_cmd, privilege_mode = (
7796
self.linux_helper.get_privilege_escalation_command()
7897
)
7998
print(
8099
f"Installing Chrome dependencies for Ubuntu using {privilege_mode}..."
81100
)
82101
subprocess.run(privilege_cmd + ["apt-get", "update", "-qq"], check=True)
83-
subprocess.run(
84-
privilege_cmd + ["apt-get", "install", "-y"] + missing_deps,
85-
check=True,
102+
install_result = subprocess.run(
103+
privilege_cmd + ["apt-get", "install", "-y"] + install_deps,
104+
capture_output=True,
105+
text=True,
106+
check=False,
86107
)
87-
print("Dependencies installed successfully.")
108+
install_ok = install_result.returncode == 0
109+
110+
if install_result.returncode != 0:
111+
apt_output = f"{install_result.stdout}\n{install_result.stderr}"
112+
unavailable_from_apt = (
113+
self.linux_helper.extract_unavailable_packages_from_apt_output(
114+
apt_output
115+
)
116+
)
117+
118+
if unavailable_from_apt:
119+
newly_cached = self.linux_helper.add_unavailable_packages(
120+
unavailable_from_apt
121+
)
122+
if newly_cached:
123+
print(
124+
"Warning: Caching unavailable packages for future runs: "
125+
f"{', '.join(sorted(newly_cached))}"
126+
)
127+
128+
retry_deps = [
129+
package
130+
for package in install_deps
131+
if package not in unavailable_from_apt
132+
]
133+
134+
if retry_deps:
135+
retry_result = subprocess.run(
136+
privilege_cmd
137+
+ ["apt-get", "install", "-y"]
138+
+ retry_deps,
139+
capture_output=True,
140+
text=True,
141+
check=False,
142+
)
143+
if retry_result.returncode != 0:
144+
print("Warning: Could not install all dependencies.")
145+
print(
146+
retry_result.stderr.strip()
147+
or retry_result.stdout.strip()
148+
)
149+
else:
150+
install_ok = True
151+
else:
152+
print(
153+
"Warning: All attempted packages were unavailable in apt. "
154+
"Continuing without interruption."
155+
)
156+
else:
157+
print("Warning: Could not install dependencies.")
158+
print(
159+
install_result.stderr.strip()
160+
or install_result.stdout.strip()
161+
)
162+
163+
if install_ok:
164+
print("Dependencies installed successfully.")
165+
else:
166+
print("Dependency installation completed with warnings.")
88167
else:
89168
return
90169

0 commit comments

Comments
 (0)