/**
* Module dependencies.
*/
var _ = require('lodash'),
argv = require('optimist').argv;
/**
* Module dependencies.
*/
var _ = require('lodash'),
argv = require('optimist').argv;Start building object to export
var util = {};
/**
* Expose `fs`, but monkey-patched to make sure existsSync()
* doesn't crash older versions of Node
*
* @api private
*/
var fs = require('fs-extra');
fs.existsSync = fs.existsSync || require('path').existsSync;
util.fs = fs;
/**
* Convert command-line arguments into configuration
* options for the Sails core
*
* @param argv
*
* @api private
*/
util.getCLIConfig = function ( argv ) {
return {--silent command-line argument
--verbose command-line argument
--silly command-line argument
log: argv.verbose ? {level: 'verbose'} :
argv.silly ? {level: 'silly'} :
argv.silent ? {level: 'silent'} :
undefined,--port=? command-line argument
port: argv.port || undefined,--prod command-line argument
environment: argv.prod ? 'production' : undefined
};
};
/**
* Methods which return a string with usage information
* for the Sails CLI
*/
util.usage = {
sails: function () {
var usage = 'Usage: sails <command>\n\n';(if node_modules/sails exists, it will be used instead of the global install)\n';
usage += _tab('sails lift') + 'Run the Sails app in the current directory:\n';
usage += _tab(' [--prod]') + ' - in production mode \n';
usage += _tab(' [--port 3000]') + ' - on port 3000 \n';
usage += _tab(' [--verbose]') + ' - with verbose logging enabled \n';
usage += '\n';
usage += _tab('sails new <appName>') + 'Create a new Sails project in a folder called <appName>:\n';
usage += _tab(' [--no-linker]') + ' - disable auto-<link> of assets in HTML files via Grunt\n';
usage += '\n';
usage += _tab('sails generate model <foo>') + 'Generate a model (`api/models/Foo.js`)\n';
usage += _tab('sails generate controller <foo>') + 'Generate a controller (`api/controllers/FooController.js`)\n';
usage += _tab('sails generate <foo>') + 'Generate both.\n';
usage += _tab(' [--dry]') + 'Don\'t actually create the module file.\n';
usage += '\n';
usage += _tab('sails console') + 'Run Sails in interactive mode (REPL)\n';
usage += _tab('sails version') + 'Get the current globally installed Sails version\n';
usage += _tab('sails run <command>') + 'Run a management command (exported by YOUR_APP/commands/index.js)';
return usage;
},
generate: {
model: function () {
var usage = 'Usage:\n';
usage += 'sails generate model <foo> [attribute0Name:type] [attribute1Name:attribute1Type] [...]' + '\n';
usage += '\n';
usage += 'E.g., to generate api/models/Cockatiel.js:' + '\n';
usage += 'sails generate model cockatiel' + '\n';
usage += '\n';
usage += 'With some attributes:' + '\n';
usage += 'sails generate model cockatiel name:string weight:float birthdate:date color:string';
}
}
};
/**
* Generate a file
*
* @api private
*/
util.generateFile = function(boilerplatePath, newPath) {
var fullBpPath = __dirname + '/boilerplates/' + (boilerplatePath || '');
var file = fs.readFileSync(fullBpPath, 'utf8');
var newFilePath = (newPath || '');
util.verifyDoesntExist(newFilePath, 'A file/directory already exists at ' + newFilePath);Touch output file to make sure the path to it exists
if (fs.createFileSync(newFilePath)) {
log.error('Could not create file, ' + newFilePath + '!');
process.exit(1);
}
fs.writeFileSync(newFilePath, file);
};
/**
* Generate a directory
*
* @api private
*/
util.generateDir = function(newPath, gitkeep) {
if (!newPath) {
log.verbose('Creating directory in pwd...');
} else {
log.verbose('Creating directory directory in ' + newPath + '...');
}
var newDirPath = (newPath || '');
util.verifyDoesntExist(newDirPath, 'A file/directory already exists at ' + newDirPath);
fs.mkdirSync(newDirPath);If directory will be empty, create a .gitkeep in it
if (gitkeep) {
generateFile('.gitkeep', newPath + '/.gitkeep');
}
};
/**
* Verify that a file doesn't exist
*
* @api private
*/
util.verifyDoesntExist = function(path, msg) {
if (util.fileExists(path)) {
log.error(msg);
process.exit(1);
}
};
/**
* Check if a file or directory exists
*
* @api private
*/
util.fileExists = function(path) {
try {Query the entry
var stats = fs.lstatSync(path);Is it a directory?
if (stats.isDirectory() || stats.isFile()) {
return true;
}
} catch (e) {...
}
return false;
};
/**
* Read an EJS template representing a Sails module,
* then send back the return string.
*
* @api private
*/util.renderBoilerplateTemplate = function(path, data) { var boilerplatePath = __dirname + '/boilerplates/templates/' + boilerplate; util.verifyExists(boilerplatePath, "Boilerplate (" + boilerplate + ") doesn't exist!"); var file = fs.readFileSync(boilerplatePath, 'utf8'); return ejs.render(file, data); };
/**
*
*
* @api private
*/
util.verifyExists = function(path, msg) {
if (!util.fileExists(path)) {
log.error(msg);
process.exit(1);
}
};
/**
* Copy a boilerplate directory or file
*
* @api private
*/
util.copyBoilerplate = function(boilerplate, destination, cb) {
var boilerplatePath = __dirname + '/boilerplates/' + boilerplate;
fs.copy(boilerplatePath, destination, function(err) {
return cb && cb(err);
});
};
/**
* Copy global sails module into current project as a local dependency
* (currently unusued)
*
* @api private
*/
util.copySails = function(destination, cb) {
try {
fs.mkdirSync(destination);
} catch (e) {
return cb && cb(e);
}Progress notifications
var stopShowingProgressNotifications,
errorCopying,
interval = 150;Draw progress notification Returns progress function
log.verbose('Copying modules into ' + destination + '...');
var canvas = turtle();
async.until(
function checkIfDone() {
canvas.tick();
return stopShowingProgressNotifications;
},
function setAlarm(cb) {
setTimeout(cb, interval);
},
function done(err) {If an error occurred, send it back
err = err || errorCopying;
return cb && cb(err);
});
async.each(['lib', 'package.json', 'node_modules'], function(fileOrDir, cb) {
fs.copy(__dirname + '/../' + fileOrDir, destination + '/' + fileOrDir, cb);
}, function doneCopying(err) {Hold onto error if there is one
errorCopying = err;When finished copying, mark done progress notifications will trigger the callback
stopShowingProgressNotifications = true;
});
};
/**
* Copy a core Sails dependency to the top-level node_modules directory
* of the current application---- in a smart way
*
* @api private
*/
util.copySailsDependency = function(moduleName, pathToNewNodeModules, cb) {
var path = __dirname + '/../node_modules/' + moduleName;
fs.copy(path, pathToNewNodeModules + '/' + moduleName, function(err) {
if (err) return cb && cb(err);Parse the module's package.json
var packageJSONPath = path + '/package.json';
var packageJSON;
try {
packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf-8'));
} catch (e) {Ignore missing package.json
packageJSON = {
dependencies: {}
};
}Get actual dependencies in this module's node_modules directory
var dependencies;
try {
dependencies = fs.readdirSync(path + '/node_modules');Remove hidden files
_.without(dependencies, function(val) {
return val.match(/\..+/);
});
} catch (e) {Assume empty dependencies
dependencies = {};
}If there are any missing dependencies which are being pulled from Sails, copy them from Sails' main node_modules directory
var missingModules = _.difference(_.keys(packageJSON.dependencies || {}), _.values(dependencies));
_.each(missingModules, function(missingModuleName) {
log.verbose('Resolving ' + moduleName + '\'s missing dependency (' + missingModuleName + ') using the version in Sails.');
util.copySailsDependency(missingModuleName, pathToNewNodeModules + '/' + moduleName + '/node_modules/');
});
return cb && cb(err);
});
};
/**
* Return a tabbed-over version of the string,
* adjusting for spacing
*
* @api private
*/
function _tab (str) {
var n = (33 - str.length);
return str + _.str.repeat(' ', n);
}Export util object
module.exports = _.cloneDeep(util);