@happikitsune/nw-builder
Version:
198 lines (179 loc) • 6.57 kB
JavaScript
var request = require("request");
var progress = require("progress");
var fs = require("fs");
var path = require("path");
var zlib = require("zlib");
var tar = require("tar-fs");
var temp = require("temp");
var ncp = require("graceful-ncp").ncp;
var rimraf = require("rimraf");
var extract = require("extract-zip");
// Automatically track and cleanup files at exit
temp.track();
var isWin = /^win/.test(process.platform);
// one progressbar for all downloads
var bar;
module.exports = {
checkCache: function (cachepath, files) {
var missing;
// if the version is >=0.12.3, then we don't know which files we want from the archives, so just check that the
// folder exists and has at least 3 files in it.
if (files.length === 1 && files[0] === "*") {
return (
fs.existsSync(cachepath) &&
fs.readdirSync(cachepath).length >= 2
);
}
files.forEach(function (file) {
if (missing) {
return;
}
if (!fs.existsSync(path.join(cachepath, file))) {
missing = true;
}
});
return !missing;
},
clearProgressbar: function () {
bar && bar.terminate();
bar = null;
},
downloadAndUnpack: function (cachepath, url) {
var extention = path.extname(url),
self = this,
rq = request(url),
len,
stream;
function format(statusCode) {
return statusCode + ": " + require("http").STATUS_CODES[statusCode];
}
return new Promise(function (resolve, reject) {
rq.proxy = true;
rq.on("error", function (err) {
bar && bar.terminate();
reject(err);
});
rq.on("response", function (res) {
len = parseInt(res.headers["content-length"], 10);
if (res.statusCode !== 200) {
reject({
statusCode: res.statusCode,
msg: "Recieved status code " + format(res.statusCode),
});
} else if (len) {
if (!bar) {
bar = new progress(
" downloading [:bar] :percent :etas",
{
complete: "=",
incomplete: "-",
width: 20,
total: len,
}
);
} else {
bar.total += len;
}
}
});
rq.on("data", function (chunk) {
len && bar && bar.tick(chunk.length);
});
if (extention === ".zip") {
rq.on("response", function (res) {
if (res.statusCode !== 200) return;
stream = temp.createWriteStream();
stream.on("finish", function () {
self.extractZip(stream.path, cachepath)
.then(self.stripRootFolder)
.then(function (files) {
resolve(files);
});
});
rq.pipe(stream);
});
} else if (extention === ".gz") {
rq.on("response", function (res) {
if (res.statusCode !== 200) return;
self.extractTar(res, cachepath)
.then(self.stripRootFolder)
.then(function (files) {
resolve(files);
});
});
}
});
},
extractTar: function (tarstream, destination) {
var gunzip = zlib.createGunzip(),
files = [];
return new Promise(function (resolve, reject) {
tarstream
.pipe(gunzip)
.on("error", function (err) {
reject(err);
})
.pipe(
tar.extract(destination, {
umask: isWin ? false : 0,
map: function (header) {
files.push({ path: path.basename(header.name) });
return header;
},
})
)
.on("finish", function () {
resolve({ files: files, destination: destination });
});
});
},
extractZip: async function (zipfile, destination) {
var files = [];
var onEntry = function (entry) {
files.push({
mode: entry.externalFileAttributes >>> 16,
path: entry.fileName,
});
};
await extract(zipfile, { dir: destination, onEntry: onEntry });
// Setup chmodSync to fix permissions
files.forEach(function (file) {
fs.chmodSync(path.join(destination, file.path), file.mode);
});
return { files, destination };
},
stripRootFolder: function (extracted) {
var files = extracted.files,
destination = extracted.destination,
rootFiles = fs.readdirSync(destination),
fromDir = path.join(
destination,
rootFiles.length === 1 ? rootFiles[0] : ""
);
// strip out root folder if it exists
if (rootFiles.length === 1 && fs.statSync(fromDir).isDirectory()) {
// strip folder from files
for (var i = 0; i < files.length; i++) {
var file = files[i];
file.path = path.relative(rootFiles[0], file.path);
if (file.path === "") {
files.splice(i, 1);
i--;
}
}
return new Promise(function (resolve, reject) {
// move stripped folder to destination
ncp(fromDir, destination, function (err) {
if (err) {
return reject();
} else
rimraf(fromDir, function () {
resolve(files);
});
});
});
} else {
return Promise.resolve(files);
}
},
};