All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openqa.selenium.safari.SafariExtensions Maven / Gradle / Ivy

Go to download

Selenium automates browsers. That's it! What you do with that power is entirely up to you.

There is a newer version: 4.24.0
Show newest version
/*
Copyright 2012 Selenium committers
Copyright 2012 Software Freedom Conservancy

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package org.openqa.selenium.safari;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.io.Files.copy;
import static com.google.common.io.Files.write;

import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.io.TemporaryFilesystem;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import com.google.common.io.Resources;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Manages the installation of the SafariDriver browser extension. This class
 * will backup and uninstall all extensions before installing the SafariDriver
 * browser extension. The SafariDriver may currently installed from one of two
 * locations:
 * 
    *
  1. A pre-built extension included with this jar.
  2. *
  3. A pre-packaged Safari .safariextz file specified through the * {@link #EXTENSION_LOCATION_PROPERTY} system property.
  4. *
* To use a pre-installed version of the SafariDriver, set the * {@link #NO_INSTALL_EXTENSION_PROPERTY} to {@code true}. */ class SafariExtensions { private static final Logger logger = Logger.getLogger(SafariExtensions.class.getName()); /** * System property that defines the location of an existing, pre-packaged * SafariDriver extension to install. */ public static final String EXTENSION_LOCATION_PROPERTY = "webdriver.safari.driver"; /** * System property that disables installing a prebuilt SafariDriver extension on * start up. */ public static final String NO_INSTALL_EXTENSION_PROPERTY = "webdriver.safari.noinstall"; private static final String EXTENSION_RESOURCE_PATH = String.format( "/%s/SafariDriver.safariextz", SafariExtensions.class.getPackage().getName().replace('.', '/')); private static final String EXTENSION_PLIST_LINES_HEAD = Joiner.on("\n").join( "", "", "", "", "\tAvailable Updates", "\t", "\t\tLast Update Check Time", "\t\t370125644.75941497", "\t\tUpdates List", "\t\t", "\t", "\tInstalled Extensions", "\t\n"); private static final String EXTENSION_PLIST_LINES_ITEM = Joiner.on("\n").join( "\t\t", "\t\t\tAdded Non-Default Toolbar Items", "\t\t\t", "\t\t\tArchive File Name", "\t\t\t%s.safariextz", // %s = name "\t\t\tBundle Directory Name", "\t\t\t%s.safariextension", // %s = name "\t\t\tEnabled", "\t\t\t", "\t\t\tHidden Bars", "\t\t\t", "\t\t\tRemoved Default Toolbar Items", "\t\t\t", "\t\t\n"); private static final String EXTENSION_PLIST_LINES_TAIL = Joiner.on("\n").join( "\t", "\tVersion", "\t1", "", ""); private final Runtime runtime; private final Backup backup; private final Optional customDataDir; private final boolean installExtension; private final List safariExtensionFiles; private UninstallThread uninstallThread; private List installedExtensions; private File extensionPlist; /** * Installs the Driver extension and/or other user-defined extensions using a * non-standard directory for the system's Safari installation. * The configuration is derived from the {@link SafariOptions} instance. * This configuration can be overridden by explicitly setting the * {@link #NO_INSTALL_EXTENSION_PROPERTY} system property, which prevents the * SafariDriver from installing or removing extensions. * * @param options A {@link SafariOptions} instance, which provides the configuration. * @see SafariOptions#dataDir * @see SafariOptions#useCustomDriverExtension * @see SafariOptions#skipExtensionInstallation * @see SafariOptions#extensionFiles */ SafariExtensions(SafariOptions options) { this.runtime = Runtime.getRuntime(); this.backup = new Backup(); this.customDataDir = options.getDataDir(); this.installExtension = !Boolean.getBoolean(NO_INSTALL_EXTENSION_PROPERTY) && !options.getUseCustomDriverExtension(); this.safariExtensionFiles = options.getExtensions(); } /** * @return Safari's application data directory for the current platform. * @throws IllegalStateException If the current platform is unsupported. */ private static File getSafariDataDirectory() { Platform current = Platform.getCurrent(); if (Platform.MAC.is(current)) { return new File("/Users/" + System.getenv("USER"), "Library/Safari"); } else if (Platform.WINDOWS.is(current)) { return new File(System.getenv("APPDATA"), "Apple Computer/Safari"); } throw new IllegalStateException("The current platform is not supported: " + current); } /** * @param customDataDir Location of the data directory for a custom Safari * installation. If omitted, the {@link #getSafariDataDirectory() default * data directory} is used * @return The directory that the SafariDriver extension should be installed * to for the current platform. * @throws IllegalStateException If the extension cannot be installed on the * current platform. * @throws IOException If an I/O error occurs. */ private static File getInstallDirectory(Optional customDataDir) throws IOException { File dataDir = customDataDir.or(getSafariDataDirectory()); checkState(dataDir.isDirectory(), "The expected Safari data directory does not exist: %s", dataDir.getAbsolutePath()); File extensionsDir = new File(dataDir, "Extensions"); if (!extensionsDir.isDirectory()) { extensionsDir.mkdir(); } return extensionsDir; } /** * Installs the SafariDriver extension, if available. * *

Warning: This method will uninstall all currently * installed extensions. They will be restored when {@link #uninstall()} is * called. * * @throws IOException If an I/O error occurs. */ public synchronized void install() throws IOException { if (uninstallThread != null) { return; // Already installed. } int numberOfExtensions = (this.installExtension ? 1 : 0) + (safariExtensionFiles.size()); installedExtensions = Lists.newArrayListWithExpectedSize(numberOfExtensions); if (!installExtension) { logger.info("Use of custom driver extension requested; skipping installation"); if (safariExtensionFiles.isEmpty()) { return; // Nothing to install. } } File installDirectory = getInstallDirectory(customDataDir); // Install SafariDriver extension, if wanted if (installExtension) { ByteSource extensionSrc = getExtensionFromSystemProperties().or(getExtensionResource()); File targetFile = new File(installDirectory, "WebDriver.safariextz"); installExtension(extensionSrc, targetFile); } // Install other extensions, if any for (File extensionFile : safariExtensionFiles) { File targetFile = new File(installDirectory, extensionFile.getName()); if (targetFile.getCanonicalPath().equals(extensionFile.getCanonicalPath())) { // The user wants to keep using an existing extension, // and added the path of an existing extension to the list. // Back-up the .safariextz file, because Safari will remove it on installation backup.backup(targetFile); installedExtensions.add(targetFile); continue; } ByteSource extensionSrc = Files.asByteSource(extensionFile); installExtension(extensionSrc, targetFile); } // Create Extensions.plist (backup if needed) replaceExtensionsPlist(installDirectory); uninstallThread = new UninstallThread(); runtime.addShutdownHook(uninstallThread); } /** * Copy a Safari extension to the target location. Any existing file is backed up. */ private synchronized void installExtension(ByteSource extensionSrc, File targetFile) throws IOException { if (targetFile.exists()) { backup.backup(targetFile); } extensionSrc.copyTo(Files.asByteSink(targetFile)); installedExtensions.add(targetFile); } private synchronized void replaceExtensionsPlist(File installDirectory) throws IOException { extensionPlist = new File(installDirectory, "Extensions.plist"); if (extensionPlist.exists()) { backup.backup(extensionPlist); } // Generate Extensions.plist and save it StringBuilder plistContent = new StringBuilder(EXTENSION_PLIST_LINES_HEAD); for (File extensionFile : installedExtensions) { String basename = Files.getNameWithoutExtension(extensionFile.getName()); // Strip .safariextz plistContent.append(String.format(EXTENSION_PLIST_LINES_ITEM, basename, basename)); } plistContent.append(EXTENSION_PLIST_LINES_TAIL); write(plistContent.toString(), extensionPlist, Charsets.UTF_8); } private static Optional getExtensionFromSystemProperties() throws FileNotFoundException { String extensionPath = System.getProperty(EXTENSION_LOCATION_PROPERTY); if (Strings.isNullOrEmpty(extensionPath)) { return Optional.absent(); } File extensionSrc = new File(extensionPath); checkState(extensionSrc.isFile(), "The SafariDriver extension specified through the %s system property does not exist: %s", EXTENSION_LOCATION_PROPERTY, extensionPath); checkState(extensionSrc.canRead(), "The SafariDriver extension specified through the %s system property is not readable: %s", EXTENSION_LOCATION_PROPERTY, extensionPath); logger.info("Using extension " + extensionSrc.getAbsolutePath()); return Optional.of(Files.asByteSource(extensionSrc)); } private static ByteSource getExtensionResource() { URL url = SafariExtensions.class.getResource(EXTENSION_RESOURCE_PATH); checkNotNull(url, "Unable to locate extension resource, %s", EXTENSION_RESOURCE_PATH); return Resources.asByteSource(url); } /** * Un-installs all extensions installed by this Safari driver, and restores backed-up files. * * @throws IOException If an I/O error occurs. */ public synchronized void uninstall() throws IOException { if (uninstallThread != null) { try { runtime.removeShutdownHook(uninstallThread); } catch (IllegalStateException shutdownInProgress) { // Do nothing. } uninstallThread = null; for (File installedExtension : installedExtensions) { installedExtension.delete(); } // .safariextz installation files are automatically deleted on install, // but the Extensions.plist file has to be deleted manually. extensionPlist.delete(); backup.restoreAll(); } } private static class Backup { private final TemporaryFilesystem filesystem = TemporaryFilesystem.getDefaultTmpFS(); private final Map backups = Maps.newHashMap(); private File backupDir; File backup(File file) throws IOException { if (backupDir == null) { backupDir = filesystem.createTempDir("SafariBackups", "webdriver"); } File backup = new File(backupDir, file.getName()); copy(file, backup); backups.put(file, backup); return backup; } void restoreAll() throws IOException { for (Map.Entry entry : backups.entrySet()) { File originalLocation = entry.getKey(); File backup = entry.getValue(); copy(backup, originalLocation); } } } private class UninstallThread extends Thread { @Override public void run() { try { uninstall(); } catch (IOException e) { throw new WebDriverException("Unable to uninstall extension", e); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy