Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/scripts/update_cdp.py
4500 views
1
#!/usr/bin/env python
2
3
import argparse
4
import json
5
import os
6
import re
7
import shutil
8
import subprocess
9
from pathlib import Path
10
11
import urllib3
12
from packaging.version import parse
13
14
http = urllib3.PoolManager()
15
root_dir = Path(os.path.realpath(__file__)).parent.parent
16
17
18
def get_chrome_milestone():
19
"""Get the Chrome milestone from the channel.
20
21
This is the same method from pinned_browser. Use --chrome_channel=Beta if
22
using early stable release.
23
"""
24
parser = argparse.ArgumentParser()
25
parser.add_argument("--chrome_channel", default="Stable", help="Set the Chrome channel")
26
args = parser.parse_args()
27
channel = args.chrome_channel
28
29
r = http.request(
30
"GET",
31
f"https://chromiumdash.appspot.com/fetch_releases?channel={channel}&num=1&platform=Mac,Linux",
32
)
33
all_versions = json.loads(r.data)
34
# use the same milestone for all Chrome releases, so pick the lowest
35
milestones = [version["milestone"] for version in all_versions if version["milestone"]]
36
if not milestones:
37
raise ValueError(f"No Chrome versions with milestones found for channel '{channel}'")
38
milestone = min(milestones)
39
r = http.request(
40
"GET",
41
"https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json",
42
)
43
versions = json.loads(r.data)["versions"]
44
45
return sorted(
46
filter(lambda v: v["version"].split(".")[0] == str(milestone), versions),
47
key=lambda v: parse(v["version"]),
48
)[-1]
49
50
51
def fetch_and_save(url, file_path):
52
response = http.request("GET", url)
53
with open(file_path, "wb") as file:
54
file.write(response.data)
55
56
57
def new_chrome(chrome_milestone):
58
return chrome_milestone["version"].split(".")[0]
59
60
61
def previous_chrome(chrome_milestone):
62
return str(int(new_chrome(chrome_milestone)) - 1)
63
64
65
def old_chrome(chrome_milestone):
66
return str(int(new_chrome(chrome_milestone)) - 3)
67
68
69
def flatten_browser_pdl(file_path, chrome_version):
70
"""Preserves the version block and concatenates all included domain .pdl files."""
71
with open(file_path) as file:
72
content = file.read()
73
# Extract version block
74
version_match = re.search(r"(version\s+major\s+\d+\s+minor\s+\d+)", content)
75
version_block = version_match.group(1) + "\n\n" if version_match else ""
76
# Find all include lines
77
includes = re.findall(r"include domains/([A-Za-z0-9_]+\.pdl)", content)
78
base_url = f"https://raw.githubusercontent.com/chromium/chromium/{chrome_version}/third_party/blink/public/devtools_protocol/domains/"
79
concatenated = ""
80
for domain_file in includes:
81
url = base_url + domain_file
82
response = http.request("GET", url)
83
concatenated += response.data.decode("utf-8") + "\n"
84
# Overwrite the file with version block + concatenated domains
85
with open(file_path, "w") as file:
86
file.write(version_block + concatenated)
87
88
89
def add_pdls(chrome_milestone):
90
source_dir = root_dir / f"common/devtools/chromium/v{previous_chrome(chrome_milestone)}"
91
target_dir = root_dir / f"common/devtools/chromium/v{new_chrome(chrome_milestone)}"
92
old_dir = root_dir / f"common/devtools/chromium/v{old_chrome(chrome_milestone)}"
93
94
if os.path.isdir(old_dir):
95
shutil.rmtree(old_dir)
96
97
if not target_dir.is_dir() or not any(target_dir.iterdir()):
98
os.makedirs(target_dir, exist_ok=True)
99
if os.path.isdir(source_dir):
100
shutil.copytree(source_dir, target_dir, dirs_exist_ok=True)
101
102
fetch_and_save(
103
f"https://raw.githubusercontent.com/chromium/chromium/{chrome_milestone['version']}/third_party/blink/public/devtools_protocol/browser_protocol.pdl",
104
f"{target_dir}/browser_protocol.pdl",
105
)
106
107
flatten_browser_pdl(f"{target_dir}/browser_protocol.pdl", chrome_milestone["version"])
108
109
deps_content = http.request(
110
"GET",
111
f"https://raw.githubusercontent.com/chromium/chromium/{chrome_milestone['version']}/DEPS",
112
).data.decode("utf-8")
113
v8_revision_line = next((line for line in deps_content.split("\n") if "v8_revision" in line), None)
114
if v8_revision_line is None:
115
raise ValueError(f"No v8_revision found in DEPS for Chrome {chrome_milestone['version']}")
116
v8_revision = v8_revision_line.split(": ")[1].strip("',")
117
fetch_and_save(
118
f"https://raw.githubusercontent.com/v8/v8/{v8_revision}/include/js_protocol.pdl",
119
f"{target_dir}/js_protocol.pdl",
120
)
121
122
# javadocs does not like script tags
123
with open(f"{target_dir}/browser_protocol.pdl", "r+") as file:
124
script_replace = file.read().replace("`<script>`", "`script`")
125
file.seek(0)
126
file.write(script_replace)
127
file.truncate()
128
129
subprocess.run(["git", "add", str(target_dir / "*")], cwd=root_dir)
130
131
132
def create_new_chrome_files(src_base, chrome_milestone):
133
"""Create new Chrome devtools files for a language binding.
134
135
Java and .NET need to copy previous version directory into new version
136
directory.
137
"""
138
source_dir = root_dir / f"{src_base}/v{previous_chrome(chrome_milestone)}"
139
target_dir = root_dir / f"{src_base}/v{new_chrome(chrome_milestone)}"
140
old_dir = root_dir / f"{src_base}/v{old_chrome(chrome_milestone)}"
141
142
if old_dir.is_dir():
143
shutil.rmtree(old_dir)
144
145
if source_dir.is_dir() and any(source_dir.iterdir()):
146
os.makedirs(target_dir, exist_ok=True)
147
for item in source_dir.iterdir():
148
shutil.copy(item, target_dir)
149
150
for file in target_dir.iterdir():
151
replace_in_file(file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone))
152
new_filename = file.name.replace(previous_chrome(chrome_milestone), new_chrome(chrome_milestone))
153
file.rename(target_dir / new_filename)
154
155
subprocess.run(["git", "add", str(target_dir / "*")], cwd=root_dir)
156
157
158
def replace_in_file(file_path, old_string, new_string, is_regex=False):
159
with open(file_path, "r+") as file:
160
if not is_regex:
161
old_string = re.escape(old_string)
162
data = re.sub(old_string, new_string, file.read())
163
file.seek(0)
164
file.write(data)
165
file.truncate()
166
167
168
def update_java(chrome_milestone):
169
create_new_chrome_files("java/src/org/openqa/selenium/devtools", chrome_milestone)
170
171
files = [
172
root_dir / "java/src/org/openqa/selenium/devtools/versions.bzl",
173
root_dir / "rake_tasks/java.rake",
174
]
175
for file in files:
176
replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone))
177
178
179
def update_dotnet(chrome_milestone):
180
create_new_chrome_files("dotnet/src/webdriver/DevTools", chrome_milestone)
181
182
files = [
183
root_dir / "dotnet/selenium-dotnet-version.bzl",
184
root_dir / "dotnet/src/webdriver/Selenium.WebDriver.csproj",
185
root_dir / "dotnet/src/webdriver/DevTools/DevToolsDomains.cs",
186
]
187
for file in files:
188
replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone))
189
190
files = [root_dir / "dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs"]
191
dir_path = root_dir / "dotnet/test/common/DevTools"
192
files.extend(str(file) for file in dir_path.glob("*") if file.is_file())
193
for file in files:
194
replace_in_file(file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone))
195
196
197
def update_ruby(chrome_milestone):
198
file = root_dir / "rb/lib/selenium/devtools/BUILD.bazel"
199
replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone))
200
201
file = root_dir / "rb/lib/selenium/devtools/version.rb"
202
replace_in_file(
203
file,
204
rf"{previous_chrome(chrome_milestone)}\.[0-9]*",
205
f"{new_chrome(chrome_milestone)}.0",
206
True,
207
)
208
209
subprocess.run(["bundle", "install"], cwd=root_dir / "rb", check=True)
210
211
212
def update_python(chrome_milestone):
213
file = root_dir / "py/BUILD.bazel"
214
replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone))
215
216
217
def update_js(chrome_milestone):
218
file = root_dir / "javascript/selenium-webdriver/BUILD.bazel"
219
replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone))
220
221
222
if __name__ == "__main__":
223
chrome_milestone = get_chrome_milestone()
224
add_pdls(chrome_milestone)
225
update_java(chrome_milestone)
226
update_dotnet(chrome_milestone)
227
update_ruby(chrome_milestone)
228
update_python(chrome_milestone)
229
update_js(chrome_milestone)
230
231
print(f"adding CDP {new_chrome(chrome_milestone)} and removing {old_chrome(chrome_milestone)}")
232
233