UNPKG

gadget

Version:

Gadget - Snap together HTML5 Applications

756 lines (647 loc) 17.3 kB
var https = require('https'); var http = require('http'); var querystring = require('querystring'); var mkdirp = require('mkdirp'); var fs = require('fs'); var _path = require('path'); var request = require('request'); var AdmZip = require('adm-zip'); var url = require('url'); var CONNECTORS = { "gitana": { "type": "js", "url": "http://code.cloudcms.com/gitana-javascript-driver/{version}/gitana.js", "dependencies": {}, "shim": true }, "jquery": { "type": "js", "url": "http://code.jquery.com/jquery-{version}.js", "dependencies": {}, "shim": true }, "alpaca": { "type": "zip", "url2": "http://www.alpacajs.org/downloads/alpaca-{version}-all.zip", "url": "local:/projects/alpaca/build/package/downloads/alpaca.zip", "locations": { "js": "js/alpaca.js", "css": "css/alpaca.css" }, "dependencies": { "jquery": "*" }, "shim2": true, "shim": false }, "ratchet": { "type": "js", "url": "local:/projects/ratchet/build/package/downloads/ratchet-{version}.js", "dependencies": { "jquery": "*" }, "shim": true }, "ratchet-jquery-template-engine": { "type": "js", "url": "local:/projects/ratchet/build/package/downloads/ratchet-{version}-jquery-template-engine.js", "dependencies": { "ratchet": "*" }, "shim": true }, "ratchet-gadgets": { "type": "zip", "url": "local:/projects/ratchet/build/package/downloads/ratchet-{version}-gadget-pack.zip", "locations": { "js": "js/ratchet-{version}-gadget-pack.js", "css": "css/ratchet-{version}-gadget-pack.css" }, "dependencies": { "ratchet": "*" }, "shim": true }, "bootstrap": { "type": "zip", "url": "http://twitter.github.com/bootstrap/assets/bootstrap.zip", "locations": { "js": "js/bootstrap.js", "css": "css/bootstrap-responsive.css" }, "skipFirstLevel": true, "dependencies": { "ratchet": "*" }, "shim": true } }; var rmdirRecursiveSync = function(dir) { if (!fs.existsSync(dir)) { return; } var list = fs.readdirSync(dir); for (var i = 0; i < list.length; i++) { var filename = _path.join(dir, list[i]); var stat = fs.statSync(filename); if (filename == "." || filename == "..") { // pass these files } else if (stat.isDirectory()) { // rmdir recursively rmdirRecursiveSync(filename); } else { // rm fiilename fs.unlinkSync(filename); } } fs.rmdirSync(dir); }; var mkdirRecursive = function(path, fn) { mkdirp(path, 0755, function(err) { if (err) throw err; // console.log(' \033[36mcreate\033[0m : ' + path); fn && fn(); }); }; /** * Sends a free trial request to Cloud CMS for a given email address. */ exports.register = function(program, email, callback) { var doRegister = function(program, email, callback) { console.log("Please wait, requesting a trial for: " + email + " ..."); console.log(""); // send email to cloud cms var data = querystring.stringify({ "email": email, "projectdesc": "(origin: cloudcms-node-js client)" }); var req = https.request({ host: "www.cloudcms.com", port: 443, path: "/form/trial/submit", method: "POST", headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': data.length } }, function(res) { /* res.on('data', function(d) { console.log(d.toString()); }); */ res.on('end', function() { console.log(""); console.log("Your free trial request was submitted."); console.log("Please check your email for notification of your free trial account."); console.log(""); callback(); }); }); req.write(data); req.on('error', function(err) { console.log(err); }); }; console.log(""); console.log("-------------------------------------------------------------------------"); console.log("Register for a Cloud CMS account"); console.log(""); if (!email) { console.log("All we need is an email address to get you started."); console.log("There is no cost and you can cancel your account at any time.") console.log(""); program.prompt("Email > ", function(email) { doRegister(program, email, callback); }); } else { doRegister(program, email, callback); } }; var installDependency = function(name, version, path, callback) { var connector = CONNECTORS[name]; if (!connector) { console.log("Cannot find connector for dependency type: " + name); return; } var type = connector.type; if (!type) { type = "js"; } var dependencyUrl = connector.url; dependencyUrl = dependencyUrl.replace("{version}", version); var libPath = path + "/public/lib"; var afterInstallCallback = function() { // for modules, we do some renaming of the JS and CSS files contained within to our convention if (type == "zip") { var jsLocation = connector.locations["js"]; var jsMain = null; var cssLocation = connector.locations["css"]; var cssMain = null; // if jsLocation, rename to module convention name if (jsLocation) { jsLocation = jsLocation.replace("{version}", version); jsMain = jsLocation.substring(0, jsLocation.lastIndexOf(".")); //fs.renameSync(libPath + "/" + name + "/" + jsLocation, libPath + "/" + name + "/" + jsMain + ".js"); } // if cssLocation, rename to module convention name if (cssLocation) { cssLocation = cssLocation.replace("{version}", version); cssMain = cssLocation.substring(0, cssLocation.lastIndexOf(".")); //fs.renameSync(libPath + "/" + name + "/" + cssLocation, libPath + "/" + cssModulePath + ".css"); } updateRequireJS(name, libPath, { "shim": connector.shim, "dependencies": connector.dependencies, "jsMain": jsMain, "cssMain": cssMain }); } else if (type == "js") { var x = dependencyUrl.lastIndexOf("/"); var filename = dependencyUrl.substring(x+1); jsMain = filename.substring(0, filename.lastIndexOf("."));; //fs.renameSync(libPath + "/" + name + "/" + filename, libPath + "/" + jsModulePath + ".js"); updateRequireJS(name, libPath, { "shim": connector.shim, "dependencies": connector.dependencies, "jsMain": jsMain, "cssMain": null }); } callback(); }; // remove module from library rmdirRecursiveSync(libPath + "/" + name); // REQUIREJS: auto-update updateRequireJS(name, libPath); if (type == "js") { _installFile(dependencyUrl, libPath + "/" + name, afterInstallCallback); } else if (type == "zip") { var filterFunction = buildLibraryFilterFunction(connector, name, version); _installZip(dependencyUrl, libPath + "/" + name, connector.skipFirstLevel, filterFunction, afterInstallCallback); } }; var updateRequireJS = function(name, libPath, config) { if (!config) { config = {}; } var dependencies = config.dependencies; var shim = config.shim; var jsMain = config.jsMain; var cssMain = config.cssMain; // MAIN.JS (function() { var text = fs.readFileSync(libPath + "/../main.js").toString(); var KEY1 = "require.config("; var KEY2 = ");"; var x1 = text.indexOf(KEY1); var x2 = text.indexOf(KEY2, x1); var piece = text.substring(x1 + KEY1.length, x2); var json = JSON.parse(text.substring(x1 + KEY1.length, x2)); if (!json.shim) { json.shim = {}; } // remove "name" from shim delete json.shim[name]; if (!json.packages) { json.packages = []; } // from "name" from packages var i = 0; while (i < json.packages.length) { if (json.packages[i] == name) { json.packages.splice(i,i); break; } else if (typeof json.packages[i] == "object") { if (json.packages[i].name == name) { json.packages.splice(i,i); break; } } i++; } if (jsMain) { if (shim && dependencies) { var dependencyArray = []; for (var dependencyName in dependencies) { dependencyArray.push(dependencyName); } json.shim[name] = dependencyArray; } // set package json.packages.push({ "name": name, "main": jsMain }); } text = text.substring(0, x1 + KEY1.length) + JSON.stringify(json, null, 4) + text.substring(x2); fs.writeFileSync(libPath + "/../main.js", text); })(); // MAIN.CSS (function() { var text = fs.readFileSync(libPath + "/../main.css").toString(); var KEY1 = "/** START: " + name + " **/"; var KEY2 = "/** END: " + name + " **/"; var x1 = text.indexOf(KEY1); if (x1 > -1) { // remove var x2 = text.indexOf(KEY2, x1); text = text.substring(0, x1) + text.substring(x2 + KEY2.length); } if (cssMain) { // add text = text + "\r\n" + KEY1 + '\r\n' + '@import url("lib/' + name + '/' + cssMain + '.css" );' + '\r\n' + KEY2 + '\r\n'; } fs.writeFileSync(libPath + "/../main.css", text); })(); }; var installDependencies = function(dependencies, path, callback) { var names = []; for (var name in dependencies) { names.push(name); } var f = function(count, path, callback) { if (count < names.length) { var name = names[count]; var version = dependencies[name]; installDependency(name, version, path, function(err) { if (err) { callback(err); return; } f(count + 1, path, callback); }); } else { callback(); } }; f(0, path, callback); } var installApplicationTemplate = function(path, callback) { _installZip("https://github.com/gitana/cloudcms-application-template/zipball/master", path, true, null, function() { callback(); }); } var buildLibraryFilterFunction = function(connector, name, version) { var jsLocation = connector.locations["js"]; if (jsLocation) { jsLocation = jsLocation.replace("{version}", version); } var cssLocation = connector.locations["css"]; if (cssLocation) { cssLocation = cssLocation.replace("{version}", version); } return function(path) { if (path) { path = path.toLowerCase(); // directories if (path.indexOf("examples/") > -1) { return true; } if (path.indexOf("favicon.ico") > -1) { return true; } if (path.indexOf("lib/") > -1) { return true; } if (path.indexOf("tests/") > -1) { return true; } // html files var x = path.indexOf("/"); if (x == -1 || x == 0) { if (path.indexOf(".html")) { return true; } if (path.indexOf(".htm")) { return true; } } // if we have a jsLocation, remove all javascript except for it if (jsLocation) { if (path.indexOf(".js") > -1) { if (path.indexOf(jsLocation.toLowerCase()) > -1) { return false; } return true; } } // if we have a cssLocation, remove all css except for it if (cssLocation) { if (path.indexOf(".css") > -1) { if (path.indexOf(cssLocation.toLowerCase()) > -1) { return false; } return true; } } } return false; }; }; var _installZip = function(file_url, targetPath, skipFirstLevel, filterFunction, callback) { var protocol = url.parse(file_url).protocol; // once we have a buffer, this extracts the zip into the right place var doExtractZip = function(buf, callback) { var zip = new AdmZip(buf); var zipEntries = zip.getEntries(); zipEntries.forEach(function(zipEntry) { var entryName = zipEntry.entryName; var subPath = entryName; var x = subPath.lastIndexOf("/"); var filename = subPath.substring(x+1); subPath = subPath.substring(0,x); // keep only folder path // if skip first level, the cut off first directory if (skipFirstLevel) { var x = subPath.indexOf("/"); if (x == -1) { subPath = ""; } else { subPath = subPath.substring(x + 1); } } if (filename.length > 0) { var filter = false; if (filterFunction) { filter = filterFunction(subPath + "/" + filename) } if (!filter) { zip.extractEntryTo(entryName, targetPath + "/" + subPath, false, true); } } }); callback(); }; // load via HTTP or HTTPS if (protocol == "http:" || protocol == "https:") { // use either HTTP or HTTPS var h = (protocol == "http:" ? http : https); var options = { host: url.parse(file_url).host, port: (protocol == "http:" ? 80 : 443), path: url.parse(file_url).pathname }; h.get(options, function(res) { var data = [], dataLen = 0; // automatically follow any redirects if (res.statusCode >= 300 && res.statusCode <= 399) { _installZip(res.headers.location, targetPath, skipFirstLevel, filterFunction, callback); return; } res.on('data', function(chunk) { data.push(chunk); dataLen += chunk.length; }).on('end', function() { var buf = new Buffer(dataLen); for (var i=0, len = data.length, pos = 0; i < len; i++) { data[i].copy(buf, pos); pos += data[i].length; } doExtractZip(buf, callback); }); }); } else if (protocol == "local:") { var filepath = file_url.substring(6); fs.readFile(filepath, function(err, data) { doExtractZip(data, callback); }); } }; var _installFile = function(file_url, targetPath, callback) { var protocol = url.parse(file_url).protocol; var doInstallFile = function(data, callback) { var x = file_url.lastIndexOf("/"); var filename = file_url.substring(x+1); mkdirRecursive(targetPath, function() { fs.writeFileSync(targetPath + "/" + filename, data, "utf-8"); callback(); }); }; // load via HTTP or HTTPS if (protocol == "http:" || protocol == "https:") { // use either HTTP or HTTPS var h = (protocol == "http:" ? http : https); var options = { host: url.parse(file_url).host, port: (protocol == "http:" ? 80 : 443), path: url.parse(file_url).pathname }; h.get(options, function(res) { var data = [], dataLen = 0; // automatically follow any redirects if (res.statusCode >= 300 && res.statusCode <= 399) { _installFile(res.headers.location, targetPath, callback); return; } res.on('data', function(chunk) { data.push(chunk); dataLen += chunk.length; }).on('end', function() { var buf = new Buffer(dataLen); for (var i=0, len = data.length, pos = 0; i < len; i++) { data[i].copy(buf, pos); pos += data[i].length; } doInstallFile(buf, callback); }); }); } else if (protocol == "local:") { var filepath = file_url.substring(6); fs.readFile(filepath, function(err, data) { doInstallFile(data, callback); }); } }; exports.createApp = function(path, callback) { // install the application template installApplicationTemplate(path, function() { // ensure base directories mkdirRecursive(path + "/public/scripts"); mkdirRecursive(path + "/public/styles"); mkdirRecursive(path + "/public/images"); mkdirRecursive(path + "/public/lib"); // ensure there is a "/config" folder mkdirRecursive(path + "/config"); // ensure there is a public "/templates" folder mkdirRecursive(path + "/public/templates"); // update dependencies updateDependencies(path, function() { callback(); }); }); }; var addPackageClientDependency = function(path, name, version) { var text = fs.readFileSync(path + "/package.json", text, "utf-8"); var packageJson = JSON.parse(text); if (!packageJson["client"]) { packageJson["client"] = {}; } if (!packageJson["client"]["dependencies"]) { packageJson["client"]["dependencies"] = {}; } packageJson["client"]["dependencies"][name] = version; fs.writeFileSync(path + "/package.json", JSON.stringify(packageJson, null, 4), "utf-8"); }; var listPackageClientDependencies = function(path) { var text = fs.readFileSync(path + "/package.json", text, "utf-8"); var packageJson = JSON.parse(text); var dependencies = {}; if (packageJson["client"] && packageJson["client"]["dependencies"]) { dependencies = packageJson["client"]["dependencies"]; } return dependencies; } var updateDependencies = exports.updateDependencies = function(path, callback) { // make sure the application template is already installed fs.exists(path + "/public", function(exists) { if (!exists) { console.log("The Cloud CMS application template has not been installed."); console.log("Please run 'createapp' first."); callback(); return; } // add core libraries to package json addPackageClientDependency(path, "jquery", "1.8.2"); addPackageClientDependency(path, "alpaca", "1.0.2-SNAPSHOT"); addPackageClientDependency(path, "ratchet", "1.0.2-SNAPSHOT"); addPackageClientDependency(path, "ratchet-jquery-template-engine", "1.0.2-SNAPSHOT"); addPackageClientDependency(path, "ratchet-gadgets", "1.0.2-SNAPSHOT"); addPackageClientDependency(path, "bootstrap", "2.1.1"); // package dependencies var dependencies = listPackageClientDependencies(path); // install dependencies installDependencies(dependencies, path, function() { callback(); }); }); };