From f2a6325bd8a172f90f246a48356e1ca82fa855dd Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Thu, 19 Oct 2023 18:15:31 -0700 Subject: [PATCH 1/4] Change the download location to the new location, and update how the zip is extracted. Fixes #13 --- .../driver_remote_version_finder_spec.cr | 3 ++- .../chrome/driver_remote_version_finder.cr | 17 +++++++------ .../chrome/install_driver_executor.cr | 24 ++++++++++++++++--- src/webdrivers/common/zip_extractor.cr | 3 ++- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr b/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr index b94ee51..ecd6819 100644 --- a/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr +++ b/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr @@ -7,7 +7,8 @@ module Webdrivers::Chrome File.delete(finder.cache_path) if File.exists?(finder.cache_path) end - it "will limit return version to matching major version if version" do + # TODO: Figure out if this is necessary + pending "will limit return version to matching major version if version" do version = SemanticVersion.new( major: 71, minor: 22, diff --git a/src/webdrivers/chrome/driver_remote_version_finder.cr b/src/webdrivers/chrome/driver_remote_version_finder.cr index a597a50..589a24c 100644 --- a/src/webdrivers/chrome/driver_remote_version_finder.cr +++ b/src/webdrivers/chrome/driver_remote_version_finder.cr @@ -2,6 +2,11 @@ class Webdrivers::Chrome::DriverRemoteVersionFinder getter cache_path : String getter version : SemanticVersion? + # Since Chrome v115+ the download locations have changed. + # We can use https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints + # to find specific API endpoints + MANIFEST_API_ENDPOINT = "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json" + def initialize(driver_directory, @version = nil) @cache_path = File.join(driver_directory, "chromedriver.version") end @@ -12,15 +17,9 @@ class Webdrivers::Chrome::DriverRemoteVersionFinder private def find_raw_version Cache.fetch(cache_path, Webdrivers.settings.cache_duration) do - response = HTTP::Client.get("https://chromedriver.storage.googleapis.com/#{latest_release}") - response.body + response = HTTP::Client.get(MANIFEST_API_ENDPOINT) + google = JSON.parse(response.body) + google.dig("channels", "Stable", "version").as_s end end - - private def latest_release - limitting_version = version - return "LATEST_RELEASE" if limitting_version.nil? - - "LATEST_RELEASE_#{limitting_version.major}" - end end diff --git a/src/webdrivers/chrome/install_driver_executor.cr b/src/webdrivers/chrome/install_driver_executor.cr index 4115853..610f274 100644 --- a/src/webdrivers/chrome/install_driver_executor.cr +++ b/src/webdrivers/chrome/install_driver_executor.cr @@ -14,7 +14,7 @@ class Webdrivers::Chrome::InstallDriverExecutor FileUtils.cd(driver_directory) do zip = download_file(from: download_url, to: download_url_filename) - Common::ZipExtractor.new(zip, driver_name, driver_directory).extract + Common::ZipExtractor.new(zip, File.join("chromedriver-#{download_url_platform}", driver_name), driver_directory).extract zip.delete File.chmod(driver_name, Common::EXECUTABLE_PERMISSIONS) end @@ -28,14 +28,32 @@ class Webdrivers::Chrome::InstallDriverExecutor File.new(to, mode: "rb") end - private def download_url - "https://chromedriver.storage.googleapis.com/#{converted_version}/#{download_url_filename}" + private def download_url : String + response = HTTP::Client.get(Webdrivers::Chrome::DriverRemoteVersionFinder::MANIFEST_API_ENDPOINT) + google = JSON.parse(response.body.to_s) + downloads = google.dig("channels", "Stable", "downloads", "chromedriver").as_a + platform = downloads.find! { |version| version["platform"].as_s == download_url_platform } + platform["url"].as_s end private def converted_version : String SemverConverter.convert(install_version) end + # TODO: Support Win64, and Mac Intel + private def download_url_platform : String + case Common.os + when Common::OS::Linux + "linux64" + when Common::OS::Mac + "mac-arm64" + when Common::OS::Windows + "win32" + else + raise "Unknown os" + end + end + private def download_url_filename : String case Common.os when Common::OS::Linux diff --git a/src/webdrivers/common/zip_extractor.cr b/src/webdrivers/common/zip_extractor.cr index 89f65b7..e01b6e5 100644 --- a/src/webdrivers/common/zip_extractor.cr +++ b/src/webdrivers/common/zip_extractor.cr @@ -9,7 +9,8 @@ class Webdrivers::Common::ZipExtractor def extract Compress::Zip::File.open(zip_file) do |zip_contents| driver = zip_contents[driver_name] - destination_path = File.join(install_path, driver.filename) + filepath = driver.filename.split(File::SEPARATOR).last + destination_path = File.join(install_path, filepath) File.delete(destination_path) if File.exists?(destination_path) driver.open { |io| File.write(destination_path, io) } end From 4ee6a47339161a6b5475b95445825da6f5ff73cb Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Fri, 20 Oct 2023 15:37:34 -0700 Subject: [PATCH 2/4] bump some shard versions --- shard.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shard.yml b/shard.yml index 933d348..bdf1228 100644 --- a/shard.yml +++ b/shard.yml @@ -12,9 +12,9 @@ dependencies: github: luckyframework/habitat version: ~> 0.4.7 crystar: - git: https://github.com/naqvis/crystar.git - commit: 56db8bb9dfbd5ed6d7908353405a5fae632a6561 + github: naqvis/crystar + version: ~> 0.3.1 development_dependencies: ameba: github: crystal-ameba/ameba - version: ~> 1.1.0 + version: ~> 1.5 From b019315474ba47296bd6675dc6c65f3652416f9a Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Fri, 20 Oct 2023 15:37:55 -0700 Subject: [PATCH 3/4] Allow for legacy versions to be pulled up --- spec/webdrivers/cache_spec.cr | 4 +- .../driver_remote_version_finder_spec.cr | 3 +- src/webdrivers/cache.cr | 2 +- .../chrome/driver_remote_version_finder.cr | 37 +++++++++++++++---- .../chrome/install_driver_executor.cr | 36 +++++++++++++++--- src/webdrivers/chromedriver.cr | 2 +- src/webdrivers/common/tar_gz_extractor.cr | 2 +- src/webdrivers/geckodriver.cr | 2 +- 8 files changed, 66 insertions(+), 22 deletions(-) diff --git a/spec/webdrivers/cache_spec.cr b/spec/webdrivers/cache_spec.cr index 4ed1520..1beaec5 100644 --- a/spec/webdrivers/cache_spec.cr +++ b/spec/webdrivers/cache_spec.cr @@ -38,7 +38,7 @@ describe Webdrivers::Cache do end end -private def with_tempfile +private def with_tempfile(&) tempfile = File.tempfile(suffix: ".txt") do |file| file.print("hello!") end @@ -47,7 +47,7 @@ ensure tempfile.try(&.delete) end -private def with_missing_file +private def with_missing_file(&) tempname = File.tempname(suffix: ".txt") yield tempname ensure diff --git a/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr b/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr index ecd6819..55c7bfe 100644 --- a/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr +++ b/spec/webdrivers/chrome/driver_remote_version_finder_spec.cr @@ -7,8 +7,7 @@ module Webdrivers::Chrome File.delete(finder.cache_path) if File.exists?(finder.cache_path) end - # TODO: Figure out if this is necessary - pending "will limit return version to matching major version if version" do + it "will limit return version to matching major version when version is provided" do version = SemanticVersion.new( major: 71, minor: 22, diff --git a/src/webdrivers/cache.cr b/src/webdrivers/cache.cr index a104272..41b1e13 100644 --- a/src/webdrivers/cache.cr +++ b/src/webdrivers/cache.cr @@ -1,5 +1,5 @@ module Webdrivers::Cache - def self.fetch(cache_path : String, expires_in : Time::Span, &block) + def self.fetch(cache_path : String, expires_in : Time::Span, &) value = read(cache_path, expires_in) return value if value diff --git a/src/webdrivers/chrome/driver_remote_version_finder.cr b/src/webdrivers/chrome/driver_remote_version_finder.cr index 589a24c..4fbffc5 100644 --- a/src/webdrivers/chrome/driver_remote_version_finder.cr +++ b/src/webdrivers/chrome/driver_remote_version_finder.cr @@ -2,11 +2,6 @@ class Webdrivers::Chrome::DriverRemoteVersionFinder getter cache_path : String getter version : SemanticVersion? - # Since Chrome v115+ the download locations have changed. - # We can use https://github.com/GoogleChromeLabs/chrome-for-testing#json-api-endpoints - # to find specific API endpoints - MANIFEST_API_ENDPOINT = "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json" - def initialize(driver_directory, @version = nil) @cache_path = File.join(driver_directory, "chromedriver.version") end @@ -17,9 +12,35 @@ class Webdrivers::Chrome::DriverRemoteVersionFinder private def find_raw_version Cache.fetch(cache_path, Webdrivers.settings.cache_duration) do - response = HTTP::Client.get(MANIFEST_API_ENDPOINT) - google = JSON.parse(response.body) - google.dig("channels", "Stable", "version").as_s + if v = version + if v.major < 113 + fetch_legacy_version(v) + else + fetch_latest_version(v) + end + else + fetch_latest_stable + end end end + + private def fetch_legacy_version(version : SemanticVersion) + response = HTTP::Client.get("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_#{version.major}") + response.body + end + + private def fetch_latest_version(version : SemanticVersion) + response = HTTP::Client.get("#{chrome_for_testing_base_url}/LATEST_RELEASE_#{version.major}") + response.body + end + + private def fetch_latest_stable + response = HTTP::Client.get("#{chrome_for_testing_base_url}/last-known-good-versions-with-downloads.json") + google = JSON.parse(response.body) + google.dig("channels", "Stable", "version").as_s + end + + private def chrome_for_testing_base_url : String + "https://googlechromelabs.github.io/chrome-for-testing" + end end diff --git a/src/webdrivers/chrome/install_driver_executor.cr b/src/webdrivers/chrome/install_driver_executor.cr index 610f274..0e203e4 100644 --- a/src/webdrivers/chrome/install_driver_executor.cr +++ b/src/webdrivers/chrome/install_driver_executor.cr @@ -3,8 +3,10 @@ class Webdrivers::Chrome::InstallDriverExecutor getter current_version : SemanticVersion? getter driver_directory : String getter driver_name : String + getter cache_path : String def initialize(@install_version, @driver_directory, @driver_name, @current_version) + @cache_path = File.join(Common.driver_directory, "chromedriver.download_url") end def execute @@ -12,9 +14,15 @@ class Webdrivers::Chrome::InstallDriverExecutor Dir.mkdir_p(driver_directory) unless File.exists?(driver_directory) + if install_version.major < 115 + normalized_driver_name = driver_name + else + normalized_driver_name = File.join("chromedriver-#{download_url_platform}", driver_name) + end + FileUtils.cd(driver_directory) do zip = download_file(from: download_url, to: download_url_filename) - Common::ZipExtractor.new(zip, File.join("chromedriver-#{download_url_platform}", driver_name), driver_directory).extract + Common::ZipExtractor.new(zip, normalized_driver_name, driver_directory).extract zip.delete File.chmod(driver_name, Common::EXECUTABLE_PERMISSIONS) end @@ -29,17 +37,33 @@ class Webdrivers::Chrome::InstallDriverExecutor end private def download_url : String - response = HTTP::Client.get(Webdrivers::Chrome::DriverRemoteVersionFinder::MANIFEST_API_ENDPOINT) - google = JSON.parse(response.body.to_s) - downloads = google.dig("channels", "Stable", "downloads", "chromedriver").as_a - platform = downloads.find! { |version| version["platform"].as_s == download_url_platform } - platform["url"].as_s + if install_version.major < 115 + "https://chromedriver.storage.googleapis.com/#{converted_version}/#{download_url_filename}" + else + fetch_download_url_for_version + end + end + + private def fetch_download_url_for_version : String + Cache.fetch(cache_path, Webdrivers.settings.cache_duration) do + response = HTTP::Client.get("#{chrome_for_testing_base_url}/known-good-versions-with-downloads.json") + google = JSON.parse(response.body.to_s) + downloads = google["versions"].as_a + version_found = downloads.find! { |version| version["version"].as_s == converted_version } + platforms = version_found.dig("downloads", "chromedriver").as_a + platform_found = platforms.find! { |platform| platform["platform"].as_s == download_url_platform } + platform_found["url"].as_s + end end private def converted_version : String SemverConverter.convert(install_version) end + private def chrome_for_testing_base_url : String + "https://googlechromelabs.github.io/chrome-for-testing" + end + # TODO: Support Win64, and Mac Intel private def download_url_platform : String case Common.os diff --git a/src/webdrivers/chromedriver.cr b/src/webdrivers/chromedriver.cr index a0aee81..4f36623 100644 --- a/src/webdrivers/chromedriver.cr +++ b/src/webdrivers/chromedriver.cr @@ -23,7 +23,7 @@ class Webdrivers::Chromedriver def self.install : String Chrome::InstallDriverExecutor.new( - install_version: latest_driver_version.not_nil!, + install_version: latest_driver_version.as(SemanticVersion), current_version: driver_version, driver_directory: Common.driver_directory, driver_name: driver_name diff --git a/src/webdrivers/common/tar_gz_extractor.cr b/src/webdrivers/common/tar_gz_extractor.cr index 5522eb3..701ad3c 100644 --- a/src/webdrivers/common/tar_gz_extractor.cr +++ b/src/webdrivers/common/tar_gz_extractor.cr @@ -9,7 +9,7 @@ class Webdrivers::Common::TarGzExtractor def extract Compress::Gzip::Reader.open(file) do |gzip| Crystar::Reader.open(gzip) do |tar| - entry = tar.next_entry.not_nil! + entry = tar.next_entry.as(Crystar::Header) destination_path = File.join(install_path, entry.name) File.delete(destination_path) if File.exists?(destination_path) File.write(destination_path, entry.io) diff --git a/src/webdrivers/geckodriver.cr b/src/webdrivers/geckodriver.cr index bfa60ea..cc5231b 100644 --- a/src/webdrivers/geckodriver.cr +++ b/src/webdrivers/geckodriver.cr @@ -17,7 +17,7 @@ class Webdrivers::Geckodriver def self.install : String Gecko::InstallDriverExecutor.new( - install_version: latest_driver_version.not_nil!, + install_version: latest_driver_version.as(SemanticVersion), current_version: driver_version, driver_directory: Common.driver_directory, driver_name: driver_name From 633536e8dd8f66529930536468d72f0bd82c5ebb Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Fri, 20 Oct 2023 16:06:15 -0700 Subject: [PATCH 4/4] fixing mac downloads --- src/webdrivers/chrome/install_driver_executor.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webdrivers/chrome/install_driver_executor.cr b/src/webdrivers/chrome/install_driver_executor.cr index 0e203e4..d38248f 100644 --- a/src/webdrivers/chrome/install_driver_executor.cr +++ b/src/webdrivers/chrome/install_driver_executor.cr @@ -70,7 +70,7 @@ class Webdrivers::Chrome::InstallDriverExecutor when Common::OS::Linux "linux64" when Common::OS::Mac - "mac-arm64" + "mac-x64" when Common::OS::Windows "win32" else