forked from mirrors/gecko-dev
		
	 f3092e5151
			
		
	
	
		f3092e5151
		
	
	
	
	
		
			
			This patch replaces the chromedrivers retrieved from the chromium snapshots with the Chrome for Testing (CfT) chromedrivers (through the "Canary" channel) for our Chromium-as-Release tests. There is an occasional intermittent issue that occurs where the chromedriver from the snapshots don't always work. Instead we can use the `last-known-good-versions-with-downloads.json` provided by CfT to get guaranteed stable chromedrivers. Differential Revision: https://phabricator.services.mozilla.com/D212707
		
			
				
	
	
		
			199 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python3 -u
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # This Source Code Form is subject to the terms of the Mozilla Public
 | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| 
 | |
| """
 | |
| This script downloads chromedriver for a given platform and then
 | |
| packages the driver along with the revision and uploads the archive.
 | |
| This is currently accomplished by using "last known good version" of
 | |
| the chromedrivers associated with Chrome for Testing. The `Canary`
 | |
| channel is specified as it is required for the Chromium-as-Release
 | |
| performance tests.
 | |
| """
 | |
| 
 | |
| 
 | |
| import argparse
 | |
| import errno
 | |
| import os
 | |
| import shutil
 | |
| import subprocess
 | |
| import tempfile
 | |
| 
 | |
| import requests
 | |
| from redo import retriable
 | |
| 
 | |
| CHROME_FOR_TESTING_INFO = {
 | |
|     "linux": {
 | |
|         "platform": "linux64",
 | |
|         "dir": "cft-chromedriver-linux",
 | |
|         "result": "cft-cd-linux.tar.bz2",
 | |
|         "chromedriver": "chromedriver_linux64.zip",
 | |
|     },
 | |
|     "win64": {
 | |
|         "platform": "win64",
 | |
|         "dir": "cft-chromedriver-win64",
 | |
|         "result": "cft-cd-win64.tar.bz2",
 | |
|         "chromedriver": "chromedriver_win32.zip",
 | |
|     },
 | |
|     "mac": {
 | |
|         "platform": "mac-x64",
 | |
|         "dir": "cft-chromedriver-mac",
 | |
|         "result": "cft-cd-mac.tar.bz2",
 | |
|         "chromedriver": "chromedriver_mac64.zip",
 | |
|     },
 | |
|     "mac-arm": {
 | |
|         "platform": "mac-arm64",
 | |
|         "dir": "cft-chromedriver-mac",
 | |
|         "result": "cft-cd-mac-arm.tar.bz2",
 | |
|         "chromedriver": "chromedriver_mac64.zip",
 | |
|     },
 | |
| }
 | |
| 
 | |
| # Bug 1869592
 | |
| # Potentially add another JSON endpoint to grab more than 1 chromedriver
 | |
| LAST_GOOD_CFT_JSON = (
 | |
|     "https://googlechromelabs.github.io/chrome-for-testing/"
 | |
|     "last-known-good-versions-with-downloads.json"
 | |
| )
 | |
| 
 | |
| 
 | |
| def log(msg):
 | |
|     print("build-cft-chromedriver: %s" % msg)
 | |
| 
 | |
| 
 | |
| @retriable(attempts=7, sleeptime=5, sleepscale=2)
 | |
| def fetch_file(url, filepath):
 | |
|     """Download a file from the given url to a given file."""
 | |
|     size = 4096
 | |
|     r = requests.get(url, stream=True)
 | |
|     r.raise_for_status()
 | |
| 
 | |
|     with open(filepath, "wb") as fd:
 | |
|         for chunk in r.iter_content(size):
 | |
|             fd.write(chunk)
 | |
| 
 | |
| 
 | |
| def unzip(zippath, target):
 | |
|     """Unzips an archive to the target location."""
 | |
|     log("Unpacking archive at: %s to: %s" % (zippath, target))
 | |
|     unzip_command = ["unzip", "-q", "-o", zippath, "-d", target]
 | |
|     subprocess.check_call(unzip_command)
 | |
| 
 | |
| 
 | |
| def get_cft_metadata():
 | |
|     """Send a request to the Chrome for Testing's last
 | |
|     good json URL (default) and get the json payload which will have
 | |
|     the download URLs that we need.
 | |
|     """
 | |
|     res = requests.get(LAST_GOOD_CFT_JSON)
 | |
|     data = res.json()
 | |
| 
 | |
|     return data
 | |
| 
 | |
| 
 | |
| def get_cd_url(data, cft_platform):
 | |
|     """Given the json data, get the download URL's for
 | |
|     the correct platform
 | |
|     """
 | |
|     for p in data["channels"]["Canary"]["downloads"]["chromedriver"]:
 | |
|         if p["platform"] == cft_platform:
 | |
|             return p["url"]
 | |
|     raise Exception("Platform not found")
 | |
| 
 | |
| 
 | |
| def get_chromedriver_revision(data):
 | |
|     """Grab revision metadata from payload"""
 | |
|     return data["channels"]["Canary"]["revision"]
 | |
| 
 | |
| 
 | |
| def fetch_chromedriver(download_url, cft_dir):
 | |
|     """Get the chromedriver for the given cft url repackage it."""
 | |
| 
 | |
|     tmpzip = os.path.join(tempfile.mkdtemp(), "cd-tmp.zip")
 | |
|     log("Downloading chromedriver from %s" % download_url)
 | |
|     fetch_file(download_url, tmpzip)
 | |
| 
 | |
|     tmppath = tempfile.mkdtemp()
 | |
|     unzip(tmpzip, tmppath)
 | |
| 
 | |
|     # Find the chromedriver then copy it to the chromium directory
 | |
|     cd_path = None
 | |
|     for dirpath, _, filenames in os.walk(tmppath):
 | |
|         for filename in filenames:
 | |
|             if filename == "chromedriver" or filename == "chromedriver.exe":
 | |
|                 cd_path = os.path.join(dirpath, filename)
 | |
|                 break
 | |
|         if cd_path is not None:
 | |
|             break
 | |
|     if cd_path is None:
 | |
|         raise Exception("Could not find chromedriver binary in %s" % tmppath)
 | |
|     log("Copying chromedriver from: %s to: %s" % (cd_path, cft_dir))
 | |
|     shutil.copy(cd_path, cft_dir)
 | |
| 
 | |
| 
 | |
| def build_cft_archive(platform):
 | |
|     """Download and store a chromedriver for a given platform."""
 | |
|     upload_dir = os.environ.get("UPLOAD_DIR")
 | |
|     if upload_dir:
 | |
|         # Create the upload directory if it doesn't exist.
 | |
|         try:
 | |
|             log("Creating upload directory in %s..." % os.path.abspath(upload_dir))
 | |
|             os.makedirs(upload_dir)
 | |
|         except OSError as e:
 | |
|             if e.errno != errno.EEXIST:
 | |
|                 raise
 | |
| 
 | |
|     cft_platform = CHROME_FOR_TESTING_INFO[platform]["platform"]
 | |
| 
 | |
|     data = get_cft_metadata()
 | |
|     cft_chromedriver_url = get_cd_url(data, cft_platform)
 | |
|     revision = get_chromedriver_revision(data)
 | |
|     # Make a temporary location for the file
 | |
|     tmppath = tempfile.mkdtemp()
 | |
| 
 | |
|     # Create the directory format expected for browsertime setup in taskgraph transform
 | |
|     artifact_dir = CHROME_FOR_TESTING_INFO[platform]["dir"]
 | |
|     cft_dir = os.path.join(tmppath, artifact_dir)
 | |
|     os.mkdir(cft_dir)
 | |
| 
 | |
|     # Store the revision number and chromedriver
 | |
|     fetch_chromedriver(cft_chromedriver_url, cft_dir)
 | |
|     revision_file = os.path.join(cft_dir, ".REVISION")
 | |
|     with open(revision_file, "w+") as f:
 | |
|         f.write(str(revision))
 | |
| 
 | |
|     tar_file = CHROME_FOR_TESTING_INFO[platform]["result"]
 | |
|     tar_command = ["tar", "cjf", tar_file, "-C", tmppath, artifact_dir]
 | |
|     log("Revision is %s" % revision)
 | |
|     log("Added revision to %s file." % revision_file)
 | |
| 
 | |
|     log("Tarring with the command: %s" % str(tar_command))
 | |
|     subprocess.check_call(tar_command)
 | |
| 
 | |
|     upload_dir = os.environ.get("UPLOAD_DIR")
 | |
|     if upload_dir:
 | |
|         # Move the tarball to the output directory for upload.
 | |
|         log("Moving %s to the upload directory..." % tar_file)
 | |
|         shutil.copy(tar_file, os.path.join(upload_dir, tar_file))
 | |
| 
 | |
|     shutil.rmtree(tmppath)
 | |
| 
 | |
| 
 | |
| def parse_args():
 | |
|     """Read command line arguments and return options."""
 | |
|     parser = argparse.ArgumentParser()
 | |
|     parser.add_argument(
 | |
|         "--platform",
 | |
|         help="Corresponding platform of CfT chromedriver to fetch.",
 | |
|         required=True,
 | |
|     )
 | |
|     # Bug 1869592 - Add optional flag to provide CfT channel e.g. Canary, Stable, etc.
 | |
|     return parser.parse_args()
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     args = vars(parse_args())
 | |
|     build_cft_archive(**args)
 |