io.github.bonigarcia.wdm.WebDriverManager Maven / Gradle / Ivy
/*
* (C) Copyright 2015 Boni Garcia (http://bonigarcia.github.io/)
*
* 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 io.github.bonigarcia.wdm;
import static io.github.bonigarcia.wdm.Architecture.X32;
import static io.github.bonigarcia.wdm.Architecture.X64;
import static io.github.bonigarcia.wdm.Config.isNullOrEmpty;
import static io.github.bonigarcia.wdm.DriverManagerType.CHROME;
import static io.github.bonigarcia.wdm.DriverManagerType.EDGE;
import static io.github.bonigarcia.wdm.DriverManagerType.FIREFOX;
import static io.github.bonigarcia.wdm.DriverManagerType.IEXPLORER;
import static io.github.bonigarcia.wdm.DriverManagerType.OPERA;
import static io.github.bonigarcia.wdm.DriverManagerType.PHANTOMJS;
import static io.github.bonigarcia.wdm.DriverManagerType.SELENIUM_SERVER_STANDALONE;
import static io.github.bonigarcia.wdm.OperatingSystem.WIN;
import static io.github.bonigarcia.wdm.Shell.getVersionFromPosixOutput;
import static io.github.bonigarcia.wdm.Shell.getVersionFromWmicOutput;
import static io.github.bonigarcia.wdm.Shell.runAndWait;
import static java.lang.Integer.parseInt;
import static java.lang.Integer.signum;
import static java.lang.Integer.valueOf;
import static java.lang.invoke.MethodHandles.lookup;
import static java.util.Collections.sort;
import static java.util.Optional.empty;
import static javax.xml.xpath.XPathConstants.NODESET;
import static javax.xml.xpath.XPathFactory.newInstance;
import static org.apache.commons.io.FileUtils.deleteDirectory;
import static org.apache.commons.io.FileUtils.listFiles;
import static org.apache.commons.io.FilenameUtils.removeExtension;
import static org.apache.commons.lang3.StringUtils.isNumeric;
import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC;
import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.BufferedReader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.jsoup.Jsoup;
import org.slf4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.LinkedTreeMap;
/**
* Parent driver manager.
*
* @author Boni Garcia ([email protected])
* @since 2.1.0
*/
public abstract class WebDriverManager {
static final Logger log = getLogger(lookup().lookupClass());
protected static final String SLASH = "/";
protected static final String PRE_INSTALLED = "pre-installed";
protected static final String BETA = "beta";
protected static final String ONLINE = "online";
protected static final String LOCAL = "local";
protected abstract List getDrivers() throws IOException;
protected abstract Optional getBrowserVersion();
protected abstract DriverManagerType getDriverManagerType();
protected abstract String getDriverName();
protected abstract void setDriverVersion(String version);
protected abstract String getDriverVersion();
protected abstract void setDriverUrl(URL url);
protected abstract URL getDriverUrl();
protected abstract Optional getMirrorUrl();
protected abstract Optional getExportParameter();
protected static Map instanceMap = new EnumMap<>(
DriverManagerType.class);
protected HttpClient httpClient;
protected Downloader downloader;
protected UrlFilter urlFilter;
protected String versionToDownload;
protected String downloadedVersion;
protected String latestVersion;
protected String binaryPath;
protected boolean mirrorLog;
protected List listVersions;
protected boolean forcedArch;
protected boolean forcedOs;
protected boolean isLatest;
protected boolean retry = true;
protected Config config = new Config();
protected Preferences preferences = new Preferences(config);
protected String preferenceKey;
protected Properties versionsProperties;
public static Config globalConfig() {
Config global = new Config();
global.setAvoidAutoReset(true);
for (DriverManagerType type : DriverManagerType.values()) {
WebDriverManager.getInstance(type).setConfig(global);
}
return global;
}
public Config config() {
return config;
}
public static synchronized WebDriverManager chromedriver() {
if (!instanceMap.containsKey(CHROME)) {
instanceMap.put(CHROME, new ChromeDriverManager());
}
return instanceMap.get(CHROME);
}
public static synchronized WebDriverManager firefoxdriver() {
if (!instanceMap.containsKey(FIREFOX)) {
instanceMap.put(FIREFOX, new FirefoxDriverManager());
}
return instanceMap.get(FIREFOX);
}
public static synchronized WebDriverManager operadriver() {
if (!instanceMap.containsKey(OPERA)) {
instanceMap.put(OPERA, new OperaDriverManager());
}
return instanceMap.get(OPERA);
}
public static synchronized WebDriverManager edgedriver() {
if (!instanceMap.containsKey(EDGE)) {
instanceMap.put(EDGE, new EdgeDriverManager());
}
return instanceMap.get(EDGE);
}
public static synchronized WebDriverManager iedriver() {
if (!instanceMap.containsKey(IEXPLORER)) {
instanceMap.put(IEXPLORER, new InternetExplorerDriverManager());
}
return instanceMap.get(IEXPLORER);
}
public static synchronized WebDriverManager phantomjs() {
if (!instanceMap.containsKey(PHANTOMJS)) {
instanceMap.put(PHANTOMJS, new PhantomJsDriverManager());
}
return instanceMap.get(PHANTOMJS);
}
public static synchronized WebDriverManager seleniumServerStandalone() {
if (!instanceMap.containsKey(SELENIUM_SERVER_STANDALONE)) {
instanceMap.put(SELENIUM_SERVER_STANDALONE,
new SeleniumServerStandaloneManager());
}
return instanceMap.get(SELENIUM_SERVER_STANDALONE);
}
protected static synchronized WebDriverManager voiddriver() {
return new VoidDriverManager();
}
public static synchronized WebDriverManager getInstance(
DriverManagerType driverManagerType) {
if (driverManagerType == null) {
return voiddriver();
}
switch (driverManagerType) {
case CHROME:
return chromedriver();
case FIREFOX:
return firefoxdriver();
case OPERA:
return operadriver();
case IEXPLORER:
return iedriver();
case EDGE:
return edgedriver();
case PHANTOMJS:
return phantomjs();
case SELENIUM_SERVER_STANDALONE:
return seleniumServerStandalone();
default:
return voiddriver();
}
}
public static synchronized WebDriverManager getInstance(
Class> webDriverClass) {
switch (webDriverClass.getName()) {
case "org.openqa.selenium.chrome.ChromeDriver":
return chromedriver();
case "org.openqa.selenium.firefox.FirefoxDriver":
return firefoxdriver();
case "org.openqa.selenium.opera.OperaDriver":
return operadriver();
case "org.openqa.selenium.ie.InternetExplorerDriver":
return iedriver();
case "org.openqa.selenium.edge.EdgeDriver":
return edgedriver();
case "org.openqa.selenium.phantomjs.PhantomJSDriver":
return phantomjs();
default:
return voiddriver();
}
}
public synchronized void setup() {
if (getDriverManagerType() != null) {
try {
Architecture architecture = config().getArchitecture();
String driverVersion = getDriverVersion();
isLatest = isVersionLatest(driverVersion);
manage(architecture, driverVersion);
} finally {
if (!config().isAvoidAutoReset()) {
reset();
}
}
}
}
public WebDriverManager version(String version) {
setDriverVersion(version);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager architecture(Architecture architecture) {
config().setArchitecture(architecture);
forcedArch = true;
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager arch32() {
architecture(X32);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager arch64() {
architecture(X64);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager operatingSystem(OperatingSystem os) {
config().setOs(os.name());
forcedOs = true;
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager forceCache() {
config().setForceCache(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager forceDownload() {
config().setOverride(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager driverRepositoryUrl(URL url) {
setDriverUrl(url);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager useMirror() {
Optional mirrorUrl = getMirrorUrl();
if (!mirrorUrl.isPresent()) {
throw new WebDriverManagerException("Mirror URL not available");
}
config().setUseMirror(true);
setDriverUrl(mirrorUrl.get());
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager proxy(String proxy) {
config().setProxy(proxy);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager proxyUser(String proxyUser) {
config().setProxyUser(proxyUser);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager proxyPass(String proxyPass) {
config().setProxyPass(proxyPass);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager useBetaVersions() {
config().setUseBetaVersions(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager ignoreVersions(String... versions) {
config().setIgnoreVersions(versions);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager gitHubTokenName(String gitHubTokenName) {
config().setGitHubTokenName(gitHubTokenName);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager gitHubTokenSecret(String gitHubTokenSecret) {
config().setGitHubTokenSecret(gitHubTokenSecret);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager timeout(int timeout) {
config().setTimeout(timeout);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager properties(String properties) {
config().setProperties(properties);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager targetPath(String targetPath) {
config().setTargetPath(targetPath);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager avoidExport() {
config().setAvoidExport(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager avoidOutputTree() {
config().setAvoidOutputTree(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager avoidAutoVersion() {
config().setAvoidAutoVersion(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager avoidPreferences() {
config().setAvoidPreferences(true);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager ttl(int seconds) {
config().setTtl(seconds);
return instanceMap.get(getDriverManagerType());
}
public WebDriverManager browserPath(String browserPath) {
config().setBinaryPath(browserPath);
return instanceMap.get(getDriverManagerType());
}
// ------------
public String getBinaryPath() {
return instanceMap.get(getDriverManagerType()).binaryPath;
}
public String getDownloadedVersion() {
return instanceMap.get(getDriverManagerType()).downloadedVersion;
}
public List getVersions() {
httpClient = new HttpClient(config());
try {
List drivers = getDrivers();
List versions = new ArrayList<>();
for (URL url : drivers) {
String version = getCurrentVersion(url, getDriverName());
if (version.isEmpty() || version.equalsIgnoreCase("icons")) {
continue;
}
if (version.startsWith(".")) {
version = version.substring(1);
}
if (!versions.contains(version)) {
versions.add(version);
}
}
log.trace("Version list before sorting {}", versions);
sort(versions, new VersionComparator());
return versions;
} catch (IOException e) {
throw new WebDriverManagerException(e);
}
}
public void clearPreferences() {
instanceMap.get(getDriverManagerType()).preferences.clear();
}
public void clearCache() {
String targetPath = config().getTargetPath();
try {
log.debug("Clearing cache at {}", targetPath);
deleteDirectory(new File(targetPath));
} catch (Exception e) {
log.warn("Exception deleting cache at {}", targetPath, e);
}
}
// ------------
protected String preDownload(String target, String version) {
log.trace("Pre-download. target={}, version={}", target, version);
return target;
}
protected File postDownload(File archive) {
File parentFolder = archive.getParentFile();
File[] ls = parentFolder.listFiles();
for (File f : ls) {
if (getDriverName().contains(removeExtension(f.getName()))) {
log.trace("Found binary in post-download: {}", f);
return f;
}
}
throw new WebDriverManagerException("Driver " + getDriverName()
+ " not found (using temporal folder " + parentFolder + ")");
}
protected String getCurrentVersion(URL url, String driverName) {
String currentVersion = "";
try {
currentVersion = url.getFile().substring(
url.getFile().indexOf(SLASH) + 1,
url.getFile().lastIndexOf(SLASH));
} catch (StringIndexOutOfBoundsException e) {
log.trace("Exception getting version of URL {} ({})", url,
e.getMessage());
}
return currentVersion;
}
protected void manage(Architecture arch, String version) {
httpClient = new HttpClient(config());
try (HttpClient wdmHttpClient = httpClient) {
downloader = new Downloader(getDriverManagerType());
urlFilter = new UrlFilter();
boolean getLatest = isVersionLatest(version);
boolean cache = config().isForceCache();
if (getLatest) {
version = detectDriverVersionFromBrowser();
}
getLatest = isNullOrEmpty(version);
// Check latest version
if (getLatest && !config().isUseBetaVersions()) {
Optional lastVersion = getLatestVersion();
getLatest = !lastVersion.isPresent();
if (!getLatest) {
version = lastVersion.get();
}
}
// For Edge
if (checkPreInstalledVersion(version)) {
return;
}
String os = config().getOs();
log.trace("Managing {} arch={} version={} getLatest={} cache={}",
getDriverName(), arch, version, getLatest, cache);
if (getLatest && latestVersion != null) {
log.debug("Latest version of {} is {} (recently resolved)",
getDriverName(), latestVersion);
version = latestVersion;
cache = true;
}
Optional driverInCache = handleCache(arch, version, os,
getLatest, cache);
String versionStr = getLatest ? "(latest version)" : version;
if (driverInCache.isPresent() && !config().isOverride()) {
storeVersionToDownload(version);
downloadedVersion = version;
log.debug("Driver {} {} found in cache", getDriverName(),
versionStr);
exportDriver(driverInCache.get());
} else {
List candidateUrls = filterCandidateUrls(arch, version,
getLatest);
if (candidateUrls.isEmpty()) {
String errorMessage = getDriverName() + " " + versionStr
+ " for " + os + arch.toString() + " not found in "
+ getDriverUrl();
log.error(errorMessage);
throw new WebDriverManagerException(errorMessage);
}
downloadCandidateUrls(candidateUrls);
}
} catch (Exception e) {
handleException(e, arch, version);
}
}
private String detectDriverVersionFromBrowser() {
String version = "";
if (config().isAvoidAutoVersion()) {
return version;
}
Optional optionalBrowserVersion = getBrowserVersion();
if (optionalBrowserVersion.isPresent()) {
String browserVersion = optionalBrowserVersion.get();
log.trace("Detected {} version {}", getDriverManagerType(),
browserVersion);
preferenceKey = getDriverManagerType().name().toLowerCase()
+ browserVersion;
if (usePreferences()
&& preferences.checkKeyInPreferences(preferenceKey)) {
// Get driver version from preferences
version = preferences.getValueFromPreferences(preferenceKey);
} else {
// Get driver version from properties
version = getVersionForInstalledBrowser(browserVersion);
}
if (!isNullOrEmpty(version)) {
log.info(
"Using {} {} (since {} {} is installed in your machine)",
getDriverName(), version, getDriverManagerType(),
browserVersion);
}
} else {
log.debug(
"The proper {} version for your {} is unknown ... trying with the latest",
getDriverName(), getDriverManagerType());
}
return version;
}
private boolean usePreferences() {
boolean usePrefs = !config().isAvoidPreferences()
&& !config().isOverride() && !forcedArch && !forcedOs;
log.trace("Using preferences {}", usePrefs);
return usePrefs;
}
private boolean checkPreInstalledVersion(String version) {
if (version.equals(PRE_INSTALLED)) {
String systemRoot = System.getenv("SystemRoot");
File microsoftWebDriverFile = new File(systemRoot,
"System32" + File.separator + "MicrosoftWebDriver.exe");
if (microsoftWebDriverFile.exists()) {
downloadedVersion = PRE_INSTALLED;
exportDriver(microsoftWebDriverFile.toString());
return true;
} else {
retry = false;
throw new WebDriverManagerException(
"MicrosoftWebDriver.exe should be pre-installed in an elevated command prompt executing: "
+ "dism /Online /Add-Capability /CapabilityName:Microsoft.WebDriver~~~~0.0.1.0");
}
}
return false;
}
private boolean isVersionLatest(String version) {
return isNullOrEmpty(version) || version.equalsIgnoreCase("latest");
}
private String getVersionForInstalledBrowser(String browserVersion) {
String driverVersion = "";
DriverManagerType driverManagerType = getDriverManagerType();
String driverLowerCase = driverManagerType.name().toLowerCase();
Optional driverVersionForBrowser = getDriverVersionForBrowserFromProperties(
driverLowerCase + browserVersion, false);
if (driverVersionForBrowser.isPresent()) {
driverVersion = driverVersionForBrowser.get();
} else {
log.debug(
"The driver version for {} {} is unknown ... trying with latest",
driverManagerType, browserVersion);
}
return driverVersion;
}
private Optional getDriverVersionForBrowserFromProperties(
String key, boolean online) {
String onlineMessage = online ? ONLINE : LOCAL;
log.trace("Getting driver version from {} properties for {}",
onlineMessage, key);
String value = getVersionFromProperties(online).getProperty(key);
if (value == null) {
log.debug("Driver for {} not found in {} properties", key,
onlineMessage);
versionsProperties = null;
value = getVersionFromProperties(!online).getProperty(key);
}
return value == null ? empty() : Optional.of(value);
}
private Properties getVersionFromProperties(boolean online) {
if (versionsProperties != null) {
log.trace("Already created versions.properties");
return versionsProperties;
} else {
try {
InputStream inputStream = getVersionsInputStream(online);
versionsProperties = new Properties();
versionsProperties.load(inputStream);
inputStream.close();
} catch (Exception e) {
versionsProperties = null;
throw new IllegalStateException(
"Cannot read versions.properties", e);
}
return versionsProperties;
}
}
private InputStream getVersionsInputStream(boolean online)
throws IOException {
String onlineMessage = online ? ONLINE : LOCAL;
log.trace("Reading {} version.properties to find out driver version",
onlineMessage);
InputStream inputStream;
try {
if (online) {
inputStream = getOnlineVersionsInputStream();
} else {
inputStream = getLocalVersionsInputStream();
}
} catch (Exception e) {
String exceptionMessage = online ? LOCAL : ONLINE;
log.warn("Error reading version.properties, using {} instead",
exceptionMessage);
if (online) {
inputStream = getLocalVersionsInputStream();
} else {
inputStream = getOnlineVersionsInputStream();
}
}
return inputStream;
}
private InputStream getLocalVersionsInputStream() {
InputStream inputStream;
inputStream = Config.class.getResourceAsStream("/versions.properties");
return inputStream;
}
private InputStream getOnlineVersionsInputStream() throws IOException {
return httpClient
.execute(httpClient
.createHttpGet(config().getVersionsPropertiesUrl()))
.getEntity().getContent();
}
protected void handleException(Exception e, Architecture arch,
String version) {
String versionStr = isNullOrEmpty(version) ? "(latest version)"
: version;
String errorMessage = String.format(
"There was an error managing %s %s (%s)", getDriverName(),
versionStr, e.getMessage());
if (!config().isForceCache() && retry) {
config().setForceCache(true);
config().setUseMirror(true);
retry = false;
log.warn("{} ... trying again using cache and mirror",
errorMessage);
manage(arch, version);
} else {
log.error("{}", errorMessage, e);
throw new WebDriverManagerException(e);
}
}
protected void downloadCandidateUrls(List candidateUrls)
throws IOException, InterruptedException {
URL url = candidateUrls.iterator().next();
String exportValue = downloader.download(url, versionToDownload,
getDriverName());
exportDriver(exportValue);
downloadedVersion = versionToDownload;
}
protected List filterCandidateUrls(Architecture arch, String version,
boolean getLatest) throws IOException {
List urls = getDrivers();
List candidateUrls;
log.trace("All URLs: {}", urls);
boolean continueSearchingVersion;
do {
// Get the latest or concrete version
candidateUrls = getLatest ? checkLatest(urls, getDriverName())
: getVersion(urls, getDriverName(), version);
log.trace("Candidate URLs: {}", candidateUrls);
if (versionToDownload == null
|| this.getClass().equals(EdgeDriverManager.class)) {
break;
}
// Filter by OS
if (!getDriverName().equalsIgnoreCase("IEDriverServer")
&& !getDriverName()
.equalsIgnoreCase("selenium-server-standalone")) {
candidateUrls = urlFilter.filterByOs(candidateUrls,
config().getOs());
}
// Filter by architecture
candidateUrls = urlFilter.filterByArch(candidateUrls, arch,
forcedArch);
// Filter by distro
candidateUrls = filterByDistro(candidateUrls);
// Filter by ignored versions
candidateUrls = filterByIgnoredVersions(candidateUrls);
// Find out if driver version has been found or not
continueSearchingVersion = candidateUrls.isEmpty() && getLatest;
if (continueSearchingVersion) {
log.info(
"No binary found for {} {} ... seeking another version",
getDriverName(), versionToDownload);
urls = removeFromList(urls, versionToDownload);
versionToDownload = null;
}
} while (continueSearchingVersion);
return candidateUrls;
}
protected List filterByIgnoredVersions(List candidateUrls) {
if (config().getIgnoreVersions() != null && !candidateUrls.isEmpty()) {
candidateUrls = urlFilter.filterByIgnoredVersions(candidateUrls,
config().getIgnoreVersions());
}
return candidateUrls;
}
protected List filterByDistro(List candidateUrls)
throws IOException {
// Filter phantomjs 2.5.0 in Linux
if (config().getOs().equalsIgnoreCase("linux")
&& getDriverName().contains("phantomjs")) {
candidateUrls = urlFilter.filterByDistro(candidateUrls, "2.5.0");
}
return candidateUrls;
}
protected Optional handleCache(Architecture arch, String version,
String os, boolean getLatest, boolean cache) {
Optional driverInCache = empty();
if (cache || !getLatest) {
driverInCache = getDriverFromCache(version, arch, os);
}
storeVersionToDownload(version);
return driverInCache;
}
protected Optional getDriverFromCache(String driverVersion,
Architecture arch, String os) {
log.trace("Checking if {} exists in cache", getDriverName());
List filesInCache = getFilesInCache();
if (!filesInCache.isEmpty()) {
// Filter by name
filesInCache = filterCacheBy(filesInCache, getDriverName());
// Filter by version
filesInCache = filterCacheBy(filesInCache, driverVersion);
// Filter by OS
if (!getDriverName().equals("msedgedriver")) {
filesInCache = filterCacheBy(filesInCache, os.toLowerCase());
}
if (filesInCache.size() == 1) {
return Optional.of(filesInCache.get(0).toString());
}
// Filter by arch
filesInCache = filterCacheBy(filesInCache, arch.toString());
if (!filesInCache.isEmpty()) {
return Optional.of(
filesInCache.get(filesInCache.size() - 1).toString());
}
}
log.trace("{} not found in cache", getDriverName());
return empty();
}
protected List filterCacheBy(List input, String key) {
List output = new ArrayList<>(input);
if (!key.isEmpty() && !input.isEmpty()) {
for (File f : input) {
if (!f.toString().contains(key)) {
output.remove(f);
}
}
}
log.trace("Filter cache by {} -- input list {} -- output list {} ", key,
input, output);
return output;
}
protected List getFilesInCache() {
return (List) listFiles(new File(downloader.getTargetPath()),
null, true);
}
protected List removeFromList(List list, String version) {
List out = new ArrayList<>(list);
for (URL url : list) {
if (url.getFile().contains(version)) {
out.remove(url);
}
}
return out;
}
protected List getVersion(List list, String driver,
String version) {
List out = new ArrayList<>();
if (getDriverName().contains("msedgedriver")) {
int i = listVersions.indexOf(version);
if (i != -1) {
out.add(list.get(i));
}
}
for (URL url : list) {
if (url.getFile().contains(driver)
&& url.getFile().contains(version)
&& !url.getFile().contains("-symbols")) {
out.add(url);
}
}
if (versionToDownload != null && !versionToDownload.equals(version)) {
versionToDownload = version;
log.info("Using {} {}", driver, version);
}
return out;
}
protected List checkLatest(List list, String driver) {
log.trace("Checking the lastest version of {} with URL list {}", driver,
list);
List out = new ArrayList<>();
List copyOfList = new ArrayList<>(list);
for (URL url : copyOfList) {
try {
handleDriver(url, driver, out);
} catch (Exception e) {
log.trace("There was a problem with URL {} : {}", url,
e.getMessage());
list.remove(url);
}
}
storeVersionToDownload(versionToDownload);
latestVersion = versionToDownload;
log.info("Latest version of {} is {}", driver, versionToDownload);
return out;
}
protected void handleDriver(URL url, String driver, List out) {
if (!config().isUseBetaVersions()
&& (url.getFile().toLowerCase().contains("beta"))) {
return;
}
if (url.getFile().contains(driver)) {
String currentVersion = getCurrentVersion(url, driver);
if (currentVersion.equalsIgnoreCase(driver)) {
return;
}
if (versionToDownload == null) {
versionToDownload = currentVersion;
}
if (versionCompare(currentVersion, versionToDownload) > 0) {
versionToDownload = currentVersion;
out.clear();
}
if (url.getFile().contains(versionToDownload)) {
out.add(url);
}
}
}
protected boolean isUsingTaobaoMirror() {
return getDriverUrl().getHost().equalsIgnoreCase("npm.taobao.org");
}
protected Integer versionCompare(String str1, String str2) {
String[] vals1 = str1.replaceAll("v", "").split("\\.");
String[] vals2 = str2.replaceAll("v", "").split("\\.");
if (vals1[0].equals("")) {
vals1[0] = "0";
}
if (vals2[0].equals("")) {
vals2[0] = "0";
}
int i = 0;
while (i < vals1.length && i < vals2.length
&& vals1[i].equals(vals2[i])) {
i++;
}
if (i < vals1.length && i < vals2.length) {
return signum(valueOf(vals1[i]).compareTo(valueOf(vals2[i])));
} else {
return signum(vals1.length - vals2.length);
}
}
/**
* This method works also for http://npm.taobao.org/ and
* https://bitbucket.org/ mirrors.
*/
protected List getDriversFromMirror(URL driverUrl) throws IOException {
if (mirrorLog) {
log.info("Crawling driver list from mirror {}", driverUrl);
mirrorLog = true;
} else {
log.trace("[Recursive call] Crawling driver list from mirror {}",
driverUrl);
}
String driverStr = driverUrl.toString();
String driverUrlContent = driverUrl.getPath();
HttpResponse response = httpClient
.execute(httpClient.createHttpGet(driverUrl));
try (InputStream in = response.getEntity().getContent()) {
org.jsoup.nodes.Document doc = Jsoup.parse(in, null, "");
Iterator iterator = doc.select("a")
.iterator();
List urlList = new ArrayList<>();
while (iterator.hasNext()) {
String link = iterator.next().attr("href");
if (link.contains("mirror") && link.endsWith(SLASH)) {
urlList.addAll(getDriversFromMirror(new URL(
driverStr + link.replace(driverUrlContent, ""))));
} else if (link.startsWith(driverUrlContent)
&& !link.contains("icons")) {
urlList.add(new URL(
driverStr + link.replace(driverUrlContent, "")));
}
}
return urlList;
}
}
protected List getDriversFromXml(URL driverUrl) throws IOException {
log.info("Reading {} to seek {}", driverUrl, getDriverName());
List urls = new ArrayList<>();
HttpResponse response = httpClient
.execute(httpClient.createHttpGet(driverUrl));
try {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()))) {
Document xml = loadXML(reader);
NodeList nodes = (NodeList) newInstance().newXPath().evaluate(
"//Contents/Key", xml.getDocumentElement(), NODESET);
for (int i = 0; i < nodes.getLength(); ++i) {
Element e = (Element) nodes.item(i);
urls.add(new URL(driverUrl.toURI().resolve(".")
+ e.getChildNodes().item(0).getNodeValue()));
}
}
} catch (Exception e) {
throw new WebDriverManagerException(e);
}
return urls;
}
protected Document loadXML(Reader reader)
throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(reader);
return builder.parse(is);
}
protected void exportDriver(String variableValue) {
binaryPath = variableValue;
Optional exportParameter = getExportParameter();
if (!config.isAvoidExport() && exportParameter.isPresent()) {
String variableName = exportParameter.get();
log.info("Exporting {} as {}", variableName, variableValue);
System.setProperty(variableName, variableValue);
} else {
log.info("Resulting binary {}", variableValue);
}
}
protected InputStream openGitHubConnection(URL driverUrl)
throws IOException {
HttpGet get = httpClient.createHttpGet(driverUrl);
String gitHubTokenName = config().getGitHubTokenName();
String gitHubTokenSecret = config().getGitHubTokenSecret();
if (!isNullOrEmpty(gitHubTokenName)
&& !isNullOrEmpty(gitHubTokenSecret)) {
String userpass = gitHubTokenName + ":" + gitHubTokenSecret;
String basicAuth = "Basic "
+ new String(new Base64().encode(userpass.getBytes()));
get.addHeader("Authorization", basicAuth);
}
return httpClient.execute(get).getEntity().getContent();
}
protected List getDriversFromGitHub() throws IOException {
List urls;
URL driverUrl = getDriverUrl();
log.info("Reading {} to seek {}", driverUrl, getDriverName());
if (isUsingTaobaoMirror()) {
urls = getDriversFromMirror(driverUrl);
} else {
String driverVersion = versionToDownload;
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(openGitHubConnection(driverUrl)))) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
GitHubApi[] releaseArray = gson.fromJson(reader,
GitHubApi[].class);
if (driverVersion != null) {
releaseArray = new GitHubApi[] {
getVersion(releaseArray, driverVersion) };
}
urls = new ArrayList<>();
for (GitHubApi release : releaseArray) {
if (release != null) {
List> assets = release
.getAssets();
for (LinkedTreeMap asset : assets) {
urls.add(new URL(asset.get("browser_download_url")
.toString()));
}
}
}
}
}
return urls;
}
protected GitHubApi getVersion(GitHubApi[] releaseArray, String version) {
GitHubApi out = null;
for (GitHubApi release : releaseArray) {
log.trace("Get version {} of {}", version, release);
if ((release.getName() != null
&& release.getName().contains(version))
|| (release.getTagName() != null
&& release.getTagName().contains(version))) {
out = release;
break;
}
}
return out;
}
protected HttpClient getHttpClient() {
return httpClient;
}
protected FilenameFilter getFolderFilter() {
return (dir, name) -> dir.isDirectory()
&& name.toLowerCase().contains(getDriverName());
}
protected Optional getDefaultBrowserVersion(String programFilesEnv,
String winBrowserName, String linuxBrowserName,
String macBrowserName, String versionFlag,
String browserNameInOutput) {
String browserBinaryPath = config().getBinaryPath();
if (IS_OS_WINDOWS) {
String programFiles = System.getenv(programFilesEnv)
.replaceAll("\\\\", "\\\\\\\\");
String browserPath = isNullOrEmpty(browserBinaryPath)
? programFiles + winBrowserName
: browserBinaryPath;
String browserVersionOutput = runAndWait(getExecFile(), "wmic",
"datafile", "where", "name='" + browserPath + "'", "get",
"Version", "/value");
if (!isNullOrEmpty(browserVersionOutput)) {
return Optional
.of(getVersionFromWmicOutput(browserVersionOutput));
}
} else if (IS_OS_LINUX || IS_OS_MAC) {
String browserPath;
if (!isNullOrEmpty(browserBinaryPath)) {
browserPath = browserBinaryPath;
} else {
browserPath = IS_OS_LINUX ? linuxBrowserName : macBrowserName;
}
String browserVersionOutput = runAndWait(browserPath, versionFlag);
if (!isNullOrEmpty(browserVersionOutput)) {
return Optional.of(getVersionFromPosixOutput(
browserVersionOutput, browserNameInOutput));
}
}
return empty();
}
protected File getExecFile() {
String systemRoot = System.getenv("SystemRoot");
File system32 = new File(systemRoot, "System32");
if (IS_OS_WINDOWS && system32.exists() && system32.isDirectory()) {
return system32;
}
return new File(".");
}
protected Optional getLatestVersion() {
return empty();
}
protected void reset() {
config().reset();
mirrorLog = false;
listVersions = null;
versionToDownload = null;
forcedArch = false;
forcedOs = false;
retry = true;
isLatest = true;
}
protected String getProgramFilesEnv() {
return System.getProperty("os.arch").contains("64")
? "PROGRAMFILES(X86)"
: "PROGRAMFILES";
}
protected URL getDriverUrlCkeckingMirror(URL url) {
if (config().isUseMirror()) {
Optional mirrorUrl = getMirrorUrl();
if (mirrorUrl.isPresent()) {
return mirrorUrl.get();
}
}
return url;
}
public static void main(String[] args) {
String validBrowsers = "chrome|firefox|opera|edge|phantomjs|iexplorer|selenium_server_standalone";
if (args.length <= 0) {
logCliError(validBrowsers);
} else {
String arg = args[0];
if (arg.equalsIgnoreCase("server")) {
startServer(args);
} else if (arg.equalsIgnoreCase("clear-preferences")) {
new Preferences(new Config()).clear();
} else {
resolveLocal(validBrowsers, arg);
}
}
}
private static void resolveLocal(String validBrowsers, String arg) {
log.info("Using WebDriverManager to resolve {}", arg);
try {
DriverManagerType driverManagerType = DriverManagerType
.valueOf(arg.toUpperCase());
WebDriverManager wdm = WebDriverManager
.getInstance(driverManagerType).avoidExport()
.targetPath(".").avoidAutoVersion().forceDownload();
if (arg.equalsIgnoreCase("edge")
|| arg.equalsIgnoreCase("iexplorer")) {
wdm.operatingSystem(WIN);
}
wdm.avoidOutputTree().setup();
} catch (Exception e) {
log.error("Driver for {} not found (valid browsers {})", arg,
validBrowsers);
}
}
private static void startServer(String[] args) {
int port = new Config().getServerPort();
if (args.length > 1 && isNumeric(args[1])) {
port = parseInt(args[1]);
}
new Server(port);
}
private static void logCliError(String validBrowsers) {
log.error("There are 3 options to run WebDriverManager CLI");
log.error(
"1. WebDriverManager used to resolve binary drivers locally:");
log.error("\tWebDriverManager browserName");
log.error("\t(where browserName={})", validBrowsers);
log.error("2. WebDriverManager as a server:");
log.error("\tWebDriverManager server ");
log.error("\t(where default port is 4041)");
log.error(
"3. To clear previously resolved driver versions (as Java preferences):");
log.error("\tWebDriverManager clear-preferences");
}
private void storeVersionToDownload(String version) {
if (!isNullOrEmpty(version)) {
if (version.startsWith(".")) {
version = version.substring(1);
}
versionToDownload = version;
if (isLatest && usePreferences() && !isNullOrEmpty(preferenceKey)) {
preferences.putValueInPreferencesIfEmpty(preferenceKey,
version);
}
}
}
private void setConfig(Config config) {
this.config = config;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy