From dea7150f33fd44b4665f63a33266945315e01092 Mon Sep 17 00:00:00 2001 From: Nurhan Turgut <50856934+nturgut@users.noreply.github.com> Date: Fri, 18 Oct 2019 10:35:21 -0700 Subject: [PATCH] Adding firefox_installer.dart (#13185) * adding firefox downloading functionality to felt * Getting the location directly from the response --- lib/web_ui/dev/chrome_installer.dart | 23 +---- lib/web_ui/dev/common.dart | 50 ++++++++++ lib/web_ui/dev/firefox_installer.dart | 129 ++++++++++++++++++++++++++ lib/web_ui/dev/test_platform.dart | 3 +- 4 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 lib/web_ui/dev/firefox_installer.dart diff --git a/lib/web_ui/dev/chrome_installer.dart b/lib/web_ui/dev/chrome_installer.dart index 3d092a04b..c03872b92 100644 --- a/lib/web_ui/dev/chrome_installer.dart +++ b/lib/web_ui/dev/chrome_installer.dart @@ -44,14 +44,14 @@ void addChromeVersionOption(ArgParser argParser) { /// exact build nuber, such as 695653. Build numbers can be found here: /// /// https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Linux_x64/ -Future getOrInstallChrome( +Future getOrInstallChrome( String requestedVersion, { StringSink infoLog, }) async { infoLog ??= io.stdout; if (requestedVersion == 'system') { - return ChromeInstallation( + return BrowserInstallation( version: 'system', executable: await _findSystemChromeExecutable(), ); @@ -69,7 +69,7 @@ Future getOrInstallChrome( } else { infoLog.writeln('Installing Chrome version: ${installer.version}'); await installer.install(); - final ChromeInstallation installation = installer.getInstallation(); + final BrowserInstallation installation = installer.getInstallation(); infoLog.writeln( 'Installations complete. To launch it run ${installation.executable}'); } @@ -91,19 +91,6 @@ Future _findSystemChromeExecutable() async { return which.stdout; } -class ChromeInstallation { - const ChromeInstallation({ - @required this.version, - @required this.executable, - }); - - /// Chrome version. - final String version; - - /// Path the the Chrome executable. - final String executable; -} - /// Manages the installation of a particular [version] of Chrome. class ChromeInstaller { factory ChromeInstaller({ @@ -157,12 +144,12 @@ class ChromeInstaller { return versionDir.existsSync(); } - ChromeInstallation getInstallation() { + BrowserInstallation getInstallation() { if (!isInstalled) { return null; } - return ChromeInstallation( + return BrowserInstallation( version: version, executable: PlatformBinding.instance.getChromeExecutablePath(versionDir), ); diff --git a/lib/web_ui/dev/common.dart b/lib/web_ui/dev/common.dart index 1f1ad4543..99d764b08 100644 --- a/lib/web_ui/dev/common.dart +++ b/lib/web_ui/dev/common.dart @@ -4,6 +4,7 @@ import 'dart:io' as io; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart'; @@ -34,7 +35,10 @@ abstract class PlatformBinding { int getChromeBuild(YamlMap chromeLock); String getChromeDownloadUrl(String version); + String getFirefoxDownloadUrl(String version); String getChromeExecutablePath(io.Directory versionDir); + String getFirefoxExecutablePath(io.Directory versionDir); + String getFirefoxLatestVersionUrl(); } const String _kBaseDownloadUrl = @@ -54,6 +58,22 @@ class _LinuxBinding implements PlatformBinding { @override String getChromeExecutablePath(io.Directory versionDir) => path.join(versionDir.path, 'chrome-linux', 'chrome'); + + @override + String getFirefoxDownloadUrl(String version) { + return 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/${version}/linux-x86_64/en-US/firefox-${version}.tar.bz2'; + } + + @override + String getFirefoxExecutablePath(io.Directory versionDir) { + // TODO: implement getFirefoxExecutablePath + return null; + } + + @override + String getFirefoxLatestVersionUrl() { + return 'https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US'; + } } class _MacBinding implements PlatformBinding { @@ -75,4 +95,34 @@ class _MacBinding implements PlatformBinding { 'Contents', 'MacOS', 'Chromium'); + + @override + String getFirefoxDownloadUrl(String version) { + // TODO: implement getFirefoxDownloadUrl + return null; + } + + @override + String getFirefoxExecutablePath(io.Directory versionDir) { + // TODO: implement getFirefoxExecutablePath + return null; + } + + @override + String getFirefoxLatestVersionUrl() { + return 'https://download.mozilla.org/?product=firefox-latest&os=osx&lang=en-US'; + } +} + +class BrowserInstallation { + const BrowserInstallation({ + @required this.version, + @required this.executable, + }); + + /// Browser version. + final String version; + + /// Path the the browser executable. + final String executable; } diff --git a/lib/web_ui/dev/firefox_installer.dart b/lib/web_ui/dev/firefox_installer.dart new file mode 100644 index 000000000..ccf7a7e0d --- /dev/null +++ b/lib/web_ui/dev/firefox_installer.dart @@ -0,0 +1,129 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'dart:io' as io; + +import 'package:http/http.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; + +import 'common.dart'; +import 'environment.dart'; + +/// Manages the installation of a particular [version] of Firefox. +class FirefoxInstaller { + factory FirefoxInstaller({ + @required String version, + }) { + if (version == 'system') { + throw BrowserInstallerException( + 'Cannot install system version of Firefox. System Firefox must be installed manually.'); + } + if (version == 'latest') { + throw BrowserInstallerException( + 'Expected a concrete Firefox version, but got $version. Maybe use FirefoxInstaller.latest()?'); + } + final io.Directory firefoxInstallationDir = io.Directory( + path.join(environment.webUiDartToolDir.path, 'firefox'), + ); + final io.Directory versionDir = io.Directory( + path.join(firefoxInstallationDir.path, version), + ); + return FirefoxInstaller._( + version: version, + firefoxInstallationDir: firefoxInstallationDir, + versionDir: versionDir, + ); + } + + static Future latest() async { + final String latestVersion = await fetchLatestFirefoxVersion(); + return FirefoxInstaller(version: latestVersion); + } + + FirefoxInstaller._({ + @required this.version, + @required this.firefoxInstallationDir, + @required this.versionDir, + }); + + /// Firefox version managed by this installer. + final String version; + + /// HTTP client used to download Firefox. + final Client client = Client(); + + /// Root directory that contains Chrome versions. + final io.Directory firefoxInstallationDir; + + /// Installation directory for Firefox of the requested [version]. + final io.Directory versionDir; + + bool get isInstalled { + return versionDir.existsSync(); + } + + BrowserInstallation getInstallation() { + if (!isInstalled) { + return null; + } + + return BrowserInstallation( + version: version, + executable: PlatformBinding.instance.getFirefoxExecutablePath(versionDir), + ); + } + + /// Install the browser by downloading from the web. + Future install() async { + final io.File downloadedFile = await _download(); + await _uncompress(downloadedFile); + downloadedFile.deleteSync(); + } + + /// Downloads the browser version from web. + /// See [version]. + Future _download() async { + if (versionDir.existsSync()) { + versionDir.deleteSync(recursive: true); + } + + versionDir.createSync(recursive: true); + final String url = PlatformBinding.instance.getFirefoxDownloadUrl(version); + final StreamedResponse download = await client.send(Request( + 'GET', + Uri.parse(url), + )); + + final io.File downloadedFile = + io.File(path.join(versionDir.path, 'firefox.zip')); + await download.stream.pipe(downloadedFile.openWrite()); + + return downloadedFile; + } + + /// Uncompress the downloaded browser files. + /// See [version]. + Future _uncompress(io.File downloadedFile) async { + /// TODO(nturgut): Implement Install. + } + + void close() { + client.close(); + } +} + +/// Fetches the latest available Chrome build version. +Future fetchLatestFirefoxVersion() async { + final RegExp forFirefoxVersion = RegExp("firefox-[0-9.]\+[0-9]"); + final io.HttpClientRequest request = await io.HttpClient() + .getUrl(Uri.parse(PlatformBinding.instance.getFirefoxLatestVersionUrl())); + request.followRedirects = false; + // We will parse the HttpHeaders to find the redirect location. + final io.HttpClientResponse response = await request.close(); + + final String location = response.headers.value('location'); + final String version = forFirefoxVersion.stringMatch(location); + + return version.substring(version.lastIndexOf('-') + 1); +} diff --git a/lib/web_ui/dev/test_platform.dart b/lib/web_ui/dev/test_platform.dart index 3ad153e4b..99236d759 100644 --- a/lib/web_ui/dev/test_platform.dart +++ b/lib/web_ui/dev/test_platform.dart @@ -41,6 +41,7 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' as wip; import 'chrome_installer.dart'; +import 'common.dart'; import 'environment.dart' as env; import 'goldens.dart'; @@ -992,7 +993,7 @@ class Chrome extends Browser { assert(version != null); var remoteDebuggerCompleter = Completer.sync(); return Chrome._(() async { - final ChromeInstallation installation = await getOrInstallChrome( + final BrowserInstallation installation = await getOrInstallChrome( version, infoLog: isCirrus ? stdout : _DevNull(), ); -- GitLab