md-nw-builder
Version:
md-nw-builder
196 lines (174 loc) • 6.55 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 = false;
rq.on('error', function(err) {
console.log(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){
console.err(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: function(zipfile, destination) {
var files = [];
var onEntry = function(entry){
files.push({
mode: entry.externalFileAttributes >>> 16,
path: entry.fileName
});
};
return new Promise(function(resolve, reject){
extract(zipfile, { dir: destination, onEntry: onEntry }, function(err){
if(err){
return reject(err);
}
// Setup chmodSync to fix permissions
files.forEach(function(file) {
fs.chmodSync(path.join(destination, file.path), file.mode);
});
resolve({ files: files, destination: 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);
}
}
};