presidium 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Docker.js +3 -4
- package/GoogleChromeDevTools.js +902 -0
- package/S3Bucket.js +12 -8
- package/index.js +0 -1
- package/internal/Archive.js +113 -0
- package/internal/Archive.test.js +71 -0
- package/internal/GoogleChromeForTesting.js +218 -0
- package/internal/GoogleChromeForTesting.test.js +50 -0
- package/internal/parsePath.js +2 -2
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD3-9B6F.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD4-9B86.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978250-A191.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978251-A1AD.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978277-A1FA.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978278-A209.pma +0 -0
- package/internal/tmp/chrome/ChromeFeatureState +1 -0
- package/internal/tmp/chrome/Default/Affiliation Database +0 -0
- package/internal/tmp/chrome/Default/Affiliation Database-journal +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOCK +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOG +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/000003.log +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/CURRENT +1 -0
- package/internal/tmp/chrome/Default/Extension Rules/LOCK +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/LOG +3 -0
- package/internal/tmp/chrome/Default/Extension Rules/LOG.old +3 -0
- package/internal/tmp/chrome/Default/Extension Rules/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/000003.log +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/CURRENT +1 -0
- package/internal/tmp/chrome/Default/Extension Scripts/LOCK +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/LOG +3 -0
- package/internal/tmp/chrome/Default/Extension Scripts/LOG.old +3 -0
- package/internal/tmp/chrome/Default/Extension Scripts/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Favicons +0 -0
- package/internal/tmp/chrome/Default/Favicons-journal +0 -0
- package/internal/tmp/chrome/Default/History +0 -0
- package/internal/tmp/chrome/Default/History-journal +0 -0
- package/internal/tmp/chrome/Default/LOCK +0 -0
- package/internal/tmp/chrome/Default/LOG +0 -0
- package/internal/tmp/chrome/Default/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/000003.log +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/CURRENT +1 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/LOCK +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/LOG +2 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOCK +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG.old +0 -0
- package/internal/tmp/chrome/Default/README +1 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/ServerCertificate +0 -0
- package/internal/tmp/chrome/Default/ServerCertificate-journal +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/000003.log +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/CURRENT +1 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOCK +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOG +3 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOG.old +3 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/000003.log +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/CURRENT +1 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG +3 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG.old +3 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOG +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOG +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOG +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOG +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOG +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db +0 -0
- package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db-journal +0 -0
- package/internal/tmp/chrome/First Run +0 -0
- package/internal/tmp/chrome/Last Version +1 -0
- package/internal/tmp/chrome/Local State +1 -0
- package/internal/tmp/chrome/ShaderCache/data_0 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_1 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_2 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_3 +0 -0
- package/internal/tmp/chrome/ShaderCache/index +0 -0
- package/internal/tmp/chrome/Variations +1 -0
- package/internal/tmp/chrome/segmentation_platform/ukm_db +0 -0
- package/internal/tmp/chrome/segmentation_platform/ukm_db-wal +0 -0
- package/package.json +3 -2
- package/Archive.js +0 -120
package/S3Bucket.js
CHANGED
|
@@ -1309,11 +1309,12 @@ class S3Bucket {
|
|
|
1309
1309
|
searchParams.set('versionId', options.VersionId)
|
|
1310
1310
|
}
|
|
1311
1311
|
|
|
1312
|
+
const encodedKey = encodeURIComponentRFC3986(key).replace(/%2F/g, '/')
|
|
1312
1313
|
const response = await this._awsRequest1(
|
|
1313
1314
|
'GET',
|
|
1314
1315
|
searchParams.size > 0
|
|
1315
|
-
? `/${
|
|
1316
|
-
: `/${
|
|
1316
|
+
? `/${encodedKey}?${searchParams.toString()}`
|
|
1317
|
+
: `/${encodedKey}`,
|
|
1317
1318
|
headers,
|
|
1318
1319
|
''
|
|
1319
1320
|
)
|
|
@@ -1500,11 +1501,12 @@ class S3Bucket {
|
|
|
1500
1501
|
searchParams.set('versionId', options.VersionId)
|
|
1501
1502
|
}
|
|
1502
1503
|
|
|
1504
|
+
const encodedKey = encodeURIComponentRFC3986(key).replace(/%2F/g, '/')
|
|
1503
1505
|
const response = await this._awsRequest1(
|
|
1504
1506
|
'GET',
|
|
1505
1507
|
searchParams.size > 0
|
|
1506
|
-
? `/${
|
|
1507
|
-
: `/${
|
|
1508
|
+
? `/${encodedKey}?acl&${searchParams.toString()}`
|
|
1509
|
+
: `/${encodedKey}?acl`,
|
|
1508
1510
|
headers,
|
|
1509
1511
|
''
|
|
1510
1512
|
)
|
|
@@ -1750,11 +1752,12 @@ class S3Bucket {
|
|
|
1750
1752
|
searchParams.set('versionId', options.VersionId)
|
|
1751
1753
|
}
|
|
1752
1754
|
|
|
1755
|
+
const encodedKey = encodeURIComponentRFC3986(key).replace(/%2F/g, '/')
|
|
1753
1756
|
const response = await this._awsRequest1(
|
|
1754
1757
|
'HEAD',
|
|
1755
1758
|
searchParams.size > 0
|
|
1756
|
-
? `/${
|
|
1757
|
-
: `/${
|
|
1759
|
+
? `/${encodedKey}?${searchParams.toString()}`
|
|
1760
|
+
: `/${encodedKey}`,
|
|
1758
1761
|
headers,
|
|
1759
1762
|
''
|
|
1760
1763
|
)
|
|
@@ -1976,11 +1979,12 @@ class S3Bucket {
|
|
|
1976
1979
|
searchParams.set('versionId', options.VersionId)
|
|
1977
1980
|
}
|
|
1978
1981
|
|
|
1982
|
+
const encodedKey = encodeURIComponentRFC3986(key).replace(/%2F/g, '/')
|
|
1979
1983
|
const response = await this._awsRequest1(
|
|
1980
1984
|
'DELETE',
|
|
1981
1985
|
searchParams.size > 0
|
|
1982
|
-
? `/${
|
|
1983
|
-
: `/${
|
|
1986
|
+
? `/${encodedKey}?${searchParams.toString()}`
|
|
1987
|
+
: `/${encodedKey}`,
|
|
1984
1988
|
headers,
|
|
1985
1989
|
''
|
|
1986
1990
|
)
|
package/index.js
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require('rubico/global')
|
|
2
|
+
const tarStream = require('tar-stream')
|
|
3
|
+
const fs = require('fs/promises')
|
|
4
|
+
const walk = require('./walk')
|
|
5
|
+
const pipe = require('rubico/pipe')
|
|
6
|
+
const tap = require('rubico/tap')
|
|
7
|
+
const get = require('rubico/get')
|
|
8
|
+
const reduce = require('rubico/reduce')
|
|
9
|
+
const thunkify = require('rubico/thunkify')
|
|
10
|
+
const pick = require('rubico/pick')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @name Archive
|
|
14
|
+
*/
|
|
15
|
+
const Archive = {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @name Archive.tar
|
|
19
|
+
*
|
|
20
|
+
* @docs
|
|
21
|
+
* ```coffeescript [specscript]
|
|
22
|
+
* module tar 'https://github.com/mafintosh/tar-stream'
|
|
23
|
+
*
|
|
24
|
+
* Archive.tar(path string, options {
|
|
25
|
+
* ignore: Array<string>,
|
|
26
|
+
* base: Object<string>,
|
|
27
|
+
* }) -> pack tar.Pack
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* Bundle multiple files and directories from a parent directory into a tarball.
|
|
31
|
+
*
|
|
32
|
+
* Arguments:
|
|
33
|
+
* * `path` - the path to the parent directory which contains the files and directories to bundle.
|
|
34
|
+
* * `options`
|
|
35
|
+
* * `ignore` - filepaths, filenames, or patterns to ignore.
|
|
36
|
+
*/
|
|
37
|
+
Archive.tar = function tar(path, options) {
|
|
38
|
+
const pathWithSlash = path.endsWith('/') ? path : `${path}/`
|
|
39
|
+
const ignore = get(options, 'ignore')
|
|
40
|
+
const pack = tarStream.pack()
|
|
41
|
+
|
|
42
|
+
pipe(path, [
|
|
43
|
+
walk,
|
|
44
|
+
filter(path => {
|
|
45
|
+
for (const part of ignore) {
|
|
46
|
+
if (path.includes(part)) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return true
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
reduce(async (pack, filepath) => {
|
|
54
|
+
pack.entry({
|
|
55
|
+
name: filepath.replace(pathWithSlash, ''),
|
|
56
|
+
...pipe([
|
|
57
|
+
fs.stat,
|
|
58
|
+
pick(['size', 'mode', 'mtime', 'uid', 'gid']),
|
|
59
|
+
])(filepath),
|
|
60
|
+
}, await fs.readFile(filepath))
|
|
61
|
+
return pack
|
|
62
|
+
}, pack),
|
|
63
|
+
|
|
64
|
+
tap(pack => {
|
|
65
|
+
const base = options.base ?? {}
|
|
66
|
+
for (const filename in base) {
|
|
67
|
+
pack.entry({ name: filename }, base[filename])
|
|
68
|
+
}
|
|
69
|
+
pack.finalize()
|
|
70
|
+
}),
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
return pack
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @name untar
|
|
78
|
+
*
|
|
79
|
+
* @docs
|
|
80
|
+
* ```coffeescript [specscript]
|
|
81
|
+
* module tar 'https://github.com/mafintosh/tar-stream'
|
|
82
|
+
* module presidium 'https://presidium.services/docs'
|
|
83
|
+
*
|
|
84
|
+
* Archive.untar(pack tar.Pack) ->
|
|
85
|
+
* contentMap Promise<Map<(filepath string)=>(content presidium.Readable)> >
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* Extract a tarball into a map of file paths to content streams.
|
|
89
|
+
*
|
|
90
|
+
* Arguments:
|
|
91
|
+
* * `pack` - a tarball represented by the `tar.Pack` type. Returned by the [tar](#tar) method.
|
|
92
|
+
*/
|
|
93
|
+
Archive.untar = function untar(pack) {
|
|
94
|
+
const extractStream = tarStream.extract()
|
|
95
|
+
const extracted = new Map()
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
extractStream.on('entry', (header, stream, next) => {
|
|
98
|
+
stream.header = header
|
|
99
|
+
extracted.set(header.name, stream)
|
|
100
|
+
next()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
extractStream.on('finish', () => {
|
|
104
|
+
resolve(extracted)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
extractStream.on('error', reject)
|
|
108
|
+
|
|
109
|
+
pack.pipe(extractStream)
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = Archive
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const assert = require('assert')
|
|
2
|
+
const stream = require('stream')
|
|
3
|
+
const fs = require('fs/promises')
|
|
4
|
+
const Test = require('thunk-test')
|
|
5
|
+
const Archive = require('./Archive')
|
|
6
|
+
const resolvePath = require('./resolvePath')
|
|
7
|
+
const map = require('rubico/map')
|
|
8
|
+
const reduce = require('rubico/reduce')
|
|
9
|
+
const Readable = require('../Readable')
|
|
10
|
+
|
|
11
|
+
const test = new Test('Archive', async function integration() {
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
const pack = await Archive.tar(__dirname, {
|
|
15
|
+
ignore: ['Dockerfile', 'node_modules', '.git', '.nyc_output'],
|
|
16
|
+
})
|
|
17
|
+
const extracted = await Archive.untar(pack)
|
|
18
|
+
assert(extracted.size > 0)
|
|
19
|
+
for (const [path, entry] of extracted) {
|
|
20
|
+
assert('header' in entry)
|
|
21
|
+
assert(!path.startsWith('/'))
|
|
22
|
+
assert.equal(typeof path, 'string')
|
|
23
|
+
assert.equal(typeof entry[Symbol.asyncIterator], 'function')
|
|
24
|
+
assert(entry.readable)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
const base = {
|
|
30
|
+
Dockerfile: 'FROM node:15-alpine'
|
|
31
|
+
}
|
|
32
|
+
const ignore = ['fixtures']
|
|
33
|
+
const pack = await Archive.tar(__dirname, { ignore, base })
|
|
34
|
+
const extracted = await Archive.untar(pack)
|
|
35
|
+
const dir = await fs.readdir(__dirname)
|
|
36
|
+
.then(filter(n => !ignore.includes(n)))
|
|
37
|
+
const extractedKeys = [...extracted.keys()]
|
|
38
|
+
assert.equal(extracted.size, dir.length + 1) // extra Dockerfile
|
|
39
|
+
assert(extracted.has('Dockerfile'))
|
|
40
|
+
assert.equal(
|
|
41
|
+
await reduce(extracted.get('Dockerfile'), (a, b) => a + b, ''),
|
|
42
|
+
'FROM node:15-alpine'
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
const base = {
|
|
48
|
+
Dockerfile: 'FROM busybox:1.32',
|
|
49
|
+
'.aws/credentials': '[presidium]\naccessKeyId\nsecretAccessKey',
|
|
50
|
+
}
|
|
51
|
+
const pack = await Archive.tar(`${__dirname}/`, {
|
|
52
|
+
ignore: ['hashJSON.js'],
|
|
53
|
+
base,
|
|
54
|
+
})
|
|
55
|
+
const extracted = await Archive.untar(pack)
|
|
56
|
+
assert(extracted.size > 0)
|
|
57
|
+
assert(extracted.has('Dockerfile'))
|
|
58
|
+
assert(extracted.has('.aws/credentials'))
|
|
59
|
+
assert.equal(
|
|
60
|
+
await reduce(extracted.get('Dockerfile'), (a, b) => a + b, ''),
|
|
61
|
+
'FROM busybox:1.32'
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}).case()
|
|
66
|
+
|
|
67
|
+
if (process.argv[1] == __filename) {
|
|
68
|
+
test()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = test
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
const https = require('https')
|
|
2
|
+
const os = require('os')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const { spawn } = require('child_process')
|
|
6
|
+
const readline = require('readline')
|
|
7
|
+
const extract = require('extract-zip')
|
|
8
|
+
const HTTP = require('../HTTP')
|
|
9
|
+
const XML = require('../XML')
|
|
10
|
+
const Readable = require('../Readable')
|
|
11
|
+
const walk = require('./walk')
|
|
12
|
+
|
|
13
|
+
async function getChromeVersions() {
|
|
14
|
+
const http = new HTTP()
|
|
15
|
+
const response = await http.GET('https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json')
|
|
16
|
+
const data = await Readable.JSON(response)
|
|
17
|
+
return data
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function updateConsoleLog(message) {
|
|
21
|
+
readline.cursorTo(process.stdout, 0, undefined);
|
|
22
|
+
readline.clearLine(process.stdout, 0);
|
|
23
|
+
process.stdout.write(message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function getChromeUrl() {
|
|
27
|
+
let platform = os.platform()
|
|
28
|
+
if (platform == 'darwin') {
|
|
29
|
+
platform = 'mac'
|
|
30
|
+
}
|
|
31
|
+
const arch = os.arch()
|
|
32
|
+
|
|
33
|
+
if (platform == 'mac') {
|
|
34
|
+
platform = `${platform}-${arch}`
|
|
35
|
+
} else {
|
|
36
|
+
platform = `${platform}${arch.slice(1)}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let url
|
|
40
|
+
if (['stable', 'beta', 'dev', 'canary'].includes(this.chromeVersion)) {
|
|
41
|
+
const chromeVersions = await getChromeVersions()
|
|
42
|
+
const channel = `${this.chromeVersion[0].toUpperCase()}${this.chromeVersion.slice(1)}`
|
|
43
|
+
const chromeVersionNumber = chromeVersions.channels[channel].version
|
|
44
|
+
url = `https://storage.googleapis.com/chrome-for-testing-public/${chromeVersionNumber}/${platform}/chrome-${platform}.zip`
|
|
45
|
+
} else {
|
|
46
|
+
const chromeVersionNumber = this.chromeVersion
|
|
47
|
+
url = `https://storage.googleapis.com/chrome-for-testing-public/${chromeVersionNumber}/${platform}/chrome-${platform}.zip`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return url
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function installChrome() {
|
|
54
|
+
const url = await getChromeUrl.call(this)
|
|
55
|
+
let filepath = `${this.chromeDir}/${url.replace('https://storage.googleapis.com/chrome-for-testing-public/', '')}`
|
|
56
|
+
if (!filepath.startsWith('/')) {
|
|
57
|
+
filepath = path.join(process.cwd(), filepath)
|
|
58
|
+
}
|
|
59
|
+
let parentDir = `${filepath.split('/').slice(0, -1).join('/')}`
|
|
60
|
+
if (!parentDir.startsWith('/')) {
|
|
61
|
+
parentDir = path.join(process.cwd(), parentDir)
|
|
62
|
+
}
|
|
63
|
+
await fs.promises.mkdir(parentDir, { recursive: true })
|
|
64
|
+
|
|
65
|
+
const http = new HTTP()
|
|
66
|
+
const response = await http.GET(url)
|
|
67
|
+
const contentLength = response.headers['content-length']
|
|
68
|
+
|
|
69
|
+
await fs.promises.mkdir(parentDir, { recursive: true })
|
|
70
|
+
const fileStream = fs.createWriteStream(filepath)
|
|
71
|
+
// response.pipe(fileStream)
|
|
72
|
+
|
|
73
|
+
let downloadedLength = 0
|
|
74
|
+
response.on('data', chunk => {
|
|
75
|
+
downloadedLength += chunk.length
|
|
76
|
+
if (downloadedLength == contentLength) {
|
|
77
|
+
updateConsoleLog(`Downloading ${url} (${downloadedLength} / ${contentLength} bytes)\n`)
|
|
78
|
+
} else {
|
|
79
|
+
updateConsoleLog(`Downloading ${url} (${downloadedLength} / ${contentLength} bytes)`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fileStream.write(chunk)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
let resolve
|
|
86
|
+
const promise = new Promise(_resolve => {
|
|
87
|
+
resolve = _resolve
|
|
88
|
+
})
|
|
89
|
+
response.on('end', () => {
|
|
90
|
+
resolve()
|
|
91
|
+
})
|
|
92
|
+
await promise
|
|
93
|
+
|
|
94
|
+
await extract(filepath, { dir: parentDir })
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function getChromeFilepath() {
|
|
98
|
+
const url = await getChromeUrl.call(this)
|
|
99
|
+
const filepath = `${this.chromeDir}/${url.replace('https://storage.googleapis.com/chrome-for-testing-public/', '')}`
|
|
100
|
+
const parentDir = `${filepath.split('/').slice(0, -1).join('/')}`
|
|
101
|
+
|
|
102
|
+
const googleChromeForTestingFilepath = `${parentDir}`
|
|
103
|
+
try {
|
|
104
|
+
for await (const filepath of walk(parentDir)) {
|
|
105
|
+
console.log(filepath)
|
|
106
|
+
if (filepath.endsWith('Google Chrome for Testing')) {
|
|
107
|
+
return filepath
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error.code == 'ENOENT') {
|
|
112
|
+
await installChrome.call(this)
|
|
113
|
+
const filepath = await getChromeFilepath.call(this)
|
|
114
|
+
return filepath
|
|
115
|
+
}
|
|
116
|
+
throw error
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
throw new Error('unable to find Google Chrome for Testing executable.')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @name GoogleChromeForTesting
|
|
124
|
+
*
|
|
125
|
+
* @docs
|
|
126
|
+
* ```coffeescript [specscript]
|
|
127
|
+
* new GoogleChromeForTesting(options {
|
|
128
|
+
* chromeVersion: 'stable'|'beta'|'dev'|'canary'|string,
|
|
129
|
+
* remoteDebuggingPort: number,
|
|
130
|
+
* headless: boolean,
|
|
131
|
+
* userDataDir: string,
|
|
132
|
+
* useMockKeychain: boolean,
|
|
133
|
+
* }) -> GoogleChromeForTesting
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* References:
|
|
137
|
+
* * [Chrome for Testing availability](https://googlechromelabs.github.io/chrome-for-testing/)
|
|
138
|
+
*/
|
|
139
|
+
class GoogleChromeForTesting {
|
|
140
|
+
constructor(options = {}) {
|
|
141
|
+
this.chromeVersion = options.chromeVersion ?? 'stable'
|
|
142
|
+
this.chromeDir = options.chromeDir ?? 'google-chrome-for-testing'
|
|
143
|
+
this.remoteDebuggingPort = options.remoteDebuggingPort ?? 9222
|
|
144
|
+
this.headless = options.headless ?? false
|
|
145
|
+
this.userDataDir = options.userDataDir ?? './tmp/chrome'
|
|
146
|
+
this.useMockKeychain = options.useMockKeychain ?? false
|
|
147
|
+
this.devtoolsUrl = undefined
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @name init
|
|
152
|
+
*
|
|
153
|
+
* @docs
|
|
154
|
+
* ```coffeescript [specscript]
|
|
155
|
+
* init() -> Promise<>
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
async init() {
|
|
159
|
+
const chromeFilepath = await getChromeFilepath.call(this)
|
|
160
|
+
console.log('spawn', chromeFilepath)
|
|
161
|
+
|
|
162
|
+
const cmd = spawn(chromeFilepath, [
|
|
163
|
+
`--remote-debugging-port=${this.remoteDebuggingPort}`,
|
|
164
|
+
`--user-data-dir=${this.userDataDir}`,
|
|
165
|
+
...this.headless ? ['--headless'] : [],
|
|
166
|
+
...this.useMockKeychain ? ['--use-mock-keychain'] : [],
|
|
167
|
+
])
|
|
168
|
+
cmd.stdout.pipe(process.stdout)
|
|
169
|
+
cmd.stderr.pipe(process.stderr)
|
|
170
|
+
|
|
171
|
+
const devtoolsUrlPromiseWithResolvers = Promise.withResolvers()
|
|
172
|
+
cmd.stderr.on('data', chunk => {
|
|
173
|
+
const line = chunk.toString('utf8').trim()
|
|
174
|
+
if (line.includes('DevTools listening on')) {
|
|
175
|
+
const devtoolsUrl = line.replace('DevTools listening on ', '')
|
|
176
|
+
devtoolsUrlPromiseWithResolvers.resolve(devtoolsUrl)
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
const spawnPromiseWithResolvers = Promise.withResolvers()
|
|
181
|
+
cmd.on('spawn', () => {
|
|
182
|
+
spawnPromiseWithResolvers.resolve()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
cmd.on('error', error => {
|
|
186
|
+
console.error(error)
|
|
187
|
+
process.exit(1)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
process.on('SIGTERM', () => {
|
|
191
|
+
cmd.kill()
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
process.on('exit', () => {
|
|
195
|
+
cmd.kill()
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
this.cmd = cmd
|
|
199
|
+
|
|
200
|
+
await spawnPromiseWithResolvers.promise
|
|
201
|
+
this.devtoolsUrl = await devtoolsUrlPromiseWithResolvers.promise
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @name close
|
|
206
|
+
*
|
|
207
|
+
* @docs
|
|
208
|
+
* ```coffeescript [specscript]
|
|
209
|
+
* close() -> undefined
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
close() {
|
|
213
|
+
this.cmd.kill('SIGKILL')
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = GoogleChromeForTesting
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const Test = require('thunk-test')
|
|
2
|
+
const assert = require('assert')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const { exec } = require('child_process')
|
|
5
|
+
const Readable = require('../Readable')
|
|
6
|
+
const GoogleChromeForTesting = require('./GoogleChromeForTesting')
|
|
7
|
+
|
|
8
|
+
const test = new Test('GoogleChromeForTesting', async function integration() {
|
|
9
|
+
await fs.promises.rm('google-chrome-for-testing', { recursive: true, force: true })
|
|
10
|
+
|
|
11
|
+
const cmd = await exec('ps aux | grep "Google Chrome for Testing" | awk \'{print $2}\' | xargs kill', {
|
|
12
|
+
stdio: 'inherit',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
const googleChromeForTesting = new GoogleChromeForTesting({
|
|
17
|
+
userDataDir: `${__dirname}/tmp/chrome`,
|
|
18
|
+
useMockKeychain: true,
|
|
19
|
+
})
|
|
20
|
+
await googleChromeForTesting.init()
|
|
21
|
+
|
|
22
|
+
assert.equal(typeof googleChromeForTesting.devtoolsUrl, 'string')
|
|
23
|
+
assert(googleChromeForTesting.devtoolsUrl.startsWith('ws://'))
|
|
24
|
+
|
|
25
|
+
googleChromeForTesting.close()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
const googleChromeForTesting = new GoogleChromeForTesting({
|
|
30
|
+
userDataDir: `${__dirname}/tmp/chrome`,
|
|
31
|
+
useMockKeychain: true,
|
|
32
|
+
})
|
|
33
|
+
await googleChromeForTesting.init()
|
|
34
|
+
|
|
35
|
+
assert.equal(typeof googleChromeForTesting.devtoolsUrl, 'string')
|
|
36
|
+
assert(googleChromeForTesting.devtoolsUrl.startsWith('ws://'))
|
|
37
|
+
|
|
38
|
+
googleChromeForTesting.close()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
await fs.promises.rm('google-chrome-for-testing', { recursive: true, force: true })
|
|
42
|
+
|
|
43
|
+
console.log('Success')
|
|
44
|
+
}).case()
|
|
45
|
+
|
|
46
|
+
if (process.argv[1] == __filename) {
|
|
47
|
+
test()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = test
|
package/internal/parsePath.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const path = require('path')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @name parsePath
|
|
@@ -14,6 +14,6 @@ const nodePath = require('path')
|
|
|
14
14
|
* }
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
const parsePath =
|
|
17
|
+
const parsePath = path.parse
|
|
18
18
|
|
|
19
19
|
module.exports = parsePath
|