diff --git a/bin/sprout b/bin/sprout index b1bbf87..472a8b1 100755 --- a/bin/sprout +++ b/bin/sprout @@ -68,6 +68,18 @@ init.addArgument(['-c', '--config'], { help: 'a config file with pre-defined val init.addArgument(['-v', '--verbose'], { action: 'storeTrue', help: 'verbose mode' }); init.setDefaults({ action: 'init' }); +/* + * $ sprout run + */ + +var run = subParser.addParser('run', { aliases: ['generate'], addHelp: true }); +run.addArgument(['name'], { help: 'name of template' }); +run.addArgument(['generator'], { help: 'name of generator to run' }); +run.addArgument([], { nargs: '*', dest: 'args', help: 'arguments' }); +run.addArgument(['-t', '--target'], { help: 'destination path' }); +run.addArgument(['-v', '--verbose'], { action: 'storeTrue', help: 'verbose mode' }); +run.setDefaults({ action: 'run' }); + /* A helper function for determining a Sprout path. * @returns {String} - a path for Sprout. diff --git a/lib/api/add.js b/lib/api/add.js index 2dfac11..897bbc5 100644 --- a/lib/api/add.js +++ b/lib/api/add.js @@ -7,7 +7,7 @@ module.exports = (function () { * @param {Function} sprout - Sprout instance. * @param {String} name - name to save template as. * @param {String} src - path or URL to template source. - * @return {Promise} - Promise for Sprout instance. + * @return {Promise} - Promise for Template instance. */ return function (sprout, name, src) { diff --git a/lib/api/init.js b/lib/api/init.js index 83293a7..9332305 100644 --- a/lib/api/init.js +++ b/lib/api/init.js @@ -9,7 +9,7 @@ module.exports = (function () { * @param {Function} sprout - Sprout instance. * @param {String} name - name of template to initialize. * @param {String} target - The path to save the template to. - * @return {Promise} - Promise for Sprout instance. + * @return {Promise} - Promise for Template instance. */ return function (sprout, name, target, options) { diff --git a/lib/api/remove.js b/lib/api/remove.js index 8db531e..1906666 100644 --- a/lib/api/remove.js +++ b/lib/api/remove.js @@ -7,7 +7,7 @@ module.exports = (function () { * Remove a template. * @param {Function} sprout - Sprout instance. * @param {String} name - name of template to remove. - * @return {Promise} - Promise for Sprout instance. + * @return {Promise} - Promise for Template instance. */ return function (sprout, name) { diff --git a/lib/api/run.js b/lib/api/run.js new file mode 100644 index 0000000..744cef3 --- /dev/null +++ b/lib/api/run.js @@ -0,0 +1,23 @@ +var Template = require('./../template') + , Promise = require('bluebird'); + +module.exports = (function () { + + /* + * Run a generator in an existing template + * given the target path and generator name. + * @param {Function} sprout - Sprout instance. + * @param {String} name - name of template to run generator from. + * @param {String} target - The path of the existing instance. + * @param {String} generator - The generator to use. + * @param {Array} args - An array of arguments to pass to the generator. + * @return {Promise} - Promise for Template instance. + */ + + return function (sprout, name, target, generator, args) { + var template = sprout.templates[name]; + if (template) return template.run(target, generator, args); + return Promise.reject(new Error('template ' + name + ' does not exist')); + } + +}.call(this)); diff --git a/lib/cli.js b/lib/cli.js index 39ae7d4..1a8fe75 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,5 +1,4 @@ var Sprout = require('./') - , Emitter = require('events').EventEmitter , helpers = require('./helpers') , inquirer = require('inquirer') , Promise = require('bluebird') @@ -87,6 +86,23 @@ module.exports = (function () { return self.emitter.emit('success', 'template `' + name + '` initialized at ' + target + '!'); } ); + }, + + /* + * Run a generator on a template. + * @param {Object} options - CLI arguments. + */ + + run: function (options) { + var self = this + , name = options.name + , generator = options.generator + , target = options.target ? path.resolve(process.cwd(), options.target) : process.cwd(); + return this.sprout.run(name, target, generator, options.args).then( + function () { + return self.emitter.emit('success', 'template `' + name + '` ran generator `' + generator + '` at ' + target + '!'); + } + ) } } diff --git a/lib/configFile.js b/lib/configFile.js deleted file mode 100644 index e11dd78..0000000 --- a/lib/configFile.js +++ /dev/null @@ -1,77 +0,0 @@ -var Promise = require('bluebird') - , fs = Promise.promisifyAll(require('fs')) - , path = require('path') - , _ = require('lodash'); - -module.exports = (function () { - - /* - * Given a target path, returns a ConfigFile instance. - * @param {String} target - the target path - * @return {Function} - ConfigFile instance. - */ - - var ConfigFile = function (target, defaults) { - var lstat; - if (!fs.existsSync(target)) { - throw new Error(target + ' does not exist'); - } else { - lstat = fs.lstatSync(target); - if (!lstat.isDirectory()) { - throw new Error(target + ' is not a directory'); - } - } - this.path = path.join(target, '.sproutrc'); - this.config = _.extend({}, defaults); - } - - ConfigFile.prototype = { - - /* - * Read `configFile.path` - * @return {Promise} - a promise which returns the read configuration. - */ - - read: function () { - var self = this; - return new Promise( - function (resolve, reject) { - - /* - * If the config file exists, read it and - * resolve with the parsed output. if the - * file doesn't exist, simply resolve with - * the existing configuration. - */ - - if (fs.existsSync(self.path)) { - return fs.readFileAsync(self.path, 'utf8').then( - function (output) { - self.config = JSON.parse(output); - return resolve(self.config); - } - ) - } else { - return resolve(self.config); - } - - } - ); - }, - - /* - * Write `configFile.path` with the JSON - * set in `configFile.config`. - * @return {Promise} - a promise which returns the configuration. - */ - - write: function () { - return fs.writeFileAsync(this.path, JSON.stringify(this.config)) - .return(this.config); - } - - } - - return ConfigFile; - -}.call(this)); diff --git a/lib/index.js b/lib/index.js index 57324b9..c6c1ce1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -67,12 +67,28 @@ module.exports = (function () { * given target path. * @param {String} name - name of template to initialize. * @param {String} target - The path to save the template to. + * @param {Object} options - Initialization options. * @return {Promise} - Promise for Sprout instance. */ init: function (name, target, options) { return require('./api/init')(this, name, target, options) .return(this); + }, + + /* + * Run a generator in an existing template + * given the target path and generator name. + * @param {String} name - name of template to run generator from. + * @param {String} target - The path of the existing instance. + * @param {String} generator - The generator to use. + * @param {Array} args - An array of arguments to pass to the generator. + * @return {Promise} - Promise for Sprout instance. + */ + + run: function (name, target, generator, args) { + return require('./api/run')(this, name, target, generator, args) + .return(this); } } diff --git a/lib/template.js b/lib/template.js index db24dc7..4c6e5de 100644 --- a/lib/template.js +++ b/lib/template.js @@ -1,5 +1,4 @@ var Utils = require('./utils') - , ConfigFile = require('./configFile') , helpers = require('./helpers') , Promise = require('bluebird') , which = require('which') @@ -38,6 +37,7 @@ module.exports = (function () { this.name = name; this.path = path.join(sprout.path, name); this.root = path.join(this.path, 'root'); + this.generators = path.join(this.path, 'generators'); /* * If `src` is set, use `isGitURL` helper to @@ -335,9 +335,9 @@ module.exports = (function () { function (resolve, reject) { /* - * Check for init.coffee. If init.coffee doesn't - * exist, confirm that init.js exists. Require - * init once this is determined. + * Check for init.js. If init.js doesn't + * exist, confirm that init.coffee exists. + * Require init once this is determined. */ var initCoffee = path.join(self.path, 'init.coffee') @@ -450,20 +450,6 @@ module.exports = (function () { self.emitter.emit('msg', 'copying files in root to target'); return ncp(self.root, target); - } - ).then( - function () { - - var configFile = new ConfigFile(target, {name: self.name}); - - /* - * Write configuration file with - * the template's name. - */ - - self.emitter.emit('msg', 'creating sprout config file at target'); - return configFile.write(); - } ).then( function () { @@ -629,6 +615,104 @@ module.exports = (function () { ).return(this); }, + /* + * Run a template generator in the specified target. + * @param {String} target - the target path. + * @param {String} name - the name of the generator to use. + * @param + * @return {Promise} - Promise for Template instance. + */ + + run: function (target, generator, args) { + var self = this; + return new Promise( + function (resolve, reject) { + + /* + * If target not passed, + * throw an error. + */ + + if (!target) { + return reject(new Error('target path required')); + } + + /* + * If target directory doesn't exist, + * throw an error. + */ + + if (!fs.existsSync(target)) { + return reject(new Error(target + ' does not exist')); + } + + /* + * If generator name isn't + * passed, throw an error. + */ + + if (!generator) { + return reject(new Error('generator name required')); + } + + /* + * Check for {generator}.js. If {generator}.js + * doesn't exist, confirm that {name}.coffee exists. + * Require {generator}.js or {generator}.coffee once + * this is determined. + */ + + var generatorCoffee = path.join(self.generators, generator + '.coffee') + , generatorJs = path.join(self.generators, generator + '.js') + , generatorPath; + + if (fs.existsSync(generatorJs)) { + generatorPath = generatorJs; + } else if (fs.existsSync(generatorCoffee)) { + generatorPath = generatorCoffee; + } else { + return reject(new Error('`' + generator + '` is not a generator in this template')); + } + + try { + self.emitter.emit('msg', 'requiring `' + generator + '` generator'); + return resolve(require(generatorPath)); + } catch (error) { + return reject(error); + } + + } + ).then( + function (generator) { + + /* + * Create a Utils instance where + * the `src` and `target` are both + * the target directory. + */ + + var utils = new Utils(self.path, target); + + /* + * Add `utils` as the first object + * in our `args` array. + */ + + (args = _.isArray(args) ? args : []).unshift(utils); + + /* + * Call the generator; pass + * the Utils instance and the + * arguments. + */ + + self.emitter.emit('msg', 'running `' + generator + '` generator'); + return generator.apply(null, args); + + } + ).return(this); + }, + /* * Delete the template. * @return {Promise} - Promise for Template instance. diff --git a/readme.md b/readme.md index b5c2353..e51ffa5 100644 --- a/readme.md +++ b/readme.md @@ -78,9 +78,7 @@ $ sprout list $ sprout init ``` -**Description**: Initializes the template with the given `name` at the given `target`. If no path is provided it will create a new folder with the same name as the template in the current working directory. If there already is one, it will throw an error. - -Sprout also comes with a [man page](man) and will display a help menu as a refresher on these commands if you type something wrong. +**Description**: Initializes the template with the given `name` at the given `target`. **Options**: @@ -106,6 +104,26 @@ Sprout also comes with a [man page](man) and will display a help menu as a refre **Aliases**: `new`, `create` +#### sprout run + +```sh +$ sprout run +``` + +**Description**: Run a generator named `generator`, provided in a template with the given `name`, on a template instance in the current working directory. + +**Options**: + + * `-t TARGET`, `--target TARGET` + Optionally pass the path to the template instance (relative to the current working directory). + + * `[args, [args ...]]` + Pass arguments to the generator, like so: + + ```sh + $ sprout run mvc model User name:string age:integer + ``` + ## Javascript API Sprout was made specifically to be easy to integrate into javascript applications and libraries that create project structures for you. It can be installed locally via npm and used directly in a node project. The API is similar to the CLI interface described above. Each method returns a [A+ compliant](http://promises-aplus.github.io/promises-spec/) promise (with extra sugar from [bluebird](https://github.com/petkaantonov/bluebird)) Example code given in coffeescript: @@ -192,6 +210,21 @@ sprout.init(name, target, options).then( ); ``` +#### sprout.run(name, target, generator, args) + +Run a generator in a template called `name` and on template instance instance at `target`, optionally with an array of `args`. + +```javascript +var name = 'mvc' +var target = '~/Projects/mvc-instance'; +var generator = 'model'; +sprout.run(name, target, generator, ['User']).then( + function (sprout) { + console.log('a model named `User` was created!'); + } +); +``` + ## Writing Your Own Templates For an example, as well as a sprout template that helps you create new sprout templates, be sure to check out [sprout-sprout](https://github.com/carrot/sprout-sprout). @@ -202,6 +235,7 @@ First thing you'll want to do is set up your project structure, which will proba ``` ├── root Where the actual template goes. +├── generators Where generators go. │ ├── file1 │ └── file2 │ └── file3 @@ -307,6 +341,29 @@ The utilities object passed to each hook contains the following functions (each - `remove(what)` - remove files; pass a path or an array of paths (relative to the template's _target_ directory). - `exec(cmd, cwd)` - run a child process with the _target_ directory set at the current working directory by default; optionally, pass a path to `cwd` (relative to the target directory). +### Generators +Sprout templates may also include "generators": small scripts to be executed on instances of a template. For example, an `mvc` template may include `model`, `controller`, and `view` generators for quickly stubbing out an model-view-controller application. Generators are passed `utils` (an instance of the `Utils` that reads from the _base_ directory and writes to the _target_ directory) in the first argument; any arguments passed to `sprout.run()` follow. A model generator in an `mvc` template may look like this: + +```javascript +module.exports = function (utils, name) { + return utils.read('templates/model').then( + function (output) { + return utils.write('lib/models/' + name + '.js', output, {name: name}); + } + ) +} +``` + +These generators are stored in your template's `generators` folder and can be used with sprout's `run` method: + +```sh +$ sprout run mvc model User +``` + +```javascript +sprout.run('mvc', 'model', ['User']); +``` + ### Versioning Templates Sometimes changes happen and you might want to be able to specify different versions of a single template. Sprout handles this through [git tags](http://git-scm.com/book/en/Git-Basics-Tagging). To specify which tag to use, simply pass a `tag` option to sprout's `init` method. diff --git a/test/fixtures/api/run/src/generators/foo.js b/test/fixtures/api/run/src/generators/foo.js new file mode 100644 index 0000000..0711670 --- /dev/null +++ b/test/fixtures/api/run/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar'); +} diff --git a/test/fixtures/template/init/configFile/src/init.js b/test/fixtures/api/run/src/init.js similarity index 100% rename from test/fixtures/template/init/configFile/src/init.js rename to test/fixtures/api/run/src/init.js diff --git a/test/fixtures/template/init/configFile/src/root/.keep b/test/fixtures/api/run/src/root/.keep similarity index 100% rename from test/fixtures/template/init/configFile/src/root/.keep rename to test/fixtures/api/run/src/root/.keep diff --git a/test/fixtures/cli/generator/src/generators/foo.js b/test/fixtures/cli/generator/src/generators/foo.js new file mode 100644 index 0000000..0711670 --- /dev/null +++ b/test/fixtures/cli/generator/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar'); +} diff --git a/test/fixtures/cli/generator/src/init.js b/test/fixtures/cli/generator/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/cli/generator/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/cli/generator/src/root/.keep b/test/fixtures/cli/generator/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/sprout/run/src/generators/foo.js b/test/fixtures/sprout/run/src/generators/foo.js new file mode 100644 index 0000000..0711670 --- /dev/null +++ b/test/fixtures/sprout/run/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar'); +} diff --git a/test/fixtures/sprout/run/src/init.js b/test/fixtures/sprout/run/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/sprout/run/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/sprout/run/src/root/.keep b/test/fixtures/sprout/run/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/arguments/src/generators/foo.js b/test/fixtures/template/run/arguments/src/generators/foo.js new file mode 100644 index 0000000..3cd0b7e --- /dev/null +++ b/test/fixtures/template/run/arguments/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils, foo) { + return utils.write('foo', foo) +} diff --git a/test/fixtures/template/run/arguments/src/init.js b/test/fixtures/template/run/arguments/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/arguments/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/arguments/src/root/.keep b/test/fixtures/template/run/arguments/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/generatorCoffee/src/generators/foo.coffee b/test/fixtures/template/run/generatorCoffee/src/generators/foo.coffee new file mode 100644 index 0000000..442a1d8 --- /dev/null +++ b/test/fixtures/template/run/generatorCoffee/src/generators/foo.coffee @@ -0,0 +1,2 @@ +module.exports = (utils) -> + utils.write 'foo', 'bar' diff --git a/test/fixtures/template/run/generatorCoffee/src/init.js b/test/fixtures/template/run/generatorCoffee/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/generatorCoffee/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/generatorCoffee/src/root/.keep b/test/fixtures/template/run/generatorCoffee/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/generatorJs/src/generators/foo.js b/test/fixtures/template/run/generatorJs/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/generatorJs/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/generatorJs/src/init.js b/test/fixtures/template/run/generatorJs/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/generatorJs/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/generatorJs/src/root/.keep b/test/fixtures/template/run/generatorJs/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/generatorMissing/src/generators/foo.js b/test/fixtures/template/run/generatorMissing/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/generatorMissing/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/generatorMissing/src/init.js b/test/fixtures/template/run/generatorMissing/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/generatorMissing/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/generatorMissing/src/root/.keep b/test/fixtures/template/run/generatorMissing/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/noGenerator/src/generators/.keep b/test/fixtures/template/run/noGenerator/src/generators/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/noGenerator/src/init.js b/test/fixtures/template/run/noGenerator/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/noGenerator/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/noGenerator/src/root/.keep b/test/fixtures/template/run/noGenerator/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/noTarget/src/generators/foo.js b/test/fixtures/template/run/noTarget/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/noTarget/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/noTarget/src/init.js b/test/fixtures/template/run/noTarget/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/noTarget/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/noTarget/src/root/.keep b/test/fixtures/template/run/noTarget/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/requireError/src/generators/foo.js b/test/fixtures/template/run/requireError/src/generators/foo.js new file mode 100644 index 0000000..2e9ea7c --- /dev/null +++ b/test/fixtures/template/run/requireError/src/generators/foo.js @@ -0,0 +1,5 @@ +require('foo') + +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/requireError/src/init.js b/test/fixtures/template/run/requireError/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/requireError/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/requireError/src/root/.keep b/test/fixtures/template/run/requireError/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/run/src/generators/foo.js b/test/fixtures/template/run/run/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/run/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/run/src/init.js b/test/fixtures/template/run/run/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/run/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/run/src/root/.keep b/test/fixtures/template/run/run/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/targetMissing/src/generators/foo.js b/test/fixtures/template/run/targetMissing/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/targetMissing/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/targetMissing/src/init.js b/test/fixtures/template/run/targetMissing/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/targetMissing/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/targetMissing/src/root/.keep b/test/fixtures/template/run/targetMissing/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/template/run/undefinedArguments/src/generators/foo.js b/test/fixtures/template/run/undefinedArguments/src/generators/foo.js new file mode 100644 index 0000000..15dbc3f --- /dev/null +++ b/test/fixtures/template/run/undefinedArguments/src/generators/foo.js @@ -0,0 +1,3 @@ +module.exports = function (utils) { + return utils.write('foo', 'bar') +} diff --git a/test/fixtures/template/run/undefinedArguments/src/init.js b/test/fixtures/template/run/undefinedArguments/src/init.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/test/fixtures/template/run/undefinedArguments/src/init.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/fixtures/template/run/undefinedArguments/src/root/.keep b/test/fixtures/template/run/undefinedArguments/src/root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/test.js b/test/test.js index 7db069b..33a8de1 100644 --- a/test/test.js +++ b/test/test.js @@ -2,9 +2,9 @@ var Sprout = require('./../lib') , apiAdd = require('./../lib/api/add') , apiInit = require('./../lib/api/init') , apiRemove = require('./../lib/api/remove') + , apiRun = require('./../lib/api/run') , Template = require('./../lib/template') , Utils = require('./../lib/utils') - , ConfigFile = require('./../lib/configFile') , CLI = require('./../lib/cli') , helpers = require('./../lib/helpers') , chai = require('chai') @@ -142,7 +142,7 @@ describe('sprout', it('should init template', function (done) { var name = 'init' - , fixture = path.join(sproutFixturesPath, 'init') + , fixture = path.join(sproutFixturesPath, name) , src = 'https://github.com/carrot/sprout-sprout' , target = path.join(fixture, 'target'); sprout.add(name, src).then( @@ -181,6 +181,53 @@ describe('sprout', } ) + describe('run', + function () { + + it('should run generator in template', + function (done) { + var name = 'run' + , fixture = path.join(sproutFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target'); + return gitInit(src).then( + function () { + return sprout.add(name, src); + } + ).then( + function () { + sprout.templates[name].should.be.instanceof(Template); + sprout.templates[name].src.should.eq(src); + fs.existsSync(sprout.templates[name].path).should.be.true; + return sprout.init(name, target); + } + ).then( + function () { + return sprout.run(name, target, 'foo'); + } + ).then( + function () { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return sprout.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('should throw if no name', + function (done) { + (function () { sprout.run(null) }).should.throw; + done(); + } + ) + + } + ) + } ) @@ -300,6 +347,57 @@ describe('api', } ) + describe('run', + function () { + + it('should run generator in template', + function (done) { + var action = 'run' + , fixture = path.join(apiFixturesPath, action) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target'); + return gitInit(src).then( + function () { + return apiAdd(sprout, action, src); + } + ).then( + function () { + sprout.templates[action].should.be.ok; + fs.existsSync(path.join(sprout.path, action)).should.be.true; + return apiInit(sprout, action, target); + } + ).then( + function () { + fs.existsSync(target).should.be.true; + return apiRun(sprout, action, target, 'foo'); + } + ).then( + function () { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return apiRemove(sprout, action); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('should throw if template does not exists', + function (done) { + return apiRun(sprout, 'foo').catch( + function (error) { + error.toString().should.eq('Error: template foo does not exist'); + done(); + } + ) + } + ) + + } + ) + } ) @@ -1095,35 +1193,6 @@ describe('template', } ) - it('should create target configuration file', - function (done) { - var name = 'configFile' - , fixture = path.join(initTemplateFixturesPath, name) - , src = path.join(fixture, 'src') - , target = path.join(fixture, 'target') - , template = new Template(sprout, name, src); - return gitInit(src).then( - function () { - return template.save(); - } - ).then( - function (template) { - fs.existsSync(template.path).should.be.true; - return template.init(target); - } - ).then( - function (template) { - JSON.parse(fs.readFileSync(path.join(target, '.sproutrc'), 'utf8')).name.should.eq(name); - return template.remove(); - } - ).then( - function () { - return rimraf(target, done); - } - ) - } - ) - it('should ask questions if questionnaire is passed', function (done) { var name = 'questionnaire' @@ -1500,6 +1569,341 @@ describe('template', } ) + describe('run', + function () { + + var runTemplateFixturesPath; + + before( + function () { + runTemplateFixturesPath = path.join(templateFixturesPath, 'run'); + } + ) + + it('should run generator', + function (done) { + var name = 'run' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo'); + } + ).then( + function (template) { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return template.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('should throw if no target set', + function (done) { + var name = 'noTarget' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(null, 'foo'); + } + ).catch( + function (error) { + error.toString().should.eq('Error: target path required') + return template.remove(name).then( + function () { + return rimraf(target, done); + } + ); + } + ) + } + ) + + it('should throw if target missing', + function (done) { + var name = 'noTarget' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , fakeTarget = path.join(fixture, 'doge/doge/doge/doge/doge') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(fakeTarget, 'foo'); + } + ).catch( + function (error) { + error.toString().should.eq('Error: ' + fakeTarget + ' does not exist'); + return template.remove(name).then( + function () { + return rimraf(target, done); + } + ); + } + ) + } + ) + + it('should throw if no generator name', + function (done) { + var name = 'noGenerator' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, null); + } + ).catch( + function (error) { + error.toString().should.eq('Error: generator name required'); + return template.remove(name).then( + function () { + return rimraf(target, done); + } + ); + } + ) + } + ) + + it('should throw if generator missing', + function (done) { + var name = 'generatorMissing' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo2'); + } + ).catch( + function (error) { + error.toString().should.eq('Error: `foo2` is not a generator in this template'); + return template.remove(name).then( + function () { + return rimraf(target, done); + } + ); + } + ) + } + ) + + it('should run generator if it\'s a .js file', + function (done) { + var name = 'generatorJs' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo'); + } + ).then( + function (template) { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return template.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('should run generator if it\'s a .coffee file', + function (done) { + var name = 'generatorCoffee' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo'); + } + ).then( + function (template) { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return template.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('should throw error if require returns error', + function (done) { + var name = 'requireError' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo'); + } + ).catch( + function (error) { + error.toString().should.eq('Error: Cannot find module \'foo\''); + return template.remove(name).then( + function () { + return rimraf(target, done); + } + ); + } + ) + } + ) + + it('it should pass arguments', + function (done) { + var name = 'arguments' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo', ['bar']); + } + ).then( + function (template) { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return template.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + it('it should not break if undefined is passed as arguments', + function (done) { + var name = 'undefinedArguments' + , fixture = path.join(runTemplateFixturesPath, name) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target') + , template = new Template(sprout, name, src); + return gitInit(src).then( + function () { + return template.save(); + } + ).then( + function () { + return template.init(target); + } + ).then( + function (template) { + return template.run(target, 'foo', undefined); + } + ).then( + function (template) { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return template.remove(name); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + + } + ) + describe('remove', function () { @@ -1928,6 +2332,37 @@ describe('CLI', } ) + it('should run generator', + function (done) { + var action = 'generator' + , fixture = path.join(cliFixturesPath, action) + , src = path.join(fixture, 'src') + , target = path.join(fixture, 'target'); + return gitInit(src).then( + function () { + return cli.run({action: 'add', name: action, src: src}); + } + ).then( + function () { + return cli.run({action: 'init', name: action, target: target}); + } + ).then( + function () { + return cli.run({action: 'run', name: action, target: target, generator: 'foo'}); + } + ).then( + function () { + fs.readFileSync(path.join(target, 'foo'), 'utf8').should.eq('bar'); + return cli.run({action: 'remove', name: action}); + } + ).then( + function () { + return rimraf(target, done); + } + ) + } + ) + it('should emit error', function (done) { var onSuccess = function () { @@ -2024,124 +2459,6 @@ describe('helpers', } ) -describe('configFile', - function () { - - var configFileFixturesPath; - - before( - function () { - configFileFixturesPath = path.join(fixturesPath, 'configFile'); - } - ) - - it('should construct with a valid path', - function (done) { - var p = path.join(configFileFixturesPath, 'validPath') - , configFile = new ConfigFile(p); - configFile.path.should.eq(path.join(p, '.sproutrc')); - configFile.config.should.be.instanceof(Object); - done(); - } - ) - - it('should set defaults', - function (done) { - var p = path.join(configFileFixturesPath, 'setDefaults') - , configFile = new ConfigFile(p, {foo: 'bar'}); - configFile.path.should.eq(path.join(p, '.sproutrc')); - configFile.config.foo.should.eq('bar'); - done(); - } - ) - - it('should throw an error if the path doesn\'t exist', - function (done) { - var p = 'foo/bar/foo/bar/foo/bar/doge'; - (function () { return new ConfigFile(p) }).should.throw(p + ' does not exist'); - done(); - } - ) - - it('should throw if path is not a directory', - function (done) { - var p = path.join(configFileFixturesPath, 'notDirectory.foo'); - (function () { return new ConfigFile(p) }).should.throw(p + ' is not a directory'); - done(); - } - ) - - describe('read', - function () { - - var configFileReadFixturesPath; - - before( - function () { - configFileReadFixturesPath = path.join(configFileFixturesPath, 'read'); - } - ) - - it('should read a configuration file', - function (done) { - var fixture = path.join(configFileReadFixturesPath, 'read') - , configFile = new ConfigFile(fixture); - return configFile.read().then( - function (config) { - config.name.should.eq('foo'); - done(); - } - ) - } - ) - - it('should resolve with empty config if config file doesn\'t exist', - function (done) { - var fixture = path.join(configFileReadFixturesPath, 'noConfig') - , configFile = new ConfigFile(fixture); - return configFile.read().then( - function (config) { - config.should.be.empty; - done(); - } - ) - } - ) - - } - ) - - describe('write', - function () { - - var configFileWriteFixturesPath; - - before( - function () { - configFileWriteFixturesPath = path.join(configFileFixturesPath, 'write'); - } - ) - - it('should write a configuration file', - function (done) { - var fixture = path.join(configFileWriteFixturesPath, 'write') - , configFile = new ConfigFile(fixture, {foo: 'bar'}); - return configFile.write().then( - function () { - JSON.parse(fs.readFileSync(configFile.path, 'utf8')).foo.should.eq('bar'); - fs.unlinkSync(configFile.path); - done(); - } - ) - } - ) - - } - ) - - } -) - /* * Helper function for initializing a git repository * in the specified directory.