diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..cef23f00
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.DS_Store
+*.log
+node_modules
+build
+*.node
+components
+coverage
+*.orig
+.idea
+sandbox
+test/out-fixtures/*
+test/watch-*.txt
+gulp.1
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 00000000..af7124ee
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,19 @@
+{
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "freeze": true,
+ "indent": 2,
+ "newcap": false,
+ "quotmark": "single",
+ "maxdepth": 3,
+ "maxstatements": 50,
+ "maxlen": 80,
+ "eqnull": true,
+ "funcscope": true,
+ "strict": true,
+ "undef": true,
+ "unused": true,
+ "node": true,
+ "mocha": true
+}
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 00000000..f93c3951
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,12 @@
+.DS_Store
+*.log
+node_modules
+build
+*.node
+components
+coverage
+*.orig
+.idea
+sandbox
+test/out-fixtures/*
+test/watch-*.txt
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..dcbee380
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - "0.10"
+ - "0.11"
+after_script:
+ - npm run coveralls
+git:
+ depth: 10
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..bc29bea5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+# gulp-cli [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Support us][gittip-image]][gittip-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url]
+> The streaming build system
+
+[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/wearefractal/gulp/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+
+[gittip-url]: https://www.gittip.com/WeAreFractal/
+[gittip-image]: http://img.shields.io/gittip/WeAreFractal.svg
+
+[downloads-image]: http://img.shields.io/npm/dm/gulp.svg
+[npm-url]: https://npmjs.org/package/gulp
+[npm-image]: http://img.shields.io/npm/v/gulp.svg
+
+[travis-url]: https://travis-ci.org/gulpjs/gulp
+[travis-image]: http://img.shields.io/travis/gulpjs/gulp.svg
+
+[coveralls-url]: https://coveralls.io/r/gulpjs/gulp
+[coveralls-image]: http://img.shields.io/coveralls/gulpjs/gulp/master.svg
diff --git a/completion/README.md b/completion/README.md
new file mode 100644
index 00000000..c0e8c913
--- /dev/null
+++ b/completion/README.md
@@ -0,0 +1,20 @@
+# Completion for gulp
+> Thanks to grunt team and Tyler Kellen
+
+To enable tasks auto-completion in shell you should add `eval "$(gulp --completion=shell)"` in your `.shellrc` file.
+
+## Bash
+
+Add `eval "$(gulp --completion=bash)"` to `~/.bashrc`.
+
+## Zsh
+
+Add `eval "$(gulp --completion=zsh)"` to `~/.zshrc`.
+
+## Powershell
+
+Add `Invoke-Expression ((gulp --completion=powershell) -join [System.Environment]::NewLine)` to `$PROFILE`.
+
+## Fish
+
+Add `gulp --completion=fish | source` to `~/.config/fish/config.fish`.
diff --git a/completion/bash b/completion/bash
new file mode 100644
index 00000000..704c27c1
--- /dev/null
+++ b/completion/bash
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Borrowed from grunt-cli
+# http://gruntjs.com/
+#
+# Copyright (c) 2012 Tyler Kellen, contributors
+# Licensed under the MIT license.
+# https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
+
+# Usage:
+#
+# To enable bash completion for gulp, add the following line (minus the
+# leading #, which is the bash comment character) to your ~/.bashrc file:
+#
+# eval "$(gulp --completion=bash)"
+
+# Enable bash autocompletion.
+function _gulp_completions() {
+ # The currently-being-completed word.
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+ #Grab tasks
+ local compls=$(gulp --tasks-simple)
+ # Tell complete what stuff to show.
+ COMPREPLY=($(compgen -W "$compls" -- "$cur"))
+}
+
+complete -o default -F _gulp_completions gulp
diff --git a/completion/fish b/completion/fish
new file mode 100644
index 00000000..f27f2248
--- /dev/null
+++ b/completion/fish
@@ -0,0 +1,10 @@
+#!/usr/bin/env fish
+
+# Usage:
+#
+# To enable fish completion for gulp, add the following line to
+# your ~/.config/fish/config.fish file:
+#
+# gulp --completion=fish | source
+
+complete -c gulp -a "(gulp --tasks-simple)" -f
diff --git a/completion/powershell b/completion/powershell
new file mode 100644
index 00000000..08ec4382
--- /dev/null
+++ b/completion/powershell
@@ -0,0 +1,61 @@
+# Copyright (c) 2014 Jason Jarrett
+#
+# Tab completion for the `gulp`
+#
+# Usage:
+#
+# To enable powershell completion for gulp you need to be running
+# at least PowerShell v3 or greater and add the below to your $PROFILE
+#
+# Invoke-Expression ((gulp --completion=powershell) -join [System.Environment]::NewLine)
+#
+#
+
+$gulp_completion_Process = {
+ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
+
+
+ # Load up an assembly to read the gulpfile's sha1
+ if(-not $global:GulpSHA1Managed) {
+ [Reflection.Assembly]::LoadWithPartialName("System.Security") | out-null
+ $global:GulpSHA1Managed = new-Object System.Security.Cryptography.SHA1Managed
+ }
+
+ # setup a global (in-memory) cache
+ if(-not $global:GulpfileShaCache) {
+ $global:GulpfileShaCache = @{};
+ }
+
+ $cache = $global:GulpfileShaCache;
+
+ # Get the gulpfile's sha1
+ $sha1gulpFile = (resolve-path gulpfile.js -ErrorAction Ignore | %{
+ $file = [System.IO.File]::Open($_.Path, "open", "read")
+ [string]::join('', ($global:GulpSHA1Managed.ComputeHash($file) | %{ $_.ToString("x2") }))
+ $file.Dispose()
+ })
+
+ # lookup the sha1 for previously cached task lists.
+ if($cache.ContainsKey($sha1gulpFile)){
+ $tasks = $cache[$sha1gulpFile];
+ } else {
+ $tasks = (gulp --tasks-simple).split("`n");
+ $cache[$sha1gulpFile] = $tasks;
+ }
+
+
+ $tasks |
+ where { $_.startswith($commandName) }
+ Sort-Object |
+ foreach { New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', ('{0}' -f $_) }
+}
+
+if (-not $global:options) {
+ $global:options = @{
+ CustomArgumentCompleters = @{};
+ NativeArgumentCompleters = @{}
+ }
+}
+
+$global:options['NativeArgumentCompleters']['gulp'] = $gulp_completion_Process
+$function:tabexpansion2 = $function:tabexpansion2 -replace 'End\r\n{','End { if ($null -ne $options) { $options += $global:options} else {$options = $global:options}'
diff --git a/completion/zsh b/completion/zsh
new file mode 100644
index 00000000..8169b22d
--- /dev/null
+++ b/completion/zsh
@@ -0,0 +1,25 @@
+#!/bin/zsh
+
+# Borrowed from grunt-cli
+# http://gruntjs.com/
+#
+# Copyright (c) 2012 Tyler Kellen, contributors
+# Licensed under the MIT license.
+# https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
+
+# Usage:
+#
+# To enable zsh completion for gulp, add the following line (minus the
+# leading #, which is the zsh comment character) to your ~/.zshrc file:
+#
+# eval "$(gulp --completion=zsh)"
+
+# Enable zsh autocompletion.
+function _gulp_completion() {
+ # Grab tasks
+ compls=$(gulp --tasks-simple)
+ completions=(${=compls})
+ compadd -- $completions
+}
+
+compdef _gulp_completion gulp
diff --git a/docs/CLI.md b/docs/CLI.md
new file mode 100644
index 00000000..1490e9d2
--- /dev/null
+++ b/docs/CLI.md
@@ -0,0 +1,25 @@
+## gulp CLI docs
+
+### Flags
+
+gulp has very few flags to know about. All other flags are for tasks to use if needed.
+
+- `-v` or `--version` will display the global and local gulp versions
+- `--require ` will require a module before running the gulpfile. This is useful for transpilers but also has other applications. You can use multiple `--require` flags
+- `--gulpfile ` will manually set path of gulpfile. Useful if you have multiple gulpfiles. This will set the CWD to the gulpfile directory as well
+- `--cwd ` will manually set the CWD. The search for the gulpfile, as well as the relativity of all requires will be from here
+- `-T` or `--tasks` will display the task dependency tree for the loaded gulpfile
+- `--tasks-simple` will display a plaintext list of tasks for the loaded gulpfile
+- `--color` will force gulp and gulp plugins to display colors even when no color support is detected
+- `--no-color` will force gulp and gulp plugins to not display colors even when color support is detected
+- `--silent` will disable all gulp logging
+
+The CLI adds process.env.INIT_CWD which is the original cwd it was launched from.
+
+### Tasks
+
+Tasks can be executed by running `gulp `. Just running `gulp` will execute the task you registered called `default`. If there is no `default` task gulp will error.
+
+### Compilers
+
+You can find a list of supported languages at [interpret](https://github.com/tkellen/node-interpret#jsvariants). If you would like to add support for a new language send pull request/open issues there.
diff --git a/index.js b/index.js
new file mode 100755
index 00000000..589cd371
--- /dev/null
+++ b/index.js
@@ -0,0 +1,212 @@
+#!/usr/bin/env node
+
+'use strict';
+var gutil = require('gulp-util');
+var prettyTime = require('pretty-hrtime');
+var chalk = require('chalk');
+var semver = require('semver');
+var archy = require('archy');
+var Liftoff = require('liftoff');
+var tildify = require('tildify');
+var interpret = require('interpret');
+var v8flags = require('v8flags');
+var completion = require('./lib/completion');
+var argv = require('minimist')(process.argv.slice(2));
+var taskTree = require('./lib/taskTree');
+
+// set env var for ORIGINAL cwd
+// before anything touches it
+process.env.INIT_CWD = process.cwd();
+
+var cli = new Liftoff({
+ name: 'gulp',
+ completions: completion,
+ extensions: interpret.jsVariants,
+ nodeFlags: v8flags.fetch()
+});
+
+// exit with 0 or 1
+var failed = false;
+process.once('exit', function(code) {
+ if (code === 0 && failed) {
+ process.exit(1);
+ }
+});
+
+// parse those args m8
+var cliPackage = require('./package');
+var versionFlag = argv.v || argv.version;
+var tasksFlag = argv.T || argv.tasks;
+var tasks = argv._;
+var toRun = tasks.length ? tasks : ['default'];
+
+// this is a hold-over until we have a better logging system
+// with log levels
+var simpleTasksFlag = argv['tasks-simple'];
+var shouldLog = !argv.silent && !simpleTasksFlag;
+
+if (!shouldLog) {
+ gutil.log = function(){};
+}
+
+cli.on('require', function (name) {
+ gutil.log('Requiring external module', chalk.magenta(name));
+});
+
+cli.on('requireFail', function (name) {
+ gutil.log(chalk.red('Failed to load external module'), chalk.magenta(name));
+});
+
+cli.on('respawn', function (flags, child) {
+ var nodeFlags = chalk.magenta(flags.join(', '));
+ var pid = chalk.magenta(child.pid);
+ gutil.log('Node flags detected:', nodeFlags);
+ gutil.log('Respawned to PID:', pid);
+});
+
+cli.launch({
+ cwd: argv.cwd,
+ configPath: argv.gulpfile,
+ require: argv.require,
+ completion: argv.completion
+}, handleArguments);
+
+// the actual logic
+function handleArguments(env) {
+ if (versionFlag && tasks.length === 0) {
+ gutil.log('CLI version', cliPackage.version);
+ if (env.modulePackage && typeof env.modulePackage.version !== 'undefined') {
+ gutil.log('Local version', env.modulePackage.version);
+ }
+ process.exit(0);
+ }
+
+ if (!env.modulePath) {
+ gutil.log(
+ chalk.red('Local gulp not found in'),
+ chalk.magenta(tildify(env.cwd))
+ );
+ gutil.log(chalk.red('Try running: npm install gulp'));
+ process.exit(1);
+ }
+
+ if (!env.configPath) {
+ gutil.log(chalk.red('No gulpfile found'));
+ process.exit(1);
+ }
+
+ // check for semver difference between cli and local installation
+ if (semver.gt(cliPackage.version, env.modulePackage.version)) {
+ gutil.log(chalk.red('Warning: gulp version mismatch:'));
+ gutil.log(chalk.red('Global gulp is', cliPackage.version));
+ gutil.log(chalk.red('Local gulp is', env.modulePackage.version));
+ }
+
+ // chdir before requiring gulpfile to make sure
+ // we let them chdir as needed
+ if (process.cwd() !== env.cwd) {
+ process.chdir(env.cwd);
+ gutil.log(
+ 'Working directory changed to',
+ chalk.magenta(tildify(env.cwd))
+ );
+ }
+
+ // this is what actually loads up the gulpfile
+ require(env.configPath);
+ gutil.log('Using gulpfile', chalk.magenta(tildify(env.configPath)));
+
+ var gulpInst = require(env.modulePath);
+ logEvents(gulpInst);
+
+ process.nextTick(function () {
+ if (simpleTasksFlag) {
+ return logTasksSimple(env, gulpInst);
+ }
+ if (tasksFlag) {
+ return logTasks(env, gulpInst);
+ }
+ gulpInst.start.apply(gulpInst, toRun);
+ });
+}
+
+function logTasks(env, localGulp) {
+ var tree = taskTree(localGulp.tasks);
+ tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath));
+ archy(tree)
+ .split('\n')
+ .forEach(function (v) {
+ if (v.trim().length === 0) {
+ return;
+ }
+ gutil.log(v);
+ });
+}
+
+function logTasksSimple(env, localGulp) {
+ console.log(Object.keys(localGulp.tasks)
+ .join('\n')
+ .trim());
+}
+
+// format orchestrator errors
+function formatError(e) {
+ if (!e.err) {
+ return e.message;
+ }
+
+ // PluginError
+ if (typeof e.err.showStack === 'boolean') {
+ return e.err.toString();
+ }
+
+ // normal error
+ if (e.err.stack) {
+ return e.err.stack;
+ }
+
+ // unknown (string, number, etc.)
+ return new Error(String(e.err)).stack;
+}
+
+// wire up logging events
+function logEvents(gulpInst) {
+
+ // total hack due to poor error management in orchestrator
+ gulpInst.on('err', function () {
+ failed = true;
+ });
+
+ gulpInst.on('task_start', function (e) {
+ // TODO: batch these
+ // so when 5 tasks start at once it only logs one time with all 5
+ gutil.log('Starting', '\'' + chalk.cyan(e.task) + '\'...');
+ });
+
+ gulpInst.on('task_stop', function (e) {
+ var time = prettyTime(e.hrDuration);
+ gutil.log(
+ 'Finished', '\'' + chalk.cyan(e.task) + '\'',
+ 'after', chalk.magenta(time)
+ );
+ });
+
+ gulpInst.on('task_err', function (e) {
+ var msg = formatError(e);
+ var time = prettyTime(e.hrDuration);
+ gutil.log(
+ '\'' + chalk.cyan(e.task) + '\'',
+ chalk.red('errored after'),
+ chalk.magenta(time)
+ );
+ gutil.log(msg);
+ });
+
+ gulpInst.on('task_not_found', function (err) {
+ gutil.log(
+ chalk.red('Task \'' + err.task + '\' is not in your gulpfile')
+ );
+ gutil.log('Please check the documentation for proper gulpfile formatting');
+ process.exit(1);
+ });
+}
diff --git a/lib/completion.js b/lib/completion.js
new file mode 100644
index 00000000..5f2ad364
--- /dev/null
+++ b/lib/completion.js
@@ -0,0 +1,22 @@
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+module.exports = function (name) {
+ if (typeof name !== 'string') {
+ throw new Error('Missing completion type');
+ }
+ var file = path.join(__dirname, '../completion', name);
+ try {
+ console.log(fs.readFileSync(file, 'utf8'));
+ process.exit(0);
+ } catch (err) {
+ console.log(
+ 'echo "gulp autocompletion rules for',
+ '\'' + name + '\'',
+ 'not found"'
+ );
+ process.exit(5);
+ }
+};
diff --git a/lib/taskTree.js b/lib/taskTree.js
new file mode 100644
index 00000000..8a638f7a
--- /dev/null
+++ b/lib/taskTree.js
@@ -0,0 +1,14 @@
+'use strict';
+
+module.exports = function (tasks) {
+ return Object.keys(tasks)
+ .reduce(function (prev, task) {
+ prev.nodes.push({
+ label: task,
+ nodes: tasks[task].dep
+ });
+ return prev;
+ }, {
+ nodes: []
+ });
+};
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..dd2a2a98
--- /dev/null
+++ b/package.json
@@ -0,0 +1,69 @@
+{
+ "name": "gulp-cli",
+ "description": "The streaming build system",
+ "version": "0.0.0",
+ "homepage": "http://gulpjs.com",
+ "repository": "gulpjs/gulp-cli",
+ "author": "Fractal (http://wearefractal.com/)",
+ "tags": [
+ "build",
+ "stream",
+ "system",
+ "make",
+ "tool",
+ "asset",
+ "pipeline"
+ ],
+ "files": [
+ "index.js",
+ "lib",
+ "completion"
+ ],
+ "bin": {
+ "gulp": "./index.js"
+ },
+ "man": "gulp.1",
+ "dependencies": {
+ "archy": "^1.0.0",
+ "chalk": "^0.5.0",
+ "gulp-util": "^3.0.0",
+ "interpret": "^0.3.2",
+ "liftoff": "^1.0.0",
+ "minimist": "^1.1.0",
+ "pretty-hrtime": "^0.2.0",
+ "semver": "^4.1.0",
+ "tildify": "^1.0.0",
+ "v8flags": "^1.0.1"
+ },
+ "devDependencies": {
+ "coveralls": "^2.7.0",
+ "graceful-fs": "^3.0.0",
+ "gulp": "^3.8.10",
+ "istanbul": "^0.3.0",
+ "jshint": "^2.5.0",
+ "jshint-stylish": "^1.0.0",
+ "marked-man": "^0.1.3",
+ "mkdirp": "^0.5.0",
+ "mocha": "^2.0.1",
+ "mocha-lcov-reporter": "^0.0.1",
+ "q": "^1.0.0",
+ "rimraf": "^2.2.5",
+ "should": "^4.0.0"
+ },
+ "scripts": {
+ "prepublish": "marked-man --name gulp docs/CLI.md > gulp.1",
+ "lint": "jshint lib bin index.js --reporter node_modules/jshint-stylish/stylish.js --exclude node_modules",
+ "test": "npm run-script lint && mocha --reporter spec",
+ "coveralls": "istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage"
+ },
+ "engineStrict": true,
+ "engines": {
+ "node": ">= 0.9"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://raw.githubusercontent.com/gulpjs/gulp/master/LICENSE"
+ }
+ ]
+}
diff --git a/test/gulpfile.js b/test/gulpfile.js
new file mode 100644
index 00000000..bea0366d
--- /dev/null
+++ b/test/gulpfile.js
@@ -0,0 +1,7 @@
+'use strict';
+
+var gulp = require('gulp');
+
+gulp.task('default', function(){
+
+});