2323supported_platform_strings = ["linux64" , "win32" , "win64" , "mac-x64" , "mac-arm64" ]
2424
2525
26- def get_google_supported_platform_string () -> tuple [ str , str , str , str ] :
26+ def get_google_supported_platform_string () -> str | None :
2727 arch_size_detected = "64" if sys .maxsize > 2 ** 32 else "32"
2828 arch_detected = "arm" if platform .processor () == "arm" else "x"
2929
@@ -39,16 +39,17 @@ def get_google_supported_platform_string() -> tuple[str, str, str, str]:
3939 if chrome_platform_detected in supported_platform_strings :
4040 platform_string = chrome_platform_detected
4141
42- return platform_string , arch_size_detected , platform . processor (), platform . system ()
42+ return platform_string
4343
4444
4545def get_chrome_download_path () -> Path | None :
46- _chrome_platform_detected , _ , _ , _ = get_google_supported_platform_string ()
46+ _chrome_platform_detected = get_google_supported_platform_string ()
4747
4848 if not _chrome_platform_detected :
4949 return None
5050
51- _default_exe_path = Path ()
51+ _default_exe_path = default_download_path
52+ _default_exe_path .mkdir (parents = True , exist_ok = True )
5253
5354 if platform .system ().startswith ("Linux" ):
5455 _default_exe_path = (
@@ -85,47 +86,49 @@ def _extract_member(self, member, targetpath, pwd): # type: ignore [no-untyped-
8586 return path
8687
8788
88- def get_chrome_sync ( # noqa: PLR0912, C901
89+ def get_chrome_sync ( # noqa: C901, PLR0912
8990 arch : str | None = None ,
9091 i : int | None = None ,
9192 path : str | Path = default_download_path ,
9293 * ,
9394 verbose : bool = False ,
95+ force : bool = False ,
9496) -> Path | str :
9597 """Download chrome synchronously: see `get_chrome()`."""
96- if not arch :
97- arch , _ , _ , _ = get_google_supported_platform_string ( )
98+ if isinstance ( path , str ) :
99+ path = Path ( path )
98100
101+ arch = arch or get_google_supported_platform_string ()
99102 if not arch :
100103 raise RuntimeError (
101104 "You must specify an arch, one of: "
102105 f"{ ', ' .join (supported_platform_strings )} . "
103106 f"Detected { arch } is not supported." ,
104107 )
105108
106- if isinstance (path , str ):
107- path = Path (path )
108109 if i :
109110 _logger .info ("Loading chrome from list" )
111+ raw_json = urllib .request .urlopen ( # noqa: S310 audit url for schemes
112+ _chrome_for_testing_url ,
113+ ).read ()
110114 browser_list = json .loads (
111- urllib .request .urlopen ( # noqa: S310 audit url for schemes
112- _chrome_for_testing_url ,
113- ).read (),
115+ raw_json ,
114116 )
115117 version_obj = browser_list ["versions" ][i ]
118+ raw_json = json .dumps (version_obj )
116119 else :
117120 _logger .info ("Using last known good version of chrome" )
118- with (
121+ raw_json = (
119122 Path (__file__ ).resolve ().parent .parent
120123 / "resources"
121124 / "last_known_good_chrome.json"
122- ).open () as f :
123- version_obj = json .load ( f )
124- if verbose :
125- print ( version_obj [ "version" ]) # noqa: T201 allow print in cli
126- print ( version_obj [" revision" ]) # noqa: T201 allow print in cli
125+ ).read_text ()
126+ version_obj = json .loads (
127+ raw_json ,
128+ )
129+ version_string = f" { version_obj ['version' ] } \n { version_obj [ ' revision' ] } "
127130 chromium_sources = version_obj ["downloads" ]["chrome" ]
128- url = ""
131+
129132 for src in chromium_sources :
130133 if src ["platform" ] == arch :
131134 url = src ["url" ]
@@ -137,19 +140,16 @@ def get_chrome_sync( # noqa: PLR0912, C901
137140 f"{ arch } is not supported." ,
138141 )
139142
140- if not path .exists ():
141- path .mkdir (parents = True )
142- filename = path / "chrome.zip"
143- with urllib .request .urlopen (url ) as response , filename .open ("wb" ) as out_file : # noqa: S310 audit url
144- shutil .copyfileobj (response , out_file )
145- with _ZipFilePermissions (filename , "r" ) as zip_ref :
146- zip_ref .extractall (path )
147- filename .unlink ()
143+ if verbose :
144+ print (raw_json ) # noqa: T201 allow print in cli
145+ version_tag = path / "version_tag.txt"
146+
147+ path .mkdir (parents = True , exist_ok = True )
148148
149149 if arch .startswith ("linux" ):
150- exe_name = path / f"chrome-{ arch } " / "chrome"
150+ exe_path = path / f"chrome-{ arch } " / "chrome"
151151 elif arch .startswith ("mac" ):
152- exe_name = (
152+ exe_path = (
153153 path
154154 / f"chrome-{ arch } "
155155 / "Google Chrome for Testing.app"
@@ -158,10 +158,37 @@ def get_chrome_sync( # noqa: PLR0912, C901
158158 / "Google Chrome for Testing"
159159 )
160160 elif arch .startswith ("win" ):
161- exe_name = path / f"chrome-{ arch } " / "chrome.exe"
161+ exe_path = path / f"chrome-{ arch } " / "chrome.exe"
162162 else :
163163 raise RuntimeError ("Couldn't calculate exe_name, unsupported architecture." )
164- return exe_name
164+
165+ if (
166+ exe_path .exists ()
167+ and version_tag .is_file ()
168+ and version_tag .read_text () == version_string
169+ and not force
170+ ):
171+ return exe_path
172+ else :
173+ if exe_path .exists (): # delete it
174+ if exe_path .is_dir ():
175+ shutil .rmtree (exe_path )
176+ else :
177+ exe_path .unlink ()
178+ # It really should always be a dir but in testing we fake it
179+ if version_tag .exists (): # delete it
180+ version_tag .unlink ()
181+
182+ # Download
183+ zip_path = path / "chrome.zip"
184+ with urllib .request .urlopen (url ) as response , zip_path .open ("wb" ) as out_file : # noqa: S310 audit url
185+ shutil .copyfileobj (response , out_file )
186+ with _ZipFilePermissions (zip_path , "r" ) as zip_ref :
187+ zip_ref .extractall (path )
188+ zip_path .unlink ()
189+ version_tag .write_text (version_string )
190+
191+ return exe_path
165192
166193
167194async def get_chrome (
@@ -170,6 +197,7 @@ async def get_chrome(
170197 path : str | Path = default_download_path ,
171198 * ,
172199 verbose : bool = False ,
200+ force : bool = False ,
173201) -> Path | str :
174202 """
175203 Download google chrome from google-chrome-for-testing server.
@@ -180,10 +208,18 @@ async def get_chrome(
180208 still in the testing directory.
181209 path: where to download it too (the folder).
182210 verbose: print out version found
211+ force: download chrome again even if already present at that version
183212
184213 """
185214 loop = asyncio .get_running_loop ()
186- fn = partial (get_chrome_sync , arch = arch , i = i , path = path , verbose = verbose )
215+ fn = partial (
216+ get_chrome_sync ,
217+ arch = arch ,
218+ i = i ,
219+ path = path ,
220+ verbose = verbose ,
221+ force = force ,
222+ )
187223 return await loop .run_in_executor (
188224 executor = None ,
189225 func = fn ,
@@ -231,12 +267,21 @@ def get_chrome_cli() -> None:
231267 action = "store_true" ,
232268 help = "Display found version number if using -i (to stdout)" ,
233269 )
270+ parser .add_argument (
271+ "-f" ,
272+ "--force" ,
273+ dest = "force" ,
274+ action = "store_true" ,
275+ default = False ,
276+ help = "Force download even if already present." ,
277+ )
234278 parser .set_defaults (path = default_download_path )
235279 parser .set_defaults (arch = None )
236280 parser .set_defaults (verbose = False )
237281 parsed = parser .parse_args ()
238282 i = parsed .i
239283 arch = parsed .arch
240284 path = Path (parsed .path )
285+ force = parsed .force
241286 verbose = parsed .verbose
242- print (get_chrome_sync (arch = arch , i = i , path = path , verbose = verbose )) # noqa: T201 allow print in cli
287+ print (get_chrome_sync (arch = arch , i = i , path = path , verbose = verbose , force = force )) # noqa: T201 allow print in cli
0 commit comments