cypress 15.2.0 → 15.4.0
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/bin/cypress +1 -1
- package/{lib → dist}/cli.js +221 -190
- package/{lib → dist}/cypress.js +29 -26
- package/{lib → dist}/errors.js +38 -26
- package/{lib → dist}/exec/info.js +2 -2
- package/{lib → dist}/exec/open.js +16 -7
- package/{lib → dist}/exec/run.js +41 -27
- package/dist/exec/spawn.js +311 -0
- package/dist/exec/versions.js +67 -0
- package/{lib → dist}/exec/xvfb.js +47 -20
- package/{index.js → dist/index.js} +5 -5
- package/dist/index.mjs +9 -0
- package/{lib → dist}/tasks/cache.js +49 -52
- package/{lib → dist}/tasks/download.js +55 -64
- package/{lib → dist}/tasks/get-folder-size.js +4 -4
- package/{lib → dist}/tasks/install.js +41 -45
- package/{lib → dist}/tasks/state.js +55 -45
- package/dist/tasks/unzip.js +192 -0
- package/{lib → dist}/tasks/verify.js +121 -131
- package/{lib → dist}/util.js +39 -39
- package/package.json +13 -13
- package/types/cypress-automation.d.ts +2 -1
- package/types/cypress-npm-api.d.ts +4 -0
- package/types/cypress.d.ts +42 -29
- package/index.mjs +0 -17
- package/lib/exec/spawn.js +0 -285
- package/lib/exec/versions.js +0 -61
- package/lib/fs.js +0 -8
- package/lib/tasks/unzip.js +0 -198
- /package/{lib → dist}/VerboseRenderer.js +0 -0
- /package/{lib → dist}/exec/shared.js +0 -0
- /package/{lib → dist}/logger.js +0 -0
@@ -18,10 +18,10 @@ const path_1 = __importDefault(require("path"));
|
|
18
18
|
const chalk_1 = __importDefault(require("chalk"));
|
19
19
|
const debug_1 = __importDefault(require("debug"));
|
20
20
|
const listr2_1 = require("listr2");
|
21
|
-
const bluebird_1 = __importDefault(require("bluebird"));
|
22
21
|
const log_symbols_1 = __importDefault(require("log-symbols"));
|
23
22
|
const common_tags_1 = require("common-tags");
|
24
|
-
const
|
23
|
+
const promises_1 = __importDefault(require("timers/promises"));
|
24
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
25
25
|
const download_1 = __importDefault(require("./download"));
|
26
26
|
const util_1 = __importDefault(require("../util"));
|
27
27
|
const state_1 = __importDefault(require("./state"));
|
@@ -90,20 +90,16 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
|
90
90
|
const tasks = new listr2_1.Listr([
|
91
91
|
{
|
92
92
|
options: { title: util_1.default.titleize('Downloading Cypress') },
|
93
|
-
task: (ctx, task) => {
|
93
|
+
task: (ctx, task) => __awaiter(void 0, void 0, void 0, function* () {
|
94
94
|
// as our download progresses indicate the status
|
95
95
|
progress.onProgress = progessify(task, 'Downloading Cypress');
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
// save the download destination for unzipping
|
104
|
-
util_1.default.setTaskTitle(task, util_1.default.titleize(chalk_1.default.green('Downloaded Cypress')), rendererOptions.renderer);
|
105
|
-
});
|
106
|
-
},
|
96
|
+
const redirectVersion = yield download_1.default.start({ version, downloadDestination, progress });
|
97
|
+
if (redirectVersion)
|
98
|
+
version = redirectVersion;
|
99
|
+
debug(`finished downloading file: ${downloadDestination}`);
|
100
|
+
// save the download destination for unzipping
|
101
|
+
util_1.default.setTaskTitle(task, util_1.default.titleize(chalk_1.default.green('Downloaded Cypress')), rendererOptions.renderer);
|
102
|
+
}),
|
107
103
|
},
|
108
104
|
unzipTask({
|
109
105
|
progress,
|
@@ -113,27 +109,24 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
|
|
113
109
|
}),
|
114
110
|
{
|
115
111
|
options: { title: util_1.default.titleize('Finishing Installation') },
|
116
|
-
task: (ctx, task) => {
|
117
|
-
const cleanup = () => {
|
112
|
+
task: (ctx, task) => __awaiter(void 0, void 0, void 0, function* () {
|
113
|
+
const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
|
118
114
|
debug('removing zip file %s', downloadDestination);
|
119
|
-
|
120
|
-
};
|
121
|
-
return cleanup()
|
122
|
-
.then(() => {
|
123
|
-
debug('finished installation in', installDir);
|
124
|
-
util_1.default.setTaskTitle(task, util_1.default.titleize(chalk_1.default.green('Finished Installation'), chalk_1.default.gray(installDir)), rendererOptions.renderer);
|
115
|
+
yield fs_extra_1.default.remove(downloadDestination);
|
125
116
|
});
|
126
|
-
|
117
|
+
yield cleanup();
|
118
|
+
debug('finished installation in', installDir);
|
119
|
+
util_1.default.setTaskTitle(task, util_1.default.titleize(chalk_1.default.green('Finished Installation'), chalk_1.default.gray(installDir)), rendererOptions.renderer);
|
120
|
+
}),
|
127
121
|
},
|
128
122
|
], { rendererOptions });
|
129
123
|
// start the tasks!
|
130
|
-
return
|
131
|
-
};
|
132
|
-
const validateOS = () => {
|
133
|
-
return util_1.default.getPlatformInfo().then((platformInfo) => {
|
134
|
-
return platformInfo.match(/(win32-x64|win32-arm64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/);
|
135
|
-
});
|
124
|
+
return tasks.run();
|
136
125
|
};
|
126
|
+
const validateOS = () => __awaiter(void 0, void 0, void 0, function* () {
|
127
|
+
const platformInfo = yield util_1.default.getPlatformInfo();
|
128
|
+
return platformInfo.match(/(win32-x64|win32-arm64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/);
|
129
|
+
});
|
137
130
|
/**
|
138
131
|
* Returns the version to install - either a string like `1.2.3` to be fetched
|
139
132
|
* from the download server or a file path or HTTP URL.
|
@@ -202,14 +195,19 @@ const start = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (o
|
|
202
195
|
if (!(yield validateOS())) {
|
203
196
|
return (0, errors_1.throwFormErrorText)(errors_1.errors.invalidOS)();
|
204
197
|
}
|
205
|
-
|
206
|
-
.
|
207
|
-
|
208
|
-
|
198
|
+
try {
|
199
|
+
yield fs_extra_1.default.ensureDir(cacheDir);
|
200
|
+
}
|
201
|
+
catch (err) {
|
202
|
+
if (err.code === 'EACCES') {
|
203
|
+
return (0, errors_1.throwFormErrorText)(errors_1.errors.invalidCacheDirectory)((0, common_tags_1.stripIndent) `
|
204
|
+
Failed to access ${chalk_1.default.cyan(cacheDir)}:
|
209
205
|
|
210
|
-
|
211
|
-
|
212
|
-
|
206
|
+
${err.message}
|
207
|
+
`);
|
208
|
+
}
|
209
|
+
throw err;
|
210
|
+
}
|
213
211
|
const binaryPkg = yield state_1.default.getBinaryPkgAsync(binaryDir);
|
214
212
|
const binaryVersion = yield state_1.default.getBinaryPkgVersion(binaryPkg);
|
215
213
|
const shouldInstall = () => {
|
@@ -251,14 +249,14 @@ const start = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (o
|
|
251
249
|
}
|
252
250
|
const getLocalFilePath = () => __awaiter(void 0, void 0, void 0, function* () {
|
253
251
|
// see if version supplied is a path to a binary
|
254
|
-
if (yield
|
252
|
+
if (yield fs_extra_1.default.pathExists(versionToInstall)) {
|
255
253
|
return path_1.default.extname(versionToInstall) === '.zip' ? versionToInstall : false;
|
256
254
|
}
|
257
255
|
const possibleFile = util_1.default.formAbsolutePath(versionToInstall);
|
258
256
|
debug('checking local file', possibleFile, 'cwd', process.cwd());
|
259
257
|
// if this exists return the path to it
|
260
258
|
// else false
|
261
|
-
if ((yield
|
259
|
+
if ((yield fs_extra_1.default.pathExists(possibleFile)) && path_1.default.extname(possibleFile) === '.zip') {
|
262
260
|
return possibleFile;
|
263
261
|
}
|
264
262
|
return false;
|
@@ -287,20 +285,18 @@ const start = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (o
|
|
287
285
|
const downloadDir = os_1.default.tmpdir();
|
288
286
|
yield downloadAndUnzip({ version: versionToInstall, installDir, downloadDir });
|
289
287
|
// delay 1 sec for UX, unless we are testing
|
290
|
-
yield
|
288
|
+
yield promises_1.default.setTimeout(1000);
|
291
289
|
displayCompletionMsg();
|
292
290
|
});
|
293
291
|
const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }) => {
|
294
292
|
return {
|
295
293
|
options: { title: util_1.default.titleize('Unzipping Cypress') },
|
296
|
-
task: (ctx, task) => {
|
294
|
+
task: (ctx, task) => __awaiter(void 0, void 0, void 0, function* () {
|
297
295
|
// as our unzip progresses indicate the status
|
298
296
|
progress.onProgress = progessify(task, 'Unzipping Cypress');
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
});
|
303
|
-
},
|
297
|
+
yield unzip_1.default.start({ zipFilePath, installDir, progress });
|
298
|
+
util_1.default.setTaskTitle(task, util_1.default.titleize(chalk_1.default.green('Unzipped Cypress')), rendererOptions.renderer);
|
299
|
+
}),
|
304
300
|
};
|
305
301
|
};
|
306
302
|
const progessify = (task, title) => {
|
@@ -1,4 +1,13 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
13
|
};
|
@@ -8,7 +17,8 @@ const os_1 = __importDefault(require("os"));
|
|
8
17
|
const path_1 = __importDefault(require("path"));
|
9
18
|
const untildify_1 = __importDefault(require("untildify"));
|
10
19
|
const debug_1 = __importDefault(require("debug"));
|
11
|
-
const
|
20
|
+
const process_1 = require("process");
|
21
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
22
|
const util_1 = __importDefault(require("../util"));
|
13
23
|
const debug = (0, debug_1.default)('cypress:cli');
|
14
24
|
const getPlatformExecutable = () => {
|
@@ -59,7 +69,7 @@ const getVersionDir = (version = util_1.default.pkgVersion(), buildInfo = util_1
|
|
59
69
|
*/
|
60
70
|
const isInstallingFromPostinstallHook = () => {
|
61
71
|
// individual folders
|
62
|
-
const cwdFolders =
|
72
|
+
const cwdFolders = (0, process_1.cwd)().split(path_1.default.sep);
|
63
73
|
const length = cwdFolders.length;
|
64
74
|
return cwdFolders[length - 2] === 'node_modules' && cwdFolders[length - 1] === 'cypress';
|
65
75
|
};
|
@@ -80,19 +90,17 @@ const getCacheDir = () => {
|
|
80
90
|
}
|
81
91
|
return cache_directory;
|
82
92
|
};
|
83
|
-
const parseRealPlatformBinaryFolderAsync = (binaryPath) => {
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
});
|
95
|
-
};
|
93
|
+
const parseRealPlatformBinaryFolderAsync = (binaryPath) => __awaiter(void 0, void 0, void 0, function* () {
|
94
|
+
const realPath = yield fs_extra_1.default.realpath(binaryPath);
|
95
|
+
debug('CYPRESS_RUN_BINARY has realpath:', realPath);
|
96
|
+
if (!realPath.toString().endsWith(getPlatformExecutable())) {
|
97
|
+
return false;
|
98
|
+
}
|
99
|
+
if (os_1.default.platform() === 'darwin') {
|
100
|
+
return path_1.default.resolve(realPath, '..', '..', '..');
|
101
|
+
}
|
102
|
+
return path_1.default.resolve(realPath, '..');
|
103
|
+
});
|
96
104
|
const getDistDir = () => {
|
97
105
|
return path_1.default.join(__dirname, '..', '..', 'dist');
|
98
106
|
};
|
@@ -104,34 +112,38 @@ const getDistDir = () => {
|
|
104
112
|
const getBinaryStatePath = (binaryDir) => {
|
105
113
|
return path_1.default.join(binaryDir, '..', 'binary_state.json');
|
106
114
|
};
|
107
|
-
const getBinaryStateContentsAsync = (binaryDir) => {
|
115
|
+
const getBinaryStateContentsAsync = (binaryDir) => __awaiter(void 0, void 0, void 0, function* () {
|
108
116
|
const fullPath = getBinaryStatePath(binaryDir);
|
109
|
-
|
110
|
-
|
111
|
-
debug('
|
112
|
-
return
|
113
|
-
}
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
try {
|
118
|
+
const contents = yield fs_extra_1.default.readJson(fullPath);
|
119
|
+
debug('binary_state.json contents:', contents);
|
120
|
+
return contents;
|
121
|
+
}
|
122
|
+
catch (error) {
|
123
|
+
if (error.code === 'ENOENT' || error instanceof SyntaxError) {
|
124
|
+
debug('could not read binary_state.json file at "%s"', fullPath);
|
125
|
+
return {};
|
126
|
+
}
|
127
|
+
throw error;
|
128
|
+
}
|
129
|
+
});
|
130
|
+
const getBinaryVerifiedAsync = (binaryDir) => __awaiter(void 0, void 0, void 0, function* () {
|
131
|
+
const contents = yield getBinaryStateContentsAsync(binaryDir);
|
132
|
+
return contents.verified;
|
133
|
+
});
|
134
|
+
const clearBinaryStateAsync = (binaryDir) => __awaiter(void 0, void 0, void 0, function* () {
|
135
|
+
yield fs_extra_1.default.remove(getBinaryStatePath(binaryDir));
|
136
|
+
});
|
123
137
|
/**
|
124
138
|
* Writes the new binary status.
|
125
139
|
* @param {boolean} verified The new test runner state after smoke test
|
126
140
|
* @param {string} binaryDir Folder holding the binary
|
127
141
|
* @returns {Promise<void>} returns a promise
|
128
142
|
*/
|
129
|
-
const writeBinaryVerifiedAsync = (verified, binaryDir) => {
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
});
|
134
|
-
};
|
143
|
+
const writeBinaryVerifiedAsync = (verified, binaryDir) => __awaiter(void 0, void 0, void 0, function* () {
|
144
|
+
const contents = yield getBinaryStateContentsAsync(binaryDir);
|
145
|
+
yield fs_extra_1.default.outputJson(getBinaryStatePath(binaryDir), lodash_1.default.extend(contents, { verified }), { spaces: 2 });
|
146
|
+
});
|
135
147
|
const getPathToExecutable = (binaryDir) => {
|
136
148
|
return path_1.default.join(binaryDir, getPlatformExecutable());
|
137
149
|
};
|
@@ -139,17 +151,15 @@ const getPathToExecutable = (binaryDir) => {
|
|
139
151
|
* Resolves with an object read from the binary app package.json file.
|
140
152
|
* If the file does not exist resolves with null
|
141
153
|
*/
|
142
|
-
const getBinaryPkgAsync = (binaryDir) => {
|
154
|
+
const getBinaryPkgAsync = (binaryDir) => __awaiter(void 0, void 0, void 0, function* () {
|
143
155
|
const pathToPackageJson = getBinaryPkgPath(binaryDir);
|
144
156
|
debug('Reading binary package.json from:', pathToPackageJson);
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
});
|
152
|
-
};
|
157
|
+
const exists = yield fs_extra_1.default.pathExists(pathToPackageJson);
|
158
|
+
if (!exists) {
|
159
|
+
return null;
|
160
|
+
}
|
161
|
+
return fs_extra_1.default.readJson(pathToPackageJson);
|
162
|
+
});
|
153
163
|
const getBinaryPkgVersion = (o) => lodash_1.default.get(o, 'version', null);
|
154
164
|
const getBinaryElectronVersion = (o) => lodash_1.default.get(o, 'electronVersion', null);
|
155
165
|
const getBinaryElectronNodeVersion = (o) => lodash_1.default.get(o, 'electronNodeVersion', null);
|
@@ -0,0 +1,192 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
const lodash_1 = __importDefault(require("lodash"));
|
16
|
+
const child_process_1 = __importDefault(require("child_process"));
|
17
|
+
const os_1 = __importDefault(require("os"));
|
18
|
+
const yauzl_1 = __importDefault(require("yauzl"));
|
19
|
+
const debug_1 = __importDefault(require("debug"));
|
20
|
+
const extract_zip_1 = __importDefault(require("extract-zip"));
|
21
|
+
const readline_1 = __importDefault(require("readline"));
|
22
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
23
|
+
const errors_1 = require("../errors");
|
24
|
+
const util_1 = __importDefault(require("../util"));
|
25
|
+
const assert_1 = __importDefault(require("assert"));
|
26
|
+
const debug = (0, debug_1.default)('cypress:cli:unzip');
|
27
|
+
const unzipTools = {
|
28
|
+
extract: extract_zip_1.default,
|
29
|
+
};
|
30
|
+
// expose this function for simple testing
|
31
|
+
const unzip = (_a) => __awaiter(void 0, [_a], void 0, function* ({ zipFilePath, installDir, progress }) {
|
32
|
+
debug('unzipping from %s', zipFilePath);
|
33
|
+
debug('into', installDir);
|
34
|
+
if (!zipFilePath) {
|
35
|
+
throw new Error('Missing zip filename');
|
36
|
+
}
|
37
|
+
const startTime = Date.now();
|
38
|
+
let yauzlDoneTime = 0;
|
39
|
+
yield fs_extra_1.default.ensureDir(installDir);
|
40
|
+
yield new Promise((resolve, reject) => {
|
41
|
+
return yauzl_1.default.open(zipFilePath, (err, zipFile) => {
|
42
|
+
yauzlDoneTime = Date.now();
|
43
|
+
if (err) {
|
44
|
+
debug('error using yauzl %s', err.message);
|
45
|
+
return reject(err);
|
46
|
+
}
|
47
|
+
const total = zipFile.entryCount;
|
48
|
+
debug('zipFile entries count', total);
|
49
|
+
const started = new Date();
|
50
|
+
let percent = 0;
|
51
|
+
let count = 0;
|
52
|
+
const notify = (percent) => {
|
53
|
+
const elapsed = +new Date() - +started;
|
54
|
+
const eta = util_1.default.calculateEta(percent, elapsed);
|
55
|
+
progress.onProgress(percent, util_1.default.secsRemaining(eta));
|
56
|
+
};
|
57
|
+
const tick = () => {
|
58
|
+
count += 1;
|
59
|
+
percent = ((count / total) * 100);
|
60
|
+
const displayPercent = percent.toFixed(0);
|
61
|
+
return notify(Number(displayPercent));
|
62
|
+
};
|
63
|
+
const unzipWithNode = () => __awaiter(void 0, void 0, void 0, function* () {
|
64
|
+
debug('unzipping with node.js (slow)');
|
65
|
+
const opts = {
|
66
|
+
dir: installDir,
|
67
|
+
onEntry: tick,
|
68
|
+
};
|
69
|
+
debug('calling Node extract tool %s %o', zipFilePath, opts);
|
70
|
+
try {
|
71
|
+
yield unzipTools.extract(zipFilePath, opts);
|
72
|
+
debug('node unzip finished');
|
73
|
+
return resolve();
|
74
|
+
}
|
75
|
+
catch (err) {
|
76
|
+
const error = err || new Error('Unknown error with Node extract tool');
|
77
|
+
debug('error %s', error.message);
|
78
|
+
return reject(error);
|
79
|
+
}
|
80
|
+
});
|
81
|
+
const unzipFallback = lodash_1.default.once(unzipWithNode);
|
82
|
+
const unzipWithUnzipTool = () => {
|
83
|
+
debug('unzipping via `unzip`');
|
84
|
+
const inflatingRe = /inflating:/;
|
85
|
+
const sp = child_process_1.default.spawn('unzip', ['-o', zipFilePath, '-d', installDir]);
|
86
|
+
sp.on('error', (err) => {
|
87
|
+
debug('unzip tool error: %s', err.message);
|
88
|
+
unzipFallback();
|
89
|
+
});
|
90
|
+
sp.on('close', (code) => {
|
91
|
+
debug('unzip tool close with code %d', code);
|
92
|
+
if (code === 0) {
|
93
|
+
percent = 100;
|
94
|
+
notify(percent);
|
95
|
+
return resolve();
|
96
|
+
}
|
97
|
+
debug('`unzip` failed %o', { code });
|
98
|
+
return unzipFallback();
|
99
|
+
});
|
100
|
+
sp.stdout.on('data', (data) => {
|
101
|
+
if (inflatingRe.test(data)) {
|
102
|
+
return tick();
|
103
|
+
}
|
104
|
+
});
|
105
|
+
sp.stderr.on('data', (data) => {
|
106
|
+
debug('`unzip` stderr %s', data);
|
107
|
+
});
|
108
|
+
};
|
109
|
+
// we attempt to first unzip with the native osx
|
110
|
+
// ditto because its less likely to have problems
|
111
|
+
// with corruption, symlinks, or icons causing failures
|
112
|
+
// and can handle resource forks
|
113
|
+
// http://automatica.com.au/2011/02/unzip-mac-os-x-zip-in-terminal/
|
114
|
+
const unzipWithOsx = () => {
|
115
|
+
debug('unzipping via `ditto`');
|
116
|
+
const copyingFileRe = /^copying file/;
|
117
|
+
const sp = child_process_1.default.spawn('ditto', ['-xkV', zipFilePath, installDir]);
|
118
|
+
// f-it just unzip with node
|
119
|
+
sp.on('error', (err) => {
|
120
|
+
debug(err.message);
|
121
|
+
unzipFallback();
|
122
|
+
});
|
123
|
+
sp.on('close', (code) => {
|
124
|
+
if (code === 0) {
|
125
|
+
// make sure we get to 100% on the progress bar
|
126
|
+
// because reading in lines is not really accurate
|
127
|
+
percent = 100;
|
128
|
+
notify(percent);
|
129
|
+
return resolve();
|
130
|
+
}
|
131
|
+
debug('`ditto` failed %o', { code });
|
132
|
+
return unzipFallback();
|
133
|
+
});
|
134
|
+
return readline_1.default.createInterface({
|
135
|
+
input: sp.stderr,
|
136
|
+
})
|
137
|
+
.on('line', (line) => {
|
138
|
+
if (copyingFileRe.test(line)) {
|
139
|
+
return tick();
|
140
|
+
}
|
141
|
+
});
|
142
|
+
};
|
143
|
+
switch (os_1.default.platform()) {
|
144
|
+
case 'darwin':
|
145
|
+
return unzipWithOsx();
|
146
|
+
case 'linux':
|
147
|
+
return unzipWithUnzipTool();
|
148
|
+
case 'win32':
|
149
|
+
return unzipWithNode();
|
150
|
+
default:
|
151
|
+
return;
|
152
|
+
}
|
153
|
+
});
|
154
|
+
});
|
155
|
+
debug('unzip completed %o', {
|
156
|
+
yauzlMs: yauzlDoneTime - startTime,
|
157
|
+
unzipMs: Date.now() - yauzlDoneTime,
|
158
|
+
});
|
159
|
+
});
|
160
|
+
function isMaybeWindowsMaxPathLengthError(err) {
|
161
|
+
return os_1.default.platform() === 'win32' && err.code === 'ENOENT' && err.syscall === 'realpath';
|
162
|
+
}
|
163
|
+
const start = (_a) => __awaiter(void 0, [_a], void 0, function* ({ zipFilePath, installDir, progress }) {
|
164
|
+
assert_1.default.ok(lodash_1.default.isString(installDir) && !lodash_1.default.isEmpty(installDir), 'missing installDir');
|
165
|
+
if (!progress) {
|
166
|
+
progress = { onProgress: () => {
|
167
|
+
return {};
|
168
|
+
} };
|
169
|
+
}
|
170
|
+
try {
|
171
|
+
const installDirExists = yield fs_extra_1.default.pathExists(installDir);
|
172
|
+
if (installDirExists) {
|
173
|
+
debug('removing existing unzipped binary', installDir);
|
174
|
+
yield fs_extra_1.default.remove(installDir);
|
175
|
+
}
|
176
|
+
yield unzip({ zipFilePath, installDir, progress });
|
177
|
+
}
|
178
|
+
catch (err) {
|
179
|
+
const errorTemplate = isMaybeWindowsMaxPathLengthError(err) ?
|
180
|
+
errors_1.errors.failedUnzipWindowsMaxPathLength
|
181
|
+
: errors_1.errors.failedUnzip;
|
182
|
+
yield (0, errors_1.throwFormErrorText)(errorTemplate)(err);
|
183
|
+
}
|
184
|
+
});
|
185
|
+
const unzipModule = {
|
186
|
+
start,
|
187
|
+
utils: {
|
188
|
+
unzip,
|
189
|
+
unzipTools,
|
190
|
+
},
|
191
|
+
};
|
192
|
+
exports.default = unzipModule;
|