mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Use native tar or 7z.exe for extracting tar.gz files when possible.
This commit is contained in:
@@ -12,6 +12,7 @@ var util = require('util');
|
||||
var _ = require('underscore');
|
||||
var Fiber = require('fibers');
|
||||
var crypto = require('crypto');
|
||||
var spawn = require("child_process").spawn;
|
||||
|
||||
var rimraf = require('rimraf');
|
||||
var sourcemap = require('source-map');
|
||||
@@ -695,33 +696,26 @@ files.extractTarGz = function (buffer, destPath, options) {
|
||||
var tempDir = files.pathJoin(parentDir, '.tmp' + utils.randomToken());
|
||||
files.mkdir_p(tempDir);
|
||||
|
||||
var tar = require("tar");
|
||||
var zlib = require("zlib");
|
||||
const startTime = +new Date;
|
||||
let promise = tryExtractWithNativeTar(buffer, tempDir);
|
||||
|
||||
new Promise(function (resolve, reject) {
|
||||
var gunzip = zlib.createGunzip().on('error', reject);
|
||||
if (process.platform === "win32") {
|
||||
promise = promise.catch(
|
||||
error => tryExtractWithNative7z(buffer, tempDir)
|
||||
);
|
||||
}
|
||||
|
||||
var extractor = new tar.Extract({
|
||||
path: files.convertToOSPath(tempDir)
|
||||
}).on('entry', function (e) {
|
||||
if (process.platform === "win32" || options.forceConvert) {
|
||||
// On Windows, try to convert old packages that have colons in paths
|
||||
// by blindly replacing all of the paths. Otherwise, we can't even
|
||||
// extract the tarball
|
||||
e.path = colonConverter.convert(e.path);
|
||||
}
|
||||
}).on('error', reject)
|
||||
.on('end', resolve);
|
||||
promise = promise.catch(
|
||||
error => tryExtractWithNpmTar(buffer, tempDir)
|
||||
);
|
||||
|
||||
// write the buffer to the (gunzip|untar) pipeline; these calls
|
||||
// cause the tar to be extracted to disk.
|
||||
gunzip.pipe(extractor);
|
||||
gunzip.write(buffer);
|
||||
gunzip.end();
|
||||
}).await();
|
||||
promise.await();
|
||||
|
||||
console.log("finished extracting in", new Date - startTime, "ms");
|
||||
|
||||
// succeed!
|
||||
var topLevelOfArchive = files.readdir(tempDir);
|
||||
console.log(topLevelOfArchive);
|
||||
if (topLevelOfArchive.length !== 1) {
|
||||
throw new Error(
|
||||
"Extracted archive '" + tempDir + "' should only contain one entry");
|
||||
@@ -733,6 +727,93 @@ files.extractTarGz = function (buffer, destPath, options) {
|
||||
files.rmdir(tempDir);
|
||||
};
|
||||
|
||||
function tryExtractWithNativeTar(buffer, tempDir) {
|
||||
const tarProc = spawn("tar", ["xzf", "-"], {
|
||||
cwd: tempDir,
|
||||
stdio: "pipe"
|
||||
});
|
||||
|
||||
tarProc.stdin.write(buffer);
|
||||
tarProc.stdin.end();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
tarProc.on("error", reject);
|
||||
tarProc.on("exit", resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function tryExtractWithNative7z(buffer, tempDir) {
|
||||
const exeOSPath = files.convertToOSPath(
|
||||
files.pathJoin(files.getCurrentNodeBinDir(), "7z.exe"));
|
||||
const tarGzBasename = "out.tar.gz";
|
||||
const tarGzOSPath = files.convertToOSPath(
|
||||
files.pathJoin(tempDir, tarGzBasename));
|
||||
|
||||
files.writeFile(tarGzOSPath, buffer);
|
||||
|
||||
const proc1 = spawn(exeOSPath, ["x", tarGzBasename], {
|
||||
cwd: tempDir,
|
||||
stdio: "inherit" // TODO Hide this later.
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
proc1.on("error", reject);
|
||||
proc1.on("exit", resolve);
|
||||
}).then(code => {
|
||||
assert.strictEqual(code, 0);
|
||||
|
||||
let tarBasename;
|
||||
const foundTar = files.readdir(tempDir).some(file => {
|
||||
if (file !== tarGzBasename) {
|
||||
tarBasename = file;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
assert.ok(foundTar, "failed to find .tar file");
|
||||
|
||||
const proc2 = spawn(exeOSPath, ["x", tarBasename], {
|
||||
cwd: tempDir,
|
||||
stdio: "inherit" // TODO Hide this later.
|
||||
});
|
||||
|
||||
function cleanUp() {
|
||||
files.unlink(files.pathJoin(tempDir, tarGzBasename));
|
||||
files.unlink(files.pathJoin(tempDir, tarBasename));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
proc2.on("error", reject);
|
||||
proc2.on("exit", resolve);
|
||||
}).then(code => {
|
||||
cleanUp();
|
||||
return code;
|
||||
}, error => {
|
||||
cleanUp();
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function tryExtractWithNpmTar(buffer, tempDir) {
|
||||
var tar = require("tar");
|
||||
var zlib = require("zlib");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var gunzip = zlib.createGunzip().on('error', reject);
|
||||
var extractor = new tar.Extract({
|
||||
path: files.convertToOSPath(tempDir)
|
||||
}).on('error', reject)
|
||||
.on('end', resolve);
|
||||
|
||||
// write the buffer to the (gunzip|untar) pipeline; these calls
|
||||
// cause the tar to be extracted to disk.
|
||||
gunzip.pipe(extractor);
|
||||
gunzip.write(buffer);
|
||||
gunzip.end();
|
||||
});
|
||||
}
|
||||
|
||||
// Tar-gzips a directory, returning a stream that can then be piped as
|
||||
// needed. The tar archive will contain a top-level directory named
|
||||
// after dirPath.
|
||||
|
||||
Reference in New Issue
Block a user