webdriver-manager-replacement
Version:
webdriver-manager-replacement
380 lines • 15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const childProcess = require("child_process");
const fs = require("fs");
const os = require("os");
const path = require("path");
const semver = require("semver");
const http_utils_1 = require("./utils/http_utils");
const file_utils_1 = require("./utils/file_utils");
const file_utils_2 = require("./utils/file_utils");
const provider_1 = require("./provider");
const rimraf = require("rimraf");
class Chromium extends provider_1.ProviderClass {
constructor(config) {
super();
this.cacheFileName = 'chromium-all.json';
this.cacheVersionFileName = 'chromium-version.json';
this.cacheStorageFileName = 'chromium-storage.json';
this.compressedBinaryFileName = 'chromium.zip';
this.configFileName = 'chromium.config.json';
this.ignoreSSL = false;
this.osType = os.type();
this.osArch = os.arch();
this.outDir = provider_1.OUT_DIR;
this.proxy = null;
this.maxVersion = null;
this.cacheFileName = this.setVar('cacheFileName', this.cacheFileName, config);
this.configFileName = this.setVar('configFileName', this.configFileName, config);
this.ignoreSSL = this.setVar('ignoreSSL', this.ignoreSSL, config);
this.osArch = this.setVar('osArch', this.osArch, config);
this.osType = this.setVar('osType', this.osType, config);
this.outDir = this.setVar('outDir', this.outDir, config);
this.proxy = this.setVar('proxy', this.proxy, config);
this.maxVersion = this.setVar('maxVersion', this.maxVersion, config);
}
makeDirectory(fileName) {
const dir = path.dirname(fileName);
try {
fs.mkdirSync(dir);
}
catch (err) {
}
}
/**
* Step 1: Download the json file that contains all the releases by OS. Each
* OS will have a list of release versions. The requested body will also be
* written to the out directory.
*
* The requested url is https://omahaproxy.appspot.com/all.json. Some other
* urls include a timestamped csv https://omahaproxy.appspot.com/history.
* @return Promise of the all-json file.
*/
async downloadAllJson() {
const fileName = path.resolve(this.outDir, this.cacheFileName);
if (!file_utils_2.isExpired(fileName)) {
return JSON.parse(fs.readFileSync(fileName).toString());
}
else {
this.makeDirectory(fileName);
const httpOptions = { fileName, ignoreSSL: this.ignoreSSL,
proxy: this.proxy };
if (file_utils_2.isExpired(fileName)) {
const allJsonUrl = 'https://omahaproxy.appspot.com/all.json';
let contents = await http_utils_1.requestBody(allJsonUrl, httpOptions);
contents = `{ "all": ${contents} }`;
const jsonObj = JSON.parse(contents);
fs.writeFileSync(fileName, JSON.stringify(jsonObj, null, 2));
return jsonObj;
}
else {
const contents = fs.readFileSync(fileName).toString();
return JSON.parse(contents);
}
}
}
/**
* Step 2: From the all-json object, make a request that matches the major
* version requested. The requested body will also be written to file in the
* out directory.
*
* An example of a requsted url is
* https://omahaproxy.appspot.com/deps.json?version=72.0.3626.81
* @param allJson The all-json object.
* @param majorVersion The major version, this must be a whole number.
*/
async downloadVersionJson(allJson, majorVersion) {
const fileName = path.resolve(this.outDir, this.cacheVersionFileName.replace('.json', `-${majorVersion}.json`));
if (!file_utils_2.isExpired(fileName)) {
return JSON.parse(fs.readFileSync(fileName).toString());
}
this.makeDirectory(fileName);
// Look up a version that makes sense.
const all = allJson['all'];
let os = '';
if (this.osType === 'Windows_NT') {
os = 'win';
if (this.osArch === 'x64') {
os = 'win64';
}
}
else if (this.osType === 'Linux') {
os = 'linux';
}
else {
os = 'mac';
}
let workingFullVersion = '';
const workingSemanticVersion = '0.0.0';
for (const item of all) {
if (item['os'] === os) {
const versions = item['versions'];
for (const version of versions) {
const fullVersion = version['current_version'];
const major = fullVersion.split('.')[0];
const minor = fullVersion.split('.')[1];
const patch = fullVersion.split('.')[2];
const semanticVersion = `${major}.${minor}.${patch}`;
if (majorVersion === major) {
if (semver.gt(semanticVersion, workingSemanticVersion)) {
workingFullVersion = fullVersion;
}
}
}
}
}
// Make a request and write it out to file.
const httpOptions = { fileName, ignoreSSL: this.ignoreSSL,
proxy: this.proxy };
const depsUrl = 'https://omahaproxy.appspot.com/deps.json?version=' +
workingFullVersion;
const contents = await http_utils_1.requestBody(depsUrl, httpOptions);
const jsonObj = JSON.parse(contents);
fs.writeFileSync(fileName, JSON.stringify(jsonObj, null, 2));
return jsonObj;
}
/**
* Step 3: From the downloaded-version-json object, get the revision number.
* This is the "chromium_base_position" and make a request to the storage
* bucket. If the returned value is {"kind": "storage#objects"}, then
* decrement the revision number.
*
* An example is the chromium_base_position revision number (612437).
* https://www.googleapis.com/storage/v1/b/chromium-browser-snapshots/o?delimiter=/&prefix=Linux_x64/612437/
* returns {"kind": "storage#objects"}.
*
* We keep decrementing the number until we reach 612434 where there is a list
* of items.
* @param downloadJson The download-version-json object.
* @param majorVersion The major version, this must be a whole number.
*/
async downloadStorageObject(downloadJson, majorVersion) {
const fileName = path.resolve(this.outDir, this.cacheStorageFileName.replace('.json', `-${majorVersion}.json`));
if (!file_utils_2.isExpired(fileName)) {
return JSON.parse(fs.readFileSync(fileName).toString());
}
this.makeDirectory(fileName);
let revisionUrl = 'https://www.googleapis.com/storage/v1/b/' +
'chromium-browser-snapshots/o?delimiter=/&prefix=';
let os = '';
if (this.osType === 'Windows_NT') {
os = 'Win';
if (this.osArch === 'x64') {
os = 'Win_x64';
}
}
else if (this.osType === 'Linux') {
os = 'Linux';
if (this.osArch === 'x64') {
os = 'Linux_x64';
}
}
else {
os = 'Mac';
}
revisionUrl += os + '/';
let chromiumBasePosition = downloadJson['chromium_base_position'];
const httpOptions = { fileName, ignoreSSL: this.ignoreSSL,
proxy: this.proxy };
while (chromiumBasePosition > 0) {
const revisionBasePositionUrl = `${revisionUrl}${chromiumBasePosition}/`;
const body = await http_utils_1.requestBody(revisionBasePositionUrl, httpOptions);
const jsonBody = JSON.parse(body);
if (jsonBody['items']) {
fs.writeFileSync(fileName, JSON.stringify(jsonBody, null, 2));
return jsonBody;
}
else {
chromiumBasePosition--;
}
}
return null;
}
/**
* Step 4: Get the download url for the chromium zip. Unzipping the zip file
* directory. The folders and binaries uncompressed are different for each OS.
* The following is examples of each OS:
*
* downloads/
* |- chrome-linux/chrome
* |- chrome-mac/Chromium.app
* |- chrome-win/chrome.exe
*
* @param storageObject The download-storage-json object
* @param majorVersion The major version, this must be a whole number.
*/
async downloadUrl(storageObject, majorVersion) {
const fileName = path.resolve(this.outDir, this.compressedBinaryFileName.replace('.zip', `-${majorVersion}.zip`));
if (file_utils_2.isExpired(fileName)) {
const httpOptions = { fileName, ignoreSSL: this.ignoreSSL,
proxy: this.proxy };
for (const item of storageObject['items']) {
const name = item['name'];
if (name.indexOf('chrome') >= 0) {
const downloadUrl = item['mediaLink'];
await http_utils_1.requestBinary(downloadUrl, httpOptions);
break;
}
}
}
if (this.osType === 'Linux') {
file_utils_1.unzipFile(fileName, this.outDir);
file_utils_1.changeFilePermissions(path.resolve(this.outDir, 'chrome-linux/chrome'), '0755', this.osType);
}
else if (this.osType === 'Darwin') {
spawnProcess('unzip', [fileName, '-d', this.outDir], 'ignore');
}
else if (this.osType === 'Windows_NT') {
file_utils_1.unzipFile(fileName, this.outDir);
}
}
async updateBinary(_, majorVersion) {
try {
this.cleanFiles();
}
catch (_) {
// no-op: best attempt to clean files, there can be only one version.
}
const allJson = await this.downloadAllJson();
const downloadVersionJson = await this.downloadVersionJson(allJson, majorVersion);
const storageObject = await this.downloadStorageObject(downloadVersionJson, majorVersion);
await this.downloadUrl(storageObject, majorVersion);
const binaryFolder = () => {
if (this.osType === 'Linux') {
return path.resolve(this.outDir, 'chrome-linux');
}
else if (this.osType === 'Darwin') {
return path.resolve(this.outDir, 'chrome-mac/Chromium.app/Contents/MacOS');
}
else if (this.osType === 'Windows_NT') {
return path.resolve(this.outDir, 'chrome-win');
}
throw new Error('os does not exist');
};
const binaryRegex = () => {
if (this.osType === 'Linux') {
return /chrome$/g;
}
else if (this.osType === 'Darwin') {
return /Chromium/g;
}
else if (this.osType === 'Windows_NT') {
return /chrome\.exe/g;
}
throw new Error('os does not exist');
};
const binaryFile = () => {
if (this.osType === 'Linux') {
return path.resolve(this.outDir, 'chrome-linux/chrome');
}
else if (this.osType === 'Darwin') {
return path.resolve(this.outDir, 'chrome-mac/Chromium.app/Contents/MacOS/Chromium');
}
else if (this.osType === 'Windows_NT') {
return 'chrome-win/chrome.exe';
}
throw new Error('os does not exist');
};
file_utils_1.generateConfigFile(binaryFolder(), path.resolve(this.outDir, this.configFileName), binaryRegex(), binaryFile());
}
getBinaryPath(version) {
try {
const configFilePath = path.resolve(this.outDir, this.configFileName);
return file_utils_1.getBinaryPathFromConfig(configFilePath, version);
}
catch (_) {
return null;
}
}
getStatus() {
try {
const existFiles = fs.readdirSync(this.outDir);
for (const existFile of existFiles) {
if (existFile.match(/chromium\-version\.*/g)) {
const regex = /chromium\-version\-(\d+)\.json/g;
const exec = regex.exec(existFile);
if (exec) {
return exec[1];
}
}
}
return null;
}
catch (_) {
return null;
}
}
cleanFiles() {
let chromiumPath = '';
if (this.osType === 'Darwin') {
chromiumPath = 'chrome-mac/';
}
else if (this.osType === 'Linux') {
chromiumPath = 'chrome-linux/';
}
else if (this.osType === 'Windows_NT') {
chromiumPath = 'chrome-win/';
}
rimraf.sync(path.resolve(this.outDir, chromiumPath));
const files = file_utils_1.removeFiles(this.outDir, [/chromium.*/g]);
try {
const fileList = files.split('\n');
if (files.length === 0) {
// No files listed to clean.
return '';
}
fileList.push(chromiumPath);
return (fileList.sort()).join('\n');
}
catch (_) {
// If files returns null, catch split error.
return '';
}
}
}
exports.Chromium = Chromium;
/**
* Helps translate the os type and arch to the download name associated
* with composing the download link.
* @param ostype The operating stystem type.
* @param osarch The chip architecture.
* @returns The download name associated with composing the download link.
*/
function osHelper(ostype, osarch) {
if (ostype === 'Darwin') {
return 'Mac';
}
else if (ostype === 'Windows_NT') {
if (osarch === 'x64') {
return 'Win_x64';
}
else if (osarch === 'x32') {
return 'Win';
}
}
else if (ostype === 'Linux') {
if (osarch === 'x64') {
return 'Linux_64';
}
}
return null;
}
exports.osHelper = osHelper;
/**
* A command line to run. Example 'npm start', the task='npm' and the
* opt_arg=['start']
* @param task The task string.
* @param optArg Optional task args.
* @param optIo Optional io arg. By default, it should log to console.
* @returns The child process.
*/
function spawnProcess(task, optArg, optIo) {
optArg = typeof optArg !== 'undefined' ? optArg : [];
let stdio = 'inherit';
if (optIo === 'ignore') {
stdio = 'ignore';
}
return childProcess.spawnSync(task, optArg, { stdio });
}
exports.spawnProcess = spawnProcess;
//# sourceMappingURL=chromium.js.map