Skip to content

Conversation

@aslushnikov
Copy link
Contributor

@aslushnikov aslushnikov commented Feb 6, 2018

This patch introduces BrowserFetcher class that manages
downloaded versions of products.

This patch:

  • shapes Downloader API to be minimal yet usable for our needs. This
    includes removing such methods as Downloader.supportedPlatforms and
    Downloader.defaultRevision.
  • makes most of the fs-related methods in Downloader async. The only
    exception is the Downloader.revisionInfo: it has stay sync due to the
    pptr.executablePath() method being sync.
  • updates install.js and utils/check_availability.js to use new API
  • finally, renames Downloader into BrowserFetcher

Fixes #1748.

This patch introduces `Downloader` class that manages
downloaded versions of products.

This patch:
- shapes Downloader API to be minimal yet usable for our needs. This
  includes removing such methods as `Downloader.supportedPlatforms` and
  `Downloader.defaultRevision`.
- makes most of the fs-related methods in Downloader async. The only
  exception is the `Downloader.revisionInfo`: it has stay sync due to the
  `pptr.executablePath()` method being sync.
- updates `install.js` and `utils/check_availability.js` to use new API.

Fixes puppeteer#1748.
class Downloader {
/**
* @return {!Array<string>}
* @param {!Object=} options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we jsdoc these options? It's a bit hard to read otherwise.

docs/api.md Outdated
The method initiates a HEAD request to check if revision is available.

#### downloader.downloadRevision(revision[, progressCallback])
- `revision` <[string]> a revision to check availability.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a revision to download.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated

Downloader is created per platform and operates revisions: strings representing 6-digit numbers, e.g. `"533271"`. Revisions could be checked with [omahaproxy.appspot.com](http://omahaproxy.appspot.com/).

> **NOTE** Downloader class is not designed to work concurrently with other instances of Downloader class.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me want to have it as a namespace with configurable options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constrained can be removed with a lock file if we need to. I'd keep it as implementation detail without hardcoding into the API: it shouldn't yield much confusion.

Copy link
Contributor

@JoelEinbinder JoelEinbinder Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Downloader class ... of the Downloader class

docs/api.md Outdated
- returns: <[Promise]> Resolves when the revision is downloaded

#### downloader.revisionInfo(revision)
- `revision` <[string]> a revision to get info.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to get info for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

else if (platform === 'linux')
this._platform = 'linux';
else if (platform === 'win32')
this._platform = os.arch() === 'x64' ? 'win64' : 'win32';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.assert(this._platform, 'Unsupported platform: ' + os.platform());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
- `folderPath` <[string]> path to the extracted revision folder
- `executablePath` <[string]> path to the revision executable
- `url` <[string]> URL this revision can be downloaded from
- `downloaded` <[boolean]> weather the revision is downloaded or not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whether

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated

### class: Downloader

A Downloader is manages downloaded chromium instances.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Downloader can download and manage different versions of Chromium.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated

A Downloader is manages downloaded chromium instances.

Downloader is created per platform and operates revisions: strings representing 6-digit numbers, e.g. `"533271"`. Revisions could be checked with [omahaproxy.appspot.com](http://omahaproxy.appspot.com/).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Downloader operates on revision strings that specify a precise version of Chromium, e.g. "533271". Revision strings can be obtained from omahaproxy.appspot.com.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
The method initiates a GET request to download revision from the host.

#### downloader.downloadedRevisions()
- returns: <[Promise]<[Array]<[string]>>> a list of all revisions downloaded for the given platform
Copy link
Contributor

@JoelEinbinder JoelEinbinder Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

storedRevisions

A list of all revisions previously downloaded for the current platform.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
#### downloader.downloadRevision(revision[, progressCallback])
- `revision` <[string]> a revision to download.
- `progressCallback` <[function]> A function that will be called with two arguments:
- `downloadedBytes` <[number]> how many bytes are downloaded
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have been downloaded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
- `revision` <[string]> a revision to download.
- `progressCallback` <[function]> A function that will be called with two arguments:
- `downloadedBytes` <[number]> how many bytes are downloaded
- `totalBytes` <[number]> how many bytes is the total download
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How large is the total download.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
- `options` <[Object]>
- `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`.
- `path` <[string]> A path for the downloads folder. Defaults `<root>/.local-chromium`, where `<root>` is puppeteer's package root.
- `platform` <[string]> Specify binary type. Possible values are: `mac`, `win32`, `win64`, `linux`. Defaults to the current platform.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop: Specify binary type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
#### puppeteer.createDownloader([options])
- `options` <[Object]>
- `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`.
- `path` <[string]> A path for the downloads folder. Defaults `<root>/.local-chromium`, where `<root>` is puppeteer's package root.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
- `revision` <[string]> a revision to check availability.
- returns: <[Promise]<[boolean]>> returns `true` if the revision could be downloaded from the host.

The method initiates a HEAD request to check if revision is available.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the revision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated

#### downloader.downloadRevision(revision[, progressCallback])
- `revision` <[string]> a revision to download.
- `progressCallback` <[function]> A function that will be called with two arguments:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<[function]([number], [number])>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
- `totalBytes` <[number]> how many bytes is the total download
- returns: <[Promise]> Resolves when the revision is downloaded and extracted

The method initiates a GET request to download revision from the host.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method ... the revision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated

#### downloader.removeRevision(revision)
- `revision` <[string]> a revision to remove. The method will throw if the revision is not downloaded.
- returns: <[Promise]> Resolves when the revision is downloaded
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has been downloaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
- returns: <[string]> Downloader target platform. Returns one of the `mac`, `linux`, `win32` or `win64`.

#### downloader.removeRevision(revision)
- `revision` <[string]> a revision to remove. The method will throw if the revision is not downloaded.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has not been downloaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
- returns: <[Promise]<[Array]<[string]>>> a list of all revisions downloaded for the given platform

#### downloader.platform()
- returns: <[string]> Downloader target platform. Returns one of the `mac`, `linux`, `win32` or `win64`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns one of the ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

docs/api.md Outdated
- `folderPath` <[string]> path to the extracted revision folder
- `executablePath` <[string]> path to the revision executable
- `url` <[string]> URL this revision can be downloaded from
- `downloaded` <[boolean]> wether the revision is downloaded or not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has been downloaded or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const downloader = Downloader.createDefault();
const downloadHost = process.env.PUPPETEER_DOWNLOAD_HOST || process.env.npm_config_puppeteer_download_host;

const puppeteer = require('./index');
Copy link
Contributor

@JoelEinbinder JoelEinbinder Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work on node 6???

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course! the index.js is the one that checks for async/await support and picks the right puppeteer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you checkout from the GitHub and run npm install? Do we built before downloading somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoelEinbinder yes, we build in the very first line of the script

Copy link
Contributor

@JoelEinbinder JoelEinbinder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulirish can you take a look at the api? Thanks.

docs/api.md Outdated
- `host` <[string]> A download host to be used. Defaults to `https://storage.googleapis.com`.
- `path` <[string]> A path for the downloads folder. Defaults to `<root>/.local-chromium`, where `<root>` is puppeteer's package root.
- `platform` <[string]> Possible values are: `mac`, `win32`, `win64`, `linux`. Defaults to the current platform.
- returns: <[Downloader]>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing bottom reference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@aslushnikov aslushnikov requested a review from paulirish February 7, 2018 00:02
expect(await downloader.canDownload('123456')).toBe(true);

await downloader.download('123456');
expect(await readFileAsync(revisionInfo.executablePath, 'utf8')).toBe('LINUX BINARY\n');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the executablePath is defined before the binary is downloaded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the revisionInfo could be called for both downloaded and non-downloaded revisions.

Copy link
Contributor

@paulirish paulirish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the expected use, right?

// I want to use a different revision than the one in package.json...

const downloader = puppeteer.createDownloader();
await downloader.download('621459');
const revisionInfo = downloader.revisionInfo('621459');

await puppeteer.launch({executablePath: revisionInfo.executablePath})

docs/api.md Outdated
- `folderPath` <[string]> path to the extracted revision folder
- `executablePath` <[string]> path to the revision executable
- `url` <[string]> URL this revision can be downloaded from
- `downloaded` <[boolean]> wether the revision has been downloaded or not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whether

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

docs/api.md Outdated
- `progressCallback` <[function]([number], [number])> A function that will be called with two arguments:
- `downloadedBytes` <[number]> how many bytes have been downloaded
- `totalBytes` <[number]> how large is the total download.
- returns: <[Promise]> Resolves when the revision is downloaded and extracted
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it return revisionInfo?
seems optional but kinda nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like returning revisionInfo, done.

docs/api.md Outdated
- `folderPath` <[string]> path to the extracted revision folder
- `executablePath` <[string]> path to the revision executable
- `url` <[string]> URL this revision can be downloaded from
- `downloaded` <[boolean]> wether the revision has been downloaded or not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i download and then remove a rev, what will revInfo.downloaded tell me? does this property really mean "currently on disk" ? maybe available?

also if i do any of these actions in separate downloader instances (assuming same host/path/platform), does it matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i download and then remove a rev, what will revInfo.downloaded tell me? does this property really mean "currently on disk" ?

Yes, that's 'currently on disk'.

also if i do any of these actions in separate downloader instances (assuming same host/path/platform), does it matter?

There are no guarantees in this case. If two downloaders try to download the same revision simultaneously, they will fight with each other and fail in some weird way.

There's a note about this in the description of downloader class.

@aslushnikov
Copy link
Contributor Author

This is the expected use, right?

@paulirish yeah. Also I'd expect different scripts for downloading and running, like we have install.js.

Also, with the download method returning revisionInfo, your example becomes a little nicer.

docs/api.md Outdated

### class: Downloader

A Downloader can download and manage different versions of Chromium.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChromiumDownloader? At first I thought this PR was for handing file downloads, but I see that's it for downloading Chromium. I wonder if the name should be more explicit?

createDownloader -> createChromiumDownloader too. Thoughts?

Copy link
Contributor Author

@aslushnikov aslushnikov Feb 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ebidel in a follow-up, I'll teach it to download content_shell builds, so it's not solely about chromium.

@aslushnikov aslushnikov changed the title feat: Introduce Downloader class feat: Introduce BrowserFetcher class Feb 7, 2018
@aslushnikov aslushnikov merged commit a363a73 into puppeteer:master Feb 7, 2018
@aslushnikov aslushnikov deleted the introduce-downloader branch May 9, 2018 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants