refactor: move ChromiumDownloader under lib/ (#1554)

This patch:
- renames ChromiumDownloader into just Downloader (this is in
  preparation for different products download)
- moves Downloader from utils/ to lib/. This unifies all of the
  production-critical code in the lib/.

Drive-by: make Downloader a regular class.
This commit is contained in:
Andrey Lushnikov 2017-12-08 13:39:13 -08:00 committed by GitHub
parent 11d94525c8
commit 9a5086847c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 98 additions and 63 deletions

View File

@ -23,12 +23,14 @@ if (process.env.NPM_CONFIG_PUPPETEER_SKIP_CHROMIUM_DOWNLOAD || process.env.npm_c
return; return;
} }
const Downloader = require('./utils/ChromiumDownloader'); const Downloader = require('./lib/Downloader');
const platform = Downloader.currentPlatform(); const downloader = Downloader.createDefault();
const revision = require('./package').puppeteer.chromium_revision;
const platform = downloader.currentPlatform();
const revision = Downloader.defaultRevision();
const ProgressBar = require('progress'); const ProgressBar = require('progress');
const revisionInfo = Downloader.revisionInfo(platform, revision); const revisionInfo = downloader.revisionInfo(platform, revision);
// Do nothing if the revision is already downloaded. // Do nothing if the revision is already downloaded.
if (revisionInfo.downloaded) if (revisionInfo.downloaded)
return; return;
@ -45,9 +47,11 @@ if (NPM_HTTP_PROXY)
if (NPM_NO_PROXY) if (NPM_NO_PROXY)
process.env.NO_PROXY = NPM_NO_PROXY; process.env.NO_PROXY = NPM_NO_PROXY;
const allRevisions = Downloader.downloadedRevisions(); const allRevisions = downloader.downloadedRevisions();
const DOWNLOAD_HOST = process.env.PUPPETEER_DOWNLOAD_HOST || process.env.npm_config_puppeteer_download_host; const downloadHost = process.env.PUPPETEER_DOWNLOAD_HOST || process.env.npm_config_puppeteer_download_host;
Downloader.downloadRevision(platform, revision, DOWNLOAD_HOST, onProgress) if (downloadHost)
downloader.setDownloadHost(downloadHost);
downloader.downloadRevision(platform, revision, onProgress)
.then(onSuccess) .then(onSuccess)
.catch(onError); .catch(onError);
@ -57,7 +61,7 @@ Downloader.downloadRevision(platform, revision, DOWNLOAD_HOST, onProgress)
function onSuccess() { function onSuccess() {
console.log('Chromium downloaded to ' + revisionInfo.folderPath); console.log('Chromium downloaded to ' + revisionInfo.folderPath);
// Remove previous chromium revisions. // Remove previous chromium revisions.
const cleanupOldVersions = allRevisions.map(({platform, revision}) => Downloader.removeRevision(platform, revision)); const cleanupOldVersions = allRevisions.map(({platform, revision}) => downloader.removeRevision(platform, revision));
return Promise.all(cleanupOldVersions); return Promise.all(cleanupOldVersions);
} }

View File

@ -26,9 +26,7 @@ const ProxyAgent = require('https-proxy-agent');
// @ts-ignore // @ts-ignore
const getProxyForUrl = require('proxy-from-env').getProxyForUrl; const getProxyForUrl = require('proxy-from-env').getProxyForUrl;
const DOWNLOADS_FOLDER = path.join(__dirname, '..', '.local-chromium');
const DEFAULT_DOWNLOAD_HOST = 'https://storage.googleapis.com'; const DEFAULT_DOWNLOAD_HOST = 'https://storage.googleapis.com';
const downloadURLs = { const downloadURLs = {
linux: '%s/chromium-browser-snapshots/Linux_x64/%d/chrome-linux.zip', linux: '%s/chromium-browser-snapshots/Linux_x64/%d/chrome-linux.zip',
mac: '%s/chromium-browser-snapshots/Mac/%d/chrome-mac.zip', mac: '%s/chromium-browser-snapshots/Mac/%d/chrome-mac.zip',
@ -36,18 +34,50 @@ const downloadURLs = {
win64: '%s/chromium-browser-snapshots/Win_x64/%d/chrome-win32.zip', win64: '%s/chromium-browser-snapshots/Win_x64/%d/chrome-win32.zip',
}; };
module.exports = { const PROJECT_ROOT = path.join(__dirname, '..');
class Downloader {
/** /**
* @return {!Array<string>} * @param {string} downloadsFolder
*/ */
supportedPlatforms: function() { constructor(downloadsFolder) {
return Object.keys(downloadURLs); this._downloadsFolder = downloadsFolder;
}, this._downloadHost = DEFAULT_DOWNLOAD_HOST;
}
/** /**
* @return {string} * @return {string}
*/ */
currentPlatform: function() { static defaultRevision() {
return require(path.join(PROJECT_ROOT, 'package.json')).puppeteer.chromium_revision;
}
/**
* @return {!Downloader}
*/
static createDefault() {
const downloadsFolder = path.join(PROJECT_ROOT, '.local-chromium');
return new Downloader(downloadsFolder);
}
/**
* @param {string} downloadHost
*/
setDownloadHost(downloadHost) {
this._downloadHost = downloadHost;
}
/**
* @return {!Array<string>}
*/
supportedPlatforms() {
return Object.keys(downloadURLs);
}
/**
* @return {string}
*/
currentPlatform() {
const platform = os.platform(); const platform = os.platform();
if (platform === 'darwin') if (platform === 'darwin')
return 'mac'; return 'mac';
@ -56,17 +86,17 @@ module.exports = {
if (platform === 'win32') if (platform === 'win32')
return os.arch() === 'x64' ? 'win64' : 'win32'; return os.arch() === 'x64' ? 'win64' : 'win32';
return ''; return '';
}, }
/** /**
* @param {string} platform * @param {string} platform
* @param {string} revision * @param {string} revision
* @return {!Promise<boolean>} * @return {!Promise<boolean>}
*/ */
canDownloadRevision: function(platform, revision) { canDownloadRevision(platform, revision) {
console.assert(downloadURLs[platform], 'Unknown platform: ' + platform); console.assert(downloadURLs[platform], 'Unknown platform: ' + platform);
const url = util.format(downloadURLs[platform], DEFAULT_DOWNLOAD_HOST, revision); const url = util.format(downloadURLs[platform], this._downloadHost, revision);
let resolve; let resolve;
const promise = new Promise(x => resolve = x); const promise = new Promise(x => resolve = x);
@ -78,25 +108,24 @@ module.exports = {
resolve(false); resolve(false);
}); });
return promise; return promise;
}, }
/** /**
* @param {string} platform * @param {string} platform
* @param {string} revision * @param {string} revision
* @param {string} [downloadHost=DEFAULT_DOWNLOAD_HOST]
* @param {?function(number, number)} progressCallback * @param {?function(number, number)} progressCallback
* @return {!Promise} * @return {!Promise}
*/ */
downloadRevision: function(platform, revision, downloadHost = DEFAULT_DOWNLOAD_HOST, progressCallback) { downloadRevision(platform, revision, progressCallback) {
let url = downloadURLs[platform]; let url = downloadURLs[platform];
console.assert(url, `Unsupported platform: ${platform}`); console.assert(url, `Unsupported platform: ${platform}`);
url = util.format(url, downloadHost, revision); url = util.format(url, this._downloadHost, revision);
const zipPath = path.join(DOWNLOADS_FOLDER, `download-${platform}-${revision}.zip`); const zipPath = path.join(this._downloadsFolder, `download-${platform}-${revision}.zip`);
const folderPath = getFolderPath(platform, revision); const folderPath = this._getFolderPath(platform, revision);
if (fs.existsSync(folderPath)) if (fs.existsSync(folderPath))
return; return;
if (!fs.existsSync(DOWNLOADS_FOLDER)) if (!fs.existsSync(this._downloadsFolder))
fs.mkdirSync(DOWNLOADS_FOLDER); fs.mkdirSync(this._downloadsFolder);
return downloadFile(url, zipPath, progressCallback) return downloadFile(url, zipPath, progressCallback)
.then(() => extractZip(zipPath, folderPath)) .then(() => extractZip(zipPath, folderPath))
.catch(err => err) .catch(err => err)
@ -106,38 +135,38 @@ module.exports = {
if (err) if (err)
throw err; throw err;
}); });
}, }
/** /**
* @return {!Array<!{platform:string, revision: string}>} * @return {!Array<!{platform:string, revision: string}>}
*/ */
downloadedRevisions: function() { downloadedRevisions() {
if (!fs.existsSync(DOWNLOADS_FOLDER)) if (!fs.existsSync(this._downloadsFolder))
return []; return [];
const fileNames = fs.readdirSync(DOWNLOADS_FOLDER); const fileNames = fs.readdirSync(this._downloadsFolder);
return fileNames.map(fileName => parseFolderPath(fileName)).filter(revision => !!revision); return fileNames.map(fileName => parseFolderPath(fileName)).filter(revision => !!revision);
}, }
/** /**
* @param {string} platform * @param {string} platform
* @param {string} revision * @param {string} revision
* @return {!Promise} * @return {!Promise}
*/ */
removeRevision: function(platform, revision) { removeRevision(platform, revision) {
console.assert(downloadURLs[platform], `Unsupported platform: ${platform}`); console.assert(downloadURLs[platform], `Unsupported platform: ${platform}`);
const folderPath = getFolderPath(platform, revision); const folderPath = this._getFolderPath(platform, revision);
console.assert(fs.existsSync(folderPath)); console.assert(fs.existsSync(folderPath));
return new Promise(fulfill => removeRecursive(folderPath, fulfill)); return new Promise(fulfill => removeRecursive(folderPath, fulfill));
}, }
/** /**
* @param {string} platform * @param {string} platform
* @param {string} revision * @param {string} revision
* @return {!{folderPath: string, executablePath: string, downloaded: boolean}} * @return {!{revision: string, folderPath: string, executablePath: string, downloaded: boolean}}
*/ */
revisionInfo: function(platform, revision) { revisionInfo(platform, revision) {
console.assert(downloadURLs[platform], `Unsupported platform: ${platform}`); console.assert(downloadURLs[platform], `Unsupported platform: ${platform}`);
const folderPath = getFolderPath(platform, revision); const folderPath = this._getFolderPath(platform, revision);
let executablePath = ''; let executablePath = '';
if (platform === 'mac') if (platform === 'mac')
executablePath = path.join(folderPath, 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'); executablePath = path.join(folderPath, 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium');
@ -148,22 +177,25 @@ module.exports = {
else else
throw 'Unsupported platform: ' + platform; throw 'Unsupported platform: ' + platform;
return { return {
revision,
executablePath, executablePath,
folderPath, folderPath,
downloaded: fs.existsSync(folderPath) downloaded: fs.existsSync(folderPath)
}; };
}, }
};
/** /**
* @param {string} platform * @param {string} platform
* @param {string} revision * @param {string} revision
* @return {string} * @return {string}
*/ */
function getFolderPath(platform, revision) { _getFolderPath(platform, revision) {
return path.join(DOWNLOADS_FOLDER, platform + '-' + revision); return path.join(this._downloadsFolder, platform + '-' + revision);
}
} }
module.exports = Downloader;
/** /**
* @param {string} folderPath * @param {string} folderPath
* @return {?{platform: string, revision: string}} * @return {?{platform: string, revision: string}}

View File

@ -17,14 +17,13 @@ const os = require('os');
const path = require('path'); const path = require('path');
const removeFolder = require('rimraf'); const removeFolder = require('rimraf');
const childProcess = require('child_process'); const childProcess = require('child_process');
const Downloader = require('../utils/ChromiumDownloader'); const Downloader = require('./Downloader');
const {Connection} = require('./Connection'); const {Connection} = require('./Connection');
const {Browser} = require('./Browser'); const {Browser} = require('./Browser');
const readline = require('readline'); const readline = require('readline');
const fs = require('fs'); const fs = require('fs');
const {helper} = require('./helper'); const {helper} = require('./helper');
// @ts-ignore const ChromiumRevision = Downloader.defaultRevision();
const ChromiumRevision = require('../package.json').puppeteer.chromium_revision;
const mkdtempAsync = helper.promisify(fs.mkdtemp); const mkdtempAsync = helper.promisify(fs.mkdtemp);
const removeFolderAsync = helper.promisify(removeFolder); const removeFolderAsync = helper.promisify(removeFolder);
@ -88,7 +87,8 @@ class Launcher {
} }
let chromeExecutable = options.executablePath; let chromeExecutable = options.executablePath;
if (typeof chromeExecutable !== 'string') { if (typeof chromeExecutable !== 'string') {
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), ChromiumRevision); const downloader = Downloader.createDefault();
const revisionInfo = downloader.revisionInfo(downloader.currentPlatform(), ChromiumRevision);
console.assert(revisionInfo.downloaded, `Chromium revision is not downloaded. Run "npm install"`); console.assert(revisionInfo.downloaded, `Chromium revision is not downloaded. Run "npm install"`);
chromeExecutable = revisionInfo.executablePath; chromeExecutable = revisionInfo.executablePath;
} }
@ -176,7 +176,8 @@ class Launcher {
* @return {string} * @return {string}
*/ */
static executablePath() { static executablePath() {
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), ChromiumRevision); const downloader = Downloader.createDefault();
const revisionInfo = downloader.revisionInfo(downloader.currentPlatform(), ChromiumRevision);
return revisionInfo.executablePath; return revisionInfo.executablePath;
} }

View File

@ -51,12 +51,7 @@ const defaultBrowserOptions = {
}; };
// Make sure the `npm install` was run after the chromium roll. // Make sure the `npm install` was run after the chromium roll.
{ console.assert(fs.existsSync(puppeteer.executablePath()), `Chromium is not Downloaded. Run 'npm install' and try to re-run tests`);
const Downloader = require('../utils/ChromiumDownloader');
const chromiumRevision = require('../package.json').puppeteer.chromium_revision;
const revisionInfo = Downloader.revisionInfo(Downloader.currentPlatform(), chromiumRevision);
console.assert(revisionInfo.downloaded, `Chromium r${chromiumRevision} is not downloaded. Run 'npm install' and try to re-run tests.`);
}
const timeout = process.env.DEBUG_TEST || slowMo ? 0 : 10 * 1000; const timeout = process.env.DEBUG_TEST || slowMo ? 0 : 10 * 1000;

View File

@ -15,10 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
const Downloader = require('./ChromiumDownloader'); const Downloader = require('../lib/Downloader');
const https = require('https'); const https = require('https');
const OMAHA_PROXY = 'https://omahaproxy.appspot.com/all.json'; const OMAHA_PROXY = 'https://omahaproxy.appspot.com/all.json';
const downloader = Downloader.createDefault();
const colors = { const colors = {
reset: '\x1b[0m', reset: '\x1b[0m',
red: '\x1b[31m', red: '\x1b[31m',
@ -71,7 +73,7 @@ async function checkOmahaProxyAvailability() {
return; return;
} }
const table = new Table([27, 7, 7, 7, 7]); const table = new Table([27, 7, 7, 7, 7]);
table.drawRow([''].concat(Downloader.supportedPlatforms())); table.drawRow([''].concat(downloader.supportedPlatforms()));
for (const platform of platforms) { for (const platform of platforms) {
// Trust only to the main platforms. // Trust only to the main platforms.
if (platform.os !== 'mac' && platform.os !== 'win' && platform.os !== 'win64' && platform.os !== 'linux') if (platform.os !== 'mac' && platform.os !== 'win' && platform.os !== 'win64' && platform.os !== 'linux')
@ -93,7 +95,7 @@ async function checkOmahaProxyAvailability() {
*/ */
async function checkRangeAvailability(fromRevision, toRevision) { async function checkRangeAvailability(fromRevision, toRevision) {
const table = new Table([10, 7, 7, 7, 7]); const table = new Table([10, 7, 7, 7, 7]);
table.drawRow([''].concat(Downloader.supportedPlatforms())); table.drawRow([''].concat(downloader.supportedPlatforms()));
const inc = fromRevision < toRevision ? 1 : -1; const inc = fromRevision < toRevision ? 1 : -1;
for (let revision = fromRevision; revision !== toRevision; revision += inc) for (let revision = fromRevision; revision !== toRevision; revision += inc)
await checkAndDrawRevisionAvailability(table, '', revision); await checkAndDrawRevisionAvailability(table, '', revision);
@ -106,8 +108,8 @@ async function checkRangeAvailability(fromRevision, toRevision) {
*/ */
async function checkAndDrawRevisionAvailability(table, name, revision) { async function checkAndDrawRevisionAvailability(table, name, revision) {
const promises = []; const promises = [];
for (const platform of Downloader.supportedPlatforms()) for (const platform of downloader.supportedPlatforms())
promises.push(Downloader.canDownloadRevision(platform, revision)); promises.push(downloader.canDownloadRevision(platform, revision));
const availability = await Promise.all(promises); const availability = await Promise.all(promises);
const allAvailable = availability.every(e => !!e); const allAvailable = availability.every(e => !!e);
const values = [name + ' ' + (allAvailable ? colors.green + revision + colors.reset : revision)]; const values = [name + ' ' + (allAvailable ? colors.green + revision + colors.reset : revision)];

View File

@ -21,6 +21,7 @@ const Message = require('../Message');
const EXCLUDE_CLASSES = new Set([ const EXCLUDE_CLASSES = new Set([
'Connection', 'Connection',
'Downloader',
'EmulationManager', 'EmulationManager',
'FrameManager', 'FrameManager',
'Helper', 'Helper',