UNPKG

@happikitsune/nw-builder

Version:
198 lines (179 loc) 6.57 kB
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); } }, };