| Index: tools/testing/dart/reset_safari.dart
|
| diff --git a/tools/testing/dart/reset_safari.dart b/tools/testing/dart/reset_safari.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e1886a5442ca861c7248ae4a9daffe21f0bbd88a
|
| --- /dev/null
|
| +++ b/tools/testing/dart/reset_safari.dart
|
| @@ -0,0 +1,227 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +
|
| +/// Helper program for killing and resetting all Safari settings to a known
|
| +/// state that works well for testing dart2js output in Safari.
|
| +///
|
| +/// Warning: this will delete all your Safari settings and bookmarks.
|
| +library testing.reset_safari;
|
| +
|
| +import 'dart:async' show
|
| + Future,
|
| + Timer;
|
| +
|
| +import 'dart:io' show
|
| + Directory,
|
| + File,
|
| + Platform,
|
| + Process,
|
| + ProcessResult;
|
| +
|
| +const String defaultSafariBundleLocation = "/Applications/Safari.app/";
|
| +
|
| +const String relativeSafariLocation = "Contents/MacOS/Safari";
|
| +
|
| +const String lsofLocation = "/usr/sbin/lsof";
|
| +
|
| +const String killLocation = "/bin/kill";
|
| +
|
| +const String pkillLocation = "/usr/bin/pkill";
|
| +
|
| +const String safari = "com.apple.Safari";
|
| +
|
| +const String defaultsLocation = "/usr/bin/defaults";
|
| +
|
| +final List<String> safariSettings = <String>[
|
| + "Library/Caches/$safari",
|
| + "Library/Safari",
|
| + "Library/Saved Application State/$safari.savedState",
|
| + "Library/Caches/Metadata/Safari",
|
| + "Library/Preferences/$safari.plist",
|
| +];
|
| +
|
| +const Duration defaultPollDelay = const Duration(milliseconds: 1);
|
| +
|
| +final String cpgi = "$safari.ContentPageGroupIdentifier";
|
| +
|
| +final String knownSafariPreference = '''
|
| +{
|
| + DefaultBrowserPromptingState2 = 2;
|
| + StartPageViewControllerMode = 0;
|
| + TestDriveOriginBrowser = 1;
|
| + TestDriveUserDecision = 2;
|
| + TestDriveState = 3;
|
| + AlwaysRestoreSessionAtLaunch = 0;
|
| + NewTabBehavior = 1;
|
| + NewWindowBehavior = 1;
|
| + LastSafariVersionWithWelcomePage = "9.0";
|
| + OpenNewTabsInFront = 0;
|
| + TabCreationPolicy = 0;
|
| +
|
| + IncludeDevelopMenu = 1;
|
| + WebKitDeveloperExtrasEnabledPreferenceKey = 1;
|
| + "$cpgi.WebKit2DeveloperExtrasEnabled" = 1;
|
| +
|
| + AutoFillCreditCardData = 0;
|
| + AutoFillMiscellaneousForms = 0;
|
| + AutoFillPasswords = 0;
|
| +
|
| + SuppressSearchSuggestions = 1;
|
| +
|
| + PreloadTopHit = 0;
|
| + ShowFavoritesUnderSmartSearchField = 0;
|
| + WebsiteSpecificSearchEnabled = 0;
|
| +
|
| + WarnAboutFraudulentWebsites = 0;
|
| +
|
| +
|
| + WebKitJavaScriptEnabled = 1;
|
| + "$cpgi.WebKit2JavaScriptEnabled" = 1;
|
| +
|
| + WebKitJavaScriptCanOpenWindowsAutomatically = 1;
|
| + "$cpgi.WebKit2JavaScriptCanOpenWindowsAutomatically" = 1;
|
| +
|
| + "$cpgi.WebKit2WebGLEnabled" = 1;
|
| + WebGLDefaultLoadPolicy = WebGLPolicyAllowNoSecurityRestrictions;
|
| +
|
| + "$cpgi.WebKit2PluginsEnabled" = 0;
|
| +
|
| + BlockStoragePolicy = 1;
|
| + WebKitStorageBlockingPolicy = 0;
|
| + "$cpgi.WebKit2StorageBlockingPolicy" = 0;
|
| +
|
| +
|
| + SafariGeolocationPermissionPolicy = 0;
|
| +
|
| + CanPromptForPushNotifications = 0;
|
| +
|
| + InstallExtensionUpdatesAutomatically = 0;
|
| +
|
| + ShowFullURLInSmartSearchField = 1;
|
| +
|
| + "$cpgi.WebKit2PlugInSnapshottingEnabled" = 0;
|
| +}
|
| +''';
|
| +
|
| +Future<Null> get pollDelay => new Future.delayed(defaultPollDelay);
|
| +
|
| +String signalArgument(
|
| + String defaultSignal,
|
| + {bool force: false,
|
| + bool testOnly: false}) {
|
| + if (force && testOnly) {
|
| + throw new ArgumentError("[force] and [testOnly] can't both be true.");
|
| + }
|
| + if (force) return "-KILL";
|
| + if (testOnly) return "-0";
|
| + return defaultSignal;
|
| +}
|
| +
|
| +Future<int> kill(
|
| + List<String> pids,
|
| + {bool force: false,
|
| + bool testOnly: false}) async {
|
| + List<String> arguments =
|
| + <String>[signalArgument("-TERM", force: force, testOnly: testOnly)]
|
| + ..addAll(pids);
|
| + ProcessResult result = await Process.run(killLocation, arguments);
|
| + return result.exitCode;
|
| +}
|
| +
|
| +Future<int> pkill(
|
| + String pattern,
|
| + {bool force: false,
|
| + bool testOnly: false}) async {
|
| + List<String> arguments = <String>[
|
| + signalArgument("-HUP", force: force, testOnly: testOnly),
|
| + pattern];
|
| + ProcessResult result = await Process.run(pkillLocation, arguments);
|
| + return result.exitCode;
|
| +}
|
| +
|
| +Uri validatedBundleName(Uri bundle) {
|
| + if (bundle == null) return Uri.base.resolve(defaultSafariBundleLocation);
|
| + if (!bundle.path.endsWith("/")) {
|
| + throw new ArgumentError(
|
| + "Bundle ('$bundle') must end with a slash ('/').");
|
| + }
|
| + return bundle;
|
| +}
|
| +
|
| +Future<Null> killSafari({Uri bundle}) async {
|
| + bundle = validatedBundleName(bundle);
|
| + Uri safariBinary = bundle.resolve(relativeSafariLocation);
|
| + ProcessResult result = await Process.run(
|
| + lsofLocation, ["-t", safariBinary.toFilePath()]);
|
| + if (result.exitCode == 0) {
|
| + String stdout = result.stdout;
|
| + List<String> pids = new List<String>.from(
|
| + stdout.split("\n").where((String line) => !line.isEmpty));
|
| + Timer timer = new Timer(const Duration(seconds: 10), () {
|
| + print("Kill -9 Safari $pids");
|
| + kill(pids, force: true);
|
| + });
|
| + int exitCode = await kill(pids);
|
| + while (exitCode == 0) {
|
| + await pollDelay;
|
| + print("Polling Safari $pids");
|
| + exitCode = await kill(pids, testOnly: true);
|
| + }
|
| + timer.cancel();
|
| + }
|
| + Timer timer = new Timer(const Duration(seconds: 10), () {
|
| + print("Kill -9 $safari");
|
| + pkill(safari, force: true);
|
| + });
|
| + int exitCode = await pkill(safari);
|
| + while (exitCode == 0) {
|
| + await pollDelay;
|
| + print("Polling $safari");
|
| + exitCode = await pkill(safari, testOnly: true);
|
| + }
|
| + timer.cancel();
|
| +}
|
| +
|
| +Future<Null> deleteIfExists(Uri uri) async {
|
| + Directory directory = new Directory.fromUri(uri);
|
| + if (await directory.exists()) {
|
| + print("Deleting directory '$uri'.");
|
| + await directory.delete(recursive: true);
|
| + } else {
|
| + File file = new File.fromUri(uri);
|
| + if (await file.exists()) {
|
| + print("Deleting file '$uri'.");
|
| + await file.delete();
|
| + } else {
|
| + print("File '$uri' not found.");
|
| + }
|
| + }
|
| +}
|
| +
|
| +Future<Null> resetSafariSettings() async {
|
| + String home = Platform.environment["HOME"];
|
| + if (!home.endsWith("/")) {
|
| + home = "$home/";
|
| + }
|
| + Uri homeDirectory = Uri.base.resolve(home);
|
| + for (String setting in safariSettings) {
|
| + await deleteIfExists(homeDirectory.resolve(setting));
|
| + }
|
| + ProcessResult result = await Process.run(
|
| + defaultsLocation, <String>["write", safari, knownSafariPreference]);
|
| + if (result.exitCode != 0) {
|
| + throw "Unable to reset Safari settings: ${result.stdout}${result.stderr}";
|
| + }
|
| +}
|
| +
|
| +Future<Null> killAndResetSafari({Uri bundle}) async {
|
| + bundle = validatedBundleName(bundle);
|
| + await killSafari(bundle: bundle);
|
| + await resetSafariSettings();
|
| +}
|
| +
|
| +Future<Null> main() async {
|
| + await killAndResetSafari();
|
| +}
|
|
|