Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

722 lines (613 sloc) 20.318 kb
// Load the basic Geddy toolkit
require('../lib/geddy')
// Dependencies
var fs = require('fs')
, path = require('path')
, utils = require('../lib/utils')
, adapter = require('../lib/template/adapters').Adapter
, templato = new (require('../deps/templato'));
namespace('env', function () {
task('init', function (environment) {
jake.addListener('complete', function (e) {
jake.Task['env:cleanup'].invoke();
});
geddy.config = require('../lib/config').readConfig({
environment: environment || 'development'
});
geddy.model = require('model');
require('../lib/init').init(geddy, function () {
complete();
});
}, {async: true});
task('cleanup', function () {
// Disconnect all the adapters
adapters = geddy.model.loadedAdapters
, adapter;
for (var p in adapters) {
adapter = adapters[p];
if (typeof adapter.disconnect == 'function') {
adapter.disconnect();
}
}
});
});
namespace('console', function () {
task('start', ['env:init'], {async: true}, function (environment) {
var env = environment || 'development'
, t = jake.Task['env:init'];
t.addListener('complete', function () {
var readline = require('readline')
, rl = readline.createInterface({
input: process.stdin
, output: process.stdout
});
rl.setPrompt('>>> ');
rl.prompt();
rl.addListener('line', function (line) {
try {
console.log(global.eval(line));
}
catch (e) {
console.log(e.stack);
}
rl.prompt();
});
rl.addListener('close', function () {
console.log('Exiting ...');
return complete();
});
});
global.capture = function (err, data) {
return global.results = {
err: err
, data: data
};
}
global.echo = function (err, data) {
capture(err, data);
if (err) {
console.log('Error: ', err);
}
if (data) {
if (data.length) {
for (var i in data) {
if (data[i] && data[i].toData) {
console.log(data[i].toData());
} else {
console.log(data[i]);
}
}
} else {
if (data && data.toData) {
console.log(data.toData());
} else {
console.log(data);
}
}
} else {
console.log('No data');
}
}
t.invoke(env);
});
});
namespace('db', function () {
task('createTable', ['env:init'], function (name) {
var modelName
, createTable
, adapters
, adapter;
if (typeof name == 'string') {
if (name.indexOf(',') > -1) {
modelNames = name.split(',');
}
else {
modelNames = [name];
}
}
else {
modelNames = name;
}
createTable = function () {
if ((m = modelNames.shift())) {
// Make sure this is a correct model-name
m = utils.string.getInflections(m).constructor.singular;
if (!geddy.model[m]) {
throw new Error(m + ' is not a known model.');
}
adapter = geddy.model.adapters[m];
if (adapter) {
console.log('Creating table for ' + m);
adapter.createTable(m, function (err, data) {
if (err) { throw err }
createTable();
});
}
else {
createTable();
}
}
else {
complete();
}
};
createTable();
}, {async: true});
task('retrofit', ['env:init'], function () {
var modelNames = Object.keys(geddy.model.descriptionRegistry)
, createTask = jake.Task['db:createTable'];
createTask.once('complete', function () {
complete();
});
createTask.invoke(modelNames);
}, {async: true});
});
namespace('gen', function () {
var _writeTemplate = function (name, filename, dirname, opts) {
var options = opts || {}
, names = utils.string.getInflections(name)
, text = fs.readFileSync(path.join(__dirname, filename + '.ejs'), 'utf8').toString()
, bare = options.bare || false // Default to full controller
, templ
, fileDir
, filePath;
// Render with the right model name
templ = new adapter({data: {ext: '.ejs'}, text: text, templato: templato});
templ.process({names: names, bare: bare, properties: options.properties});
// Write file
fileDir = dirname;
if (!utils.file.existsSync(fileDir)) {
fs.mkdirSync(fileDir);
}
filePath = path.join(fileDir, names.filename[options.inflection] + '.js');
fs.writeFileSync(filePath, templ.markup, 'utf8');
console.log('[Added] ' + filePath);
};
var _formatModelProperties = function (properties) {
var obj = {'default': {name: 'id', type: 'int'}};
if (!properties) {
return obj;
}
var itemsArr = properties.split('%')
, name
, type
, args
, i
, value;
i = -1;
while (++i < itemsArr.length) {
value = itemsArr[i];
name = value.replace(/:.*/g, '');
type = value.replace(/[a-zA-Z]*:?/, '');
args = type.replace(/[a-zA-Z]*:?/, '');
// Take off any args on the type
type = type.replace(/:.*/g, '');
// Defaults and aliases
if (!type) {
type = 'string';
}
if (args === 'def') {
args = 'default';
}
switch (type) {
case 'text':
type = 'string';
break;
case 'integer':
type = 'int';
break;
case 'bool':
type = 'boolean';
break;
case 'default':
case 'def':
type = 'string';
args = 'default';
break;
}
// Manage properties that deal with changing the default property
if (args === 'default') {
// Reset old default to it's own property
obj[obj['default'].name] = obj[obj['default'].name] || obj['default'];
// Add new default property
obj['default'] = {name: name, type: type};
continue;
}
// If ID property is given and it matches the default
// then rewrite the default with the new ID property
if (name === 'id' && obj['default'].name === 'id') {
obj['default'] = {name: name, type: type};
continue;
}
// If the name is name or title then set them to default, otherwise add
// the property normally
if (name === 'name' || name === 'title') {
// Reset old default to it's own property
obj[obj['default'].name] = obj[obj['default'].name] || obj['default'];
// Add new default property
obj['default'] = {name: name, type: type};
} else {
obj[name] = {name: name, type: type};
}
}
return obj;
};
// Creates a new Geddy app scaffold
task('app', function (name, engine) {
var mkdirs
, cps
, text
, tpl;
if (!name) {
throw new Error('No app name specified.');
}
if (!engine) {
engine = 'ejs';
}
mkdirs = [
''
, 'config'
, 'app/models'
, 'app/controllers'
, 'app/helpers'
, 'lib'
, 'log'
, 'node_modules'
, 'test'
];
cps = [
['views/' + engine, 'app/views']
, ['public', '']
, ['router.js', 'config']
, ['init.js', 'config']
, ['environment.js', 'config']
, ['development.js', 'config']
, ['production.js', 'config']
, ['main.js', 'app/controllers']
, ['application.js', 'app/controllers']
, ['favicon.ico', 'public']
];
mkdirs.forEach(function (dir) {
jake.mkdirP(path.join(name, dir));
});
cps.forEach(function (cp) {
jake.cpR(path.join(__dirname, 'base', cp[0]), path.join(name, cp[1]), {silent: true});
});
text = fs.readFileSync(path.join(__dirname, 'base', 'Jakefile.ejs'), 'utf8').toString()
templ = new adapter({data: {ext: '.ejs'}, text: text, templato: templato});
templ.process({appName: name});
fs.writeFileSync(path.join(name, 'Jakefile'), templ.markup, 'utf8');
console.log('Created app ' + name + '.');
});
// Creates a resource with a model, controller and a resource route
task('resource', function (name, modelProperties) {
var names
, modelTask = jake.Task['gen:model'];
if (!name) {
throw new Error('No resource name specified.');
}
modelTask.on('complete', function () {
jake.Task['gen:controller'].invoke(name);
jake.Task['gen:route'].invoke(name);
names = utils.string.getInflections(name);
// Create views folder but not actions
jake.mkdirP(path.join('app', 'views', names.filename.plural));
console.log('[Added] ' + names.filename.plural + ' view directory');
complete();
});
modelTask.invoke(name, modelProperties);
}, {async: true});
// Creates a full scaffold with views, a model, controller and a resource route
task('scaffold', function (name, engine, modelProperties) {
var modelTask = jake.Task['gen:model'];
if (!modelProperties && engine) {
modelProperties = engine;
engine = '';
}
if (!name) {
throw new Error('No scaffold name specified.');
}
if (!engine) {
engine = 'ejs';
}
modelTask.on('complete', function () {
jake.Task['gen:test'].invoke(name,
{properties: modelProperties});
jake.Task['gen:controllerScaffold'].invoke(name,
{properties: modelProperties});
jake.Task['gen:route'].invoke(name);
jake.Task['gen:viewsScaffold'].invoke(name,
{engine: engine, properties: modelProperties});
complete();
});
modelTask.invoke(name, modelProperties, 'scaffold');
}, {async: true});
task('model', function (name, properties, modelPath) {
var createTableTask;
if (!name) {
throw new Error('No model name specified.');
}
if (!modelPath) {
modelPath = 'resource';
}
modelPath += '/model';
_writeTemplate(name, modelPath, path.join('app', 'models'), {
inflection: 'singular'
, properties: _formatModelProperties(properties)
});
// Try to create a table -- should be a no-op if an
// appropriate DB adapter can't be found
createTableTask = jake.Task['db:createTable'];
createTableTask.on('complete', function () {
complete();
});
createTableTask.invoke(name);
}, {async: true});
task('controller', function (name) {
if (!name) {
throw new Error('No controller name specified.');
}
_writeTemplate(name, 'resource/controller', path.join('app', 'controllers'),
{inflection: 'plural', bare: false});
});
task('test', function (name) {
if (!name) {
throw new Error('No test name specified.');
}
_writeTemplate(name, 'resource/test', 'test',
{inflection: 'singular'});
});
task('controllerScaffold', function (name, options) {
if (!name) {
throw new Error('No controller name specified.');
}
options = options || {};
_writeTemplate(name, 'scaffold/controller', path.join('app', 'controllers'), {
inflection: 'plural'
, bare: false
, properties: _formatModelProperties(options.properties)
});
});
task('bareController', function (name, engine) {
if (!name) {
throw new Error('No controller name specified.');
}
if (!engine) {
engine = 'ejs';
}
_writeTemplate(name, 'resource/controller', path.join('app', 'controllers'),
{inflection: 'plural', bare: true});
jake.Task['gen:route'].invoke(name, {bare: true});
jake.Task['gen:views'].invoke(name, {bare: true, engine: engine});
});
task('route', function (name, options) {
if (!name) {
throw new Error('No route name specified.');
}
options = options || {};
var names = utils.string.getInflections(name)
, routeType = options.bare ? 'Bare' : 'Resource'
, jsRouter = path.normalize('config/router.js')
, coffeeRouter = path.normalize('config/router.coffee')
, routerPath
, routerArr
, text
, splitText
, newRoute
, beginPath;
// Check if the router file exists
beginPath = path.join(process.cwd(), 'config');
utils.file.searchParentPath(jsRouter, function (err) {
if (err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.file.searchParentPath(coffeeRouter, beginPath, function (err) {
if (err) {
throw jsErr;
} else {
routerPath = coffeeRouter;
}
});
} else {
routerPath = jsRouter;
}
});
if (routerPath) {
text = fs.readFileSync(routerPath, 'utf8');
if (routerPath.match('.coffee')) {
if (options.bare) {
newRoute = 'router.match(\'/' + names.filename.plural +
'\').to controller: \'' + names.constructor.plural +
'\', action: \'index\'';
} else {
newRoute = 'router.resource \'' + names.filename.plural + '\'';
}
} else if (routerPath.match('.js')) {
if (options.bare) {
newRoute = 'router.match(\'/' + names.filename.plural +
'\').to({controller: \'' + names.constructor.plural +
'\', action: \'index\'});';
} else {
newRoute = 'router.resource(\'' + names.filename.plural + '\');';
}
}
// Don't add the same route over and over
if (text.indexOf(newRoute) == -1) {
// Add the new resource route just above the export
routerArr = text.split('exports.router');
routerArr[0] += newRoute + '\n';
text = routerArr.join('exports.router');
fs.writeFileSync(routerPath, text, 'utf8');
console.log('[Added] ' + routeType + ' ' + names.filename.plural +
' route added to ' + routerPath);
}
else {
console.log(routeType + ' ' + names.filename.plural + ' route already defined in ' +
routerPath);
}
} else {
console.log('There is no router file to add routes too');
}
});
task('views', function (name, options) {
if (!name) {
throw new Error('No view name specified.');
}
options = options || {};
// Option defaults
options.engine = options.engine || 'ejs';
var names = utils.string.getInflections(name)
, engine = options.engine
, appViewDir = path.join('app', 'views', names.filename.plural)
, templateViewDir = path.join(__dirname, 'views', engine)
, cmds = []
, ext = '.html'
, appLayoutPath
, actions
, addActionView;
// Set extension based on engine option
switch (engine) {
case 'ejs':
ext += '.ejs';
break;
case 'jade':
ext += '.jade';
break;
case 'handlebars':
ext += '.hbs';
break;
case 'mustache':
ext += '.ms';
break;
}
// Set application layout path
appLayoutPath = path.join('app', 'views', 'layouts', 'application');
// Copy template view to application path
addActionView = function (action) {
jake.cpR(path.join(templateViewDir, action + ext), appViewDir);
};
jake.mkdirP(appViewDir);
jake.mkdirP('app/views/layouts');
addActionView('index');
// Add views for the other CRUD actions when doing a full-on resource
if (!options.bare) {
['add', 'edit', 'show'].forEach(function (action) {
addActionView(action);
});
}
// Create default layout if one doesn't exist
// Hack: There should be a better way to detect if a application layout exists
if (!utils.file.existsSync(appLayoutPath + '.html.ejs') && !utils.file.existsSync(appLayoutPath + '.html.jade') &&
!utils.file.existsSync(appLayoutPath + '.html.hbs') && !utils.file.existsSync(appLayoutPath + '.html.ms')) {
// Copy template layout file to apps application layout file
jake.cpR(path.join(templateViewDir, 'layout' + ext), appLayoutPath + ext);
}
console.log('[Added] View templates');
});
task('viewsScaffold', function (name, options) {
if (!name) {
throw new Error('No view name specified.');
}
options = options || {};
// Option defaults
options.engine = options.engine || 'ejs';
var names = utils.string.getInflections(name)
, engine = options.engine
, appViewDir = path.join('app', 'views', names.filename.plural)
, templateViewDir = path.join(__dirname, 'scaffold', 'views', engine)
, cmds = []
, ext = '.html'
, appLayoutPath
, actions
, addActionView
, text
, templ;
// Set extension based on engine option
switch (engine) {
case 'ejs':
ext += '.ejs';
break;
case 'jade':
ext += '.jade';
break;
case 'handlebars':
ext += '.hbs';
break;
case 'mustache':
ext += '.ms';
break;
}
// Set application layout path
appLayoutPath = path.join('app', 'views', 'layouts', 'application');
// Function to compile the template
addActionView = function (action) {
text = fs.readFileSync(path.join(templateViewDir, action + ext + '.ejs')).toString();
// Compile template text
templ = new adapter({data: {ext: '.ejs'}, text: text, templato: templato});
templ.process({names: names, properties: _formatModelProperties(options.properties)});
// Write file
fs.writeFileSync(path.join(appViewDir, action + ext),
templ.markup.replace(/<@/g, '<%').replace(/@>/g, '%>'), 'utf8');
};
jake.mkdirP(appViewDir);
jake.mkdirP('app/views/layouts');
// Add views for the other CRUD actions when doing a full-on resource
['index', 'add', 'show', 'edit'].forEach(function (action) {
addActionView(action);
});
// Create default layout if one doesn't exist
// Hack: There should be a better way to detect if a application layout exists
if (!utils.file.existsSync(appLayoutPath + '.html.ejs') && !utils.file.existsSync(appLayoutPath + '.html.jade') &&
!utils.file.existsSync(appLayoutPath + '.html.hbs') && !utils.file.existsSync(appLayoutPath + '.html.ms')) {
// Copy template layout file to apps application layout file
jake.cpR(path.join(templateViewDir, 'layout' + ext), appLayoutPath + ext);
}
console.log('[Added] View templates');
});
// Generate a new application secret in environment.js
task('secret', function () {
var jsEnvironment = path.normalize('config/environment.js')
, coffeeEnvironment = path.normalize('config/environment.coffee')
, secret = utils.string.uuid(128)
, environmentPath
, environmentArr
, text
, splitText
, beginPath;
// Check if the environment file exists
beginPath = path.join(process.cwd(), 'config');
utils.file.searchParentPath(jsEnvironment, function (err) {
if (err) {
var jsErr = err;
// If jsEnvironment wasn't found, try finding coffee variant
utils.file.searchParentPath(coffeeEnvironment, beginPath, function (err) {
if (err) {
throw jsErr;
} else {
environmentPath = coffeeEnvironment;
}
});
} else {
environmentPath = jsEnvironment;
}
});
if (environmentPath) {
text = fs.readFileSync(environmentPath, 'utf8').toString();
// Remove any old secret
text = text.replace(/\nconfig.secret.+\n/, '');
splitText = 'module.exports = config';
if (environmentPath.match('.js')) {
splitText += ';';
}
environmentArr = text.split(splitText);
environmentArr[0] += "config.secret = '" + secret + "'";
environmentArr[0] += environmentPath.match('.js') ? ';\n\n' : '\n\n';
text = environmentArr.join(splitText);
fs.writeFileSync(environmentPath, text, 'utf8');
console.log('[Added] Application secret to \'' + environmentPath + '\'');
}
else {
console.log('There is no environment config to add the app-secret to.');
}
});
});
Jump to Line
Something went wrong with that request. Please try again.