pcjs/modules/grunts/manifester/tasks/manifester.js
2016-05-27 08:46:13 -07:00

135 lines
6.6 KiB
JavaScript

/**
* grunt-manifester
* https://github.com/jeffpar/pcjs
*
* Copyright (c) 2014-2016 jeffpar
* Licensed under the MIT license.
*
* TODO: Update this header with our standard header and fix all the JSHint warnings
*/
"use strict";
var fs = require("fs");
var path = require("path");
var mkdirp = require("mkdirp");
var url = require("url");
var async = require("async");
var parseXML = require("xml2js").parseString; // see: https://github.com/Leonidas-from-XIV/node-xml2js
var unzip = require("unzip");
var util = require("util");
var defines = require("../../../shared/lib/defines");
var net = require("../../../shared/lib/netlib");
module.exports = function (grunt) {
/*
* Please see the Grunt documentation for more information regarding task
* creation: http://gruntjs.com/creating-tasks
*/
grunt.registerMultiTask('manifester', 'manifest.xml processor', function() {
/*
* Merge task-specific and/or target-specific options with these defaults
*
var options = this.options({
});
*/
/*
* Tell grunt this task is asynchronous
*/
var asManifests = [];
var doneGrunt = this.async();
/*
* Iterate over all specified file groups
*/
this.files.forEach(function(file) {
file.src.filter(function(sFilePath) {
/*
* Warn on and remove invalid source files (if nonull was set)
*/
if (!grunt.file.exists(sFilePath)) {
grunt.log.warn('Source file "' + sFilePath + '" not found.');
return false;
}
return true;
}).map(function(sFilePath) {
/*
* TODO: Given the memory constraints I've run into with Grunt in the past, it would
* probably be better queue up the file paths instead of the file contents, and do async
* readFile() calls.
*/
asManifests.push(sFilePath);
});
});
async.each(asManifests, function processXML(sManifestFile, doneAsync) {
var sManifestXML = grunt.file.read(sManifestFile);
parseXML(sManifestXML, function doneParseXML(err, xml) {
var cCallbacks = 0;
if (xml.manifest) {
// console.log(util.inspect(xml, false, null));
for (var iRepo in xml.manifest.repo) {
var repo = xml.manifest.repo[iRepo];
if (repo.src) {
var src = repo.src[0];
var sURL = src.$['href'];
// var sURL = src._ || src; // the former is set if there are any attributes, otherwise the element is just a string
console.log('found src URL: "' + sURL + '"');
if (sURL.slice(0, 5) == "http:" && sURL.slice(-1) == '/') {
for (var iDownload in repo.download) {
var download = repo.download[iDownload];
var sDownloadFile = download.$['href'];
// var sDownloadFile = download._ || download;
console.log("processing download " + sDownloadFile);
var sRemoteFile = sURL + sDownloadFile;
var sLocalDir = path.join(path.dirname(sManifestFile), repo.$['dir']);
if (grunt.file.exists(sLocalDir) || mkdirp.sync(sLocalDir)) {
var sLocalFile = path.join(sLocalDir, sDownloadFile);
if (grunt.file.exists(sLocalFile)) {
console.log("file already exists: " + sLocalFile);
} else {
console.log('downloadFile("' + sRemoteFile + '", "' + sLocalFile + '")...');
cCallbacks++;
net.downloadFile(sRemoteFile, sLocalFile, function doneDownloadFile(err, status) {
console.log('downloadFile("' + sRemoteFile + '") returned ' + status + ': ' + (err? false : true));
if (!err && status == 200 && sLocalFile.slice(-4) == ".zip") {
var sLocalZipDir = path.join(sLocalDir, path.basename(sLocalFile, ".zip"));
if (grunt.file.exists(sLocalZipDir) || mkdirp.sync(sLocalZipDir)) {
/*
* TODO: As explained here (https://github.com/EvanOxfeld/node-unzip/issues/40), determine why this ZIP
* file (http://beej.us/moria/files/pc/zip-arc/mor55-88.zip) causes an "invalid stored block lengths" error.
*/
fs.createReadStream(sLocalFile).pipe(unzip.Extract({path: sLocalZipDir})).on('close', function() {
console.log("unzip complete: " + sLocalZipDir);
if (--cCallbacks == 0) doneAsync();
});
return;
} else {
grunt.log.warn("unzip directory not available: " + sLocalZipDir);
}
}
if (--cCallbacks == 0) doneAsync();
});
}
} else {
grunt.log.warn("download directory not available: " + sLocalDir);
}
}
} else {
grunt.log.warn("unsupported repo src: " + sURL);
}
}
}
}
if (!cCallbacks) doneAsync();
});
}, function(err) {
doneGrunt();
});
});
};