From 41e184c1d145a59f70f1ad4556597b4e02835ffa Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 7 Nov 2016 19:48:24 -0800 Subject: [PATCH 1/3] chore(install): move ember cli in our repo and remove everything unnecessary --- .eslintignore | 3 + lib/bootstrap-local.js | 8 +- lib/packages.js | 1 + package.json | 2 - .../angular-cli/blueprints/class/index.js | 2 +- .../angular-cli/blueprints/component/index.js | 2 +- .../angular-cli/blueprints/directive/index.js | 2 +- .../angular-cli/blueprints/module/index.js | 2 +- packages/angular-cli/blueprints/ng2/index.js | 2 +- packages/angular-cli/blueprints/pipe/index.js | 2 +- .../angular-cli/blueprints/service/index.js | 2 +- packages/angular-cli/commands/build.ts | 2 +- packages/angular-cli/commands/completion.ts | 2 +- packages/angular-cli/commands/destroy.ts | 2 +- packages/angular-cli/commands/doc.ts | 2 +- packages/angular-cli/commands/e2e.ts | 2 +- packages/angular-cli/commands/easter-egg.ts | 2 +- packages/angular-cli/commands/generate.ts | 4 +- packages/angular-cli/commands/get.ts | 2 +- .../commands/github-pages-deploy.ts | 2 +- packages/angular-cli/commands/help.ts | 4 +- packages/angular-cli/commands/init.ts | 9 +- packages/angular-cli/commands/lint.ts | 2 +- packages/angular-cli/commands/new.ts | 6 +- packages/angular-cli/commands/serve.ts | 3 +- packages/angular-cli/commands/set.ts | 2 +- packages/angular-cli/commands/test.ts | 2 +- packages/angular-cli/commands/version.ts | 2 +- packages/angular-cli/lib/cli/index.js | 6 +- packages/angular-cli/package.json | 4 +- .../angular-cli/tasks/build-webpack-watch.ts | 2 +- packages/angular-cli/tasks/build-webpack.ts | 2 +- .../angular-cli/tasks/create-github-repo.ts | 2 +- packages/angular-cli/tasks/doc.ts | 2 +- packages/angular-cli/tasks/e2e.ts | 2 +- packages/angular-cli/tasks/git-init.js | 4 +- packages/angular-cli/tasks/link-cli.ts | 2 +- packages/angular-cli/tasks/lint.ts | 2 +- packages/angular-cli/tasks/npm-install.ts | 2 +- packages/angular-cli/tasks/serve-webpack.ts | 2 +- packages/angular-cli/tasks/test.ts | 2 +- packages/ast-tools/src/change.spec.ts | 2 +- packages/ember-cli/LICENSE.md | 21 + packages/ember-cli/bin/ember | 35 + packages/ember-cli/lib/cli/cli.js | 165 ++ packages/ember-cli/lib/cli/index.js | 105 ++ packages/ember-cli/lib/cli/lookup-command.js | 64 + packages/ember-cli/lib/commands/addon.js | 22 + .../ember-cli/lib/commands/asset-sizes.js | 19 + packages/ember-cli/lib/commands/build.js | 50 + packages/ember-cli/lib/commands/destroy.js | 77 + packages/ember-cli/lib/commands/generate.js | 155 ++ packages/ember-cli/lib/commands/help.js | 132 ++ packages/ember-cli/lib/commands/init.js | 125 ++ .../ember-cli/lib/commands/install-addon.js | 17 + .../ember-cli/lib/commands/install-bower.js | 22 + .../ember-cli/lib/commands/install-npm.js | 22 + packages/ember-cli/lib/commands/install.js | 39 + packages/ember-cli/lib/commands/new.js | 102 + packages/ember-cli/lib/commands/test.js | 175 ++ .../ember-cli/lib/commands/uninstall-npm.js | 22 + packages/ember-cli/lib/commands/unknown.js | 20 + packages/ember-cli/lib/commands/version.js | 34 + packages/ember-cli/lib/errors/silent.js | 11 + packages/ember-cli/lib/ext/promise.js | 68 + .../ember-cli/lib/models/addon-discovery.js | 260 +++ packages/ember-cli/lib/models/addon.js | 979 ++++++++++ .../ember-cli/lib/models/addons-factory.js | 66 + packages/ember-cli/lib/models/blueprint.js | 1637 +++++++++++++++++ packages/ember-cli/lib/models/builder.js | 187 ++ packages/ember-cli/lib/models/command.js | 510 +++++ .../ember-cli/lib/models/edit-file-diff.js | 63 + packages/ember-cli/lib/models/file-info.js | 173 ++ .../lib/models/installation-checker.js | 75 + packages/ember-cli/lib/models/project.js | 733 ++++++++ .../ember-cli/lib/models/server-watcher.js | 61 + packages/ember-cli/lib/models/task.js | 15 + .../ember-cli/lib/models/update-checker.js | 104 ++ packages/ember-cli/lib/models/watcher.js | 134 ++ packages/ember-cli/lib/tasks/addon-install.js | 81 + packages/ember-cli/lib/tasks/bower-install.js | 57 + packages/ember-cli/lib/tasks/build-watch.js | 29 + packages/ember-cli/lib/tasks/build.js | 52 + .../tasks/create-and-step-into-directory.js | 46 + .../lib/tasks/destroy-from-blueprint.js | 9 + .../lib/tasks/generate-from-blueprint.js | 96 + packages/ember-cli/lib/tasks/git-init.js | 50 + .../ember-cli/lib/tasks/install-blueprint.js | 56 + packages/ember-cli/lib/tasks/npm-install.js | 11 + packages/ember-cli/lib/tasks/npm-task.js | 64 + packages/ember-cli/lib/tasks/npm-uninstall.js | 11 + packages/ember-cli/lib/tasks/update.js | 118 ++ packages/ember-cli/lib/ui/index.js | 231 +++ packages/ember-cli/lib/ui/write-error.js | 25 + .../lib/utilities/COMMIT_MESSAGE.txt | 39 + packages/ember-cli/lib/utilities/DAG.js | 110 ++ .../lib/utilities/attempt-never-index.js | 20 + packages/ember-cli/lib/utilities/deprecate.js | 19 + .../ember-cli/lib/utilities/doc-generator.js | 24 + .../lib/utilities/find-build-file.js | 28 + .../lib/utilities/get-option-args.js | 15 + .../lib/utilities/get-package-base-name.js | 12 + .../ember-cli/lib/utilities/json-generator.js | 100 + .../ember-cli/lib/utilities/markdown-color.js | 213 +++ .../lib/utilities/merge-blueprint-options.js | 31 + .../ember-cli/lib/utilities/mk-tmp-dir-in.js | 25 + .../utilities/normalize-blueprint-option.js | 7 + packages/ember-cli/lib/utilities/npm.js | 38 + .../ember-cli/lib/utilities/open-editor.js | 42 + .../ember-cli/lib/utilities/parse-options.js | 11 + packages/ember-cli/lib/utilities/path.js | 31 + .../lib/utilities/platform-checker.js | 35 + .../ember-cli/lib/utilities/print-command.js | 92 + .../lib/utilities/printable-properties.js | 36 + .../lib/utilities/require-as-hash.js | 33 + .../ember-cli/lib/utilities/require-local.js | 8 + .../ember-cli/lib/utilities/root-command.js | 12 + packages/ember-cli/lib/utilities/sequence.js | 41 + .../lib/utilities/valid-project-name.js | 11 + .../ember-cli/lib/utilities/version-utils.js | 26 + .../ember-cli/lib/utilities/windows-admin.js | 41 + packages/ember-cli/package.json | 66 + packages/ember-cli/tsconfig.json | 34 + scripts/publish/build.js | 15 +- tests/acceptance/destroy.spec.js | 5 - tests/acceptance/generate-class.spec.js | 5 - tests/acceptance/generate-component.spec.js | 7 +- tests/acceptance/generate-directive.spec.js | 7 +- tests/acceptance/generate-module.spec.js | 5 - tests/acceptance/generate-pipe.spec.js | 7 +- tests/acceptance/generate-route.spec.js | 5 - tests/acceptance/generate-service.spec.js | 7 +- tests/acceptance/github-pages-deploy.spec.js | 7 +- tests/acceptance/init.spec.js | 11 +- tests/acceptance/new.spec.js | 9 +- tests/e2e/setup/010-build.ts | 17 +- tests/e2e/setup/500-create-project.ts | 11 +- tests/helpers/mock-ui.js | 4 +- tests/helpers/tmp.js | 2 +- 139 files changed, 8739 insertions(+), 134 deletions(-) create mode 100644 packages/ember-cli/LICENSE.md create mode 100755 packages/ember-cli/bin/ember create mode 100644 packages/ember-cli/lib/cli/cli.js create mode 100644 packages/ember-cli/lib/cli/index.js create mode 100644 packages/ember-cli/lib/cli/lookup-command.js create mode 100644 packages/ember-cli/lib/commands/addon.js create mode 100644 packages/ember-cli/lib/commands/asset-sizes.js create mode 100644 packages/ember-cli/lib/commands/build.js create mode 100644 packages/ember-cli/lib/commands/destroy.js create mode 100644 packages/ember-cli/lib/commands/generate.js create mode 100644 packages/ember-cli/lib/commands/help.js create mode 100644 packages/ember-cli/lib/commands/init.js create mode 100644 packages/ember-cli/lib/commands/install-addon.js create mode 100644 packages/ember-cli/lib/commands/install-bower.js create mode 100644 packages/ember-cli/lib/commands/install-npm.js create mode 100644 packages/ember-cli/lib/commands/install.js create mode 100644 packages/ember-cli/lib/commands/new.js create mode 100644 packages/ember-cli/lib/commands/test.js create mode 100644 packages/ember-cli/lib/commands/uninstall-npm.js create mode 100644 packages/ember-cli/lib/commands/unknown.js create mode 100644 packages/ember-cli/lib/commands/version.js create mode 100644 packages/ember-cli/lib/errors/silent.js create mode 100644 packages/ember-cli/lib/ext/promise.js create mode 100644 packages/ember-cli/lib/models/addon-discovery.js create mode 100644 packages/ember-cli/lib/models/addon.js create mode 100644 packages/ember-cli/lib/models/addons-factory.js create mode 100644 packages/ember-cli/lib/models/blueprint.js create mode 100644 packages/ember-cli/lib/models/builder.js create mode 100644 packages/ember-cli/lib/models/command.js create mode 100644 packages/ember-cli/lib/models/edit-file-diff.js create mode 100644 packages/ember-cli/lib/models/file-info.js create mode 100644 packages/ember-cli/lib/models/installation-checker.js create mode 100644 packages/ember-cli/lib/models/project.js create mode 100644 packages/ember-cli/lib/models/server-watcher.js create mode 100644 packages/ember-cli/lib/models/task.js create mode 100644 packages/ember-cli/lib/models/update-checker.js create mode 100644 packages/ember-cli/lib/models/watcher.js create mode 100644 packages/ember-cli/lib/tasks/addon-install.js create mode 100644 packages/ember-cli/lib/tasks/bower-install.js create mode 100644 packages/ember-cli/lib/tasks/build-watch.js create mode 100644 packages/ember-cli/lib/tasks/build.js create mode 100644 packages/ember-cli/lib/tasks/create-and-step-into-directory.js create mode 100644 packages/ember-cli/lib/tasks/destroy-from-blueprint.js create mode 100644 packages/ember-cli/lib/tasks/generate-from-blueprint.js create mode 100644 packages/ember-cli/lib/tasks/git-init.js create mode 100644 packages/ember-cli/lib/tasks/install-blueprint.js create mode 100644 packages/ember-cli/lib/tasks/npm-install.js create mode 100644 packages/ember-cli/lib/tasks/npm-task.js create mode 100644 packages/ember-cli/lib/tasks/npm-uninstall.js create mode 100644 packages/ember-cli/lib/tasks/update.js create mode 100644 packages/ember-cli/lib/ui/index.js create mode 100644 packages/ember-cli/lib/ui/write-error.js create mode 100644 packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt create mode 100644 packages/ember-cli/lib/utilities/DAG.js create mode 100644 packages/ember-cli/lib/utilities/attempt-never-index.js create mode 100644 packages/ember-cli/lib/utilities/deprecate.js create mode 100644 packages/ember-cli/lib/utilities/doc-generator.js create mode 100644 packages/ember-cli/lib/utilities/find-build-file.js create mode 100644 packages/ember-cli/lib/utilities/get-option-args.js create mode 100644 packages/ember-cli/lib/utilities/get-package-base-name.js create mode 100644 packages/ember-cli/lib/utilities/json-generator.js create mode 100644 packages/ember-cli/lib/utilities/markdown-color.js create mode 100644 packages/ember-cli/lib/utilities/merge-blueprint-options.js create mode 100644 packages/ember-cli/lib/utilities/mk-tmp-dir-in.js create mode 100644 packages/ember-cli/lib/utilities/normalize-blueprint-option.js create mode 100644 packages/ember-cli/lib/utilities/npm.js create mode 100644 packages/ember-cli/lib/utilities/open-editor.js create mode 100644 packages/ember-cli/lib/utilities/parse-options.js create mode 100644 packages/ember-cli/lib/utilities/path.js create mode 100644 packages/ember-cli/lib/utilities/platform-checker.js create mode 100644 packages/ember-cli/lib/utilities/print-command.js create mode 100644 packages/ember-cli/lib/utilities/printable-properties.js create mode 100644 packages/ember-cli/lib/utilities/require-as-hash.js create mode 100644 packages/ember-cli/lib/utilities/require-local.js create mode 100644 packages/ember-cli/lib/utilities/root-command.js create mode 100644 packages/ember-cli/lib/utilities/sequence.js create mode 100644 packages/ember-cli/lib/utilities/valid-project-name.js create mode 100644 packages/ember-cli/lib/utilities/version-utils.js create mode 100644 packages/ember-cli/lib/utilities/windows-admin.js create mode 100644 packages/ember-cli/package.json create mode 100644 packages/ember-cli/tsconfig.json diff --git a/.eslintignore b/.eslintignore index fb4ee165bd86..f220aa998f21 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,3 +6,6 @@ typings/ # Ignore all blueprint files. We e2e tests those later on. packages/angular-cli/blueprints/*/files/ + +# Ignore ember cli. +packages/ember-cli/ \ No newline at end of file diff --git a/lib/bootstrap-local.js b/lib/bootstrap-local.js index 34b7a28c7a47..802e55ebae0e 100644 --- a/lib/bootstrap-local.js +++ b/lib/bootstrap-local.js @@ -61,7 +61,13 @@ if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) { const newRequest = path.relative(dir, path.join(__dirname, '../packages', request)); return oldLoad.call(this, newRequest, parent); } else { - return oldLoad.apply(this, arguments); + let match = Object.keys(packages).find(pkgName => request.startsWith(pkgName + '/')); + if (match) { + const p = path.join(packages[match].root, request.substr(match.length)); + return oldLoad.call(this, p, parent); + } else { + return oldLoad.apply(this, arguments); + } } }; } diff --git a/lib/packages.js b/lib/packages.js index 204f71dab448..69b9b378d821 100644 --- a/lib/packages.js +++ b/lib/packages.js @@ -17,6 +17,7 @@ const packages = fs.readdirSync(packageRoot) dist: path.join(__dirname, '../dist', pkg.name), packageJson: path.join(pkg.root, 'package.json'), root: pkg.root, + relative: path.relative(path.dirname(__dirname), pkg.root), main: path.resolve(pkg.root, 'src/index.ts') }; return packages; diff --git a/package.json b/package.json index 4290a066bc78..ea1dcfc80eeb 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "fs-extra": "^0.30.0", "fs.realpath": "^1.0.0", "glob": "^7.0.3", - "handlebars": "^4.0.5", "html-webpack-plugin": "^2.19.0", "istanbul-instrumenter-loader": "^0.2.0", "json-loader": "^0.5.4", @@ -105,7 +104,6 @@ "style-loader": "^0.13.1", "stylus": "^0.54.5", "stylus-loader": "^2.1.0", - "symlink-or-copy": "^1.0.3", "ts-loader": "^0.8.2", "tslint": "^3.15.1", "tslint-loader": "^2.1.4", diff --git a/packages/angular-cli/blueprints/class/index.js b/packages/angular-cli/blueprints/class/index.js index cfdc7f376098..47b2a75a21e2 100644 --- a/packages/angular-cli/blueprints/class/index.js +++ b/packages/angular-cli/blueprints/class/index.js @@ -1,6 +1,6 @@ const stringUtils = require('ember-cli-string-utils'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/component/index.js b/packages/angular-cli/blueprints/component/index.js index 19a9a4ed2e44..10d8fd93d55e 100644 --- a/packages/angular-cli/blueprints/component/index.js +++ b/packages/angular-cli/blueprints/component/index.js @@ -1,6 +1,6 @@ const path = require('path'); const chalk = require('chalk'); -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); const findParentModule = require('../../utilities/find-parent-module').default; const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/directive/index.js b/packages/angular-cli/blueprints/directive/index.js index ba53e7e95442..27832830555a 100644 --- a/packages/angular-cli/blueprints/directive/index.js +++ b/packages/angular-cli/blueprints/directive/index.js @@ -4,7 +4,7 @@ const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; const NodeHost = require('@angular-cli/ast-tools').NodeHost; -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/module/index.js b/packages/angular-cli/blueprints/module/index.js index 03022d434651..7c5b7cfed069 100644 --- a/packages/angular-cli/blueprints/module/index.js +++ b/packages/angular-cli/blueprints/module/index.js @@ -1,5 +1,5 @@ const path = require('path'); -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/ng2/index.js b/packages/angular-cli/blueprints/ng2/index.js index 6e5467990eb1..35680dfe6555 100644 --- a/packages/angular-cli/blueprints/ng2/index.js +++ b/packages/angular-cli/blueprints/ng2/index.js @@ -1,4 +1,4 @@ -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const path = require('path'); const stringUtils = require('ember-cli-string-utils'); const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/pipe/index.js b/packages/angular-cli/blueprints/pipe/index.js index 12f957add718..6c163daf985b 100644 --- a/packages/angular-cli/blueprints/pipe/index.js +++ b/packages/angular-cli/blueprints/pipe/index.js @@ -4,7 +4,7 @@ const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; const NodeHost = require('@angular-cli/ast-tools').NodeHost; -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/service/index.js b/packages/angular-cli/blueprints/service/index.js index e08e0e349ff3..834f2805300c 100644 --- a/packages/angular-cli/blueprints/service/index.js +++ b/packages/angular-cli/blueprints/service/index.js @@ -1,7 +1,7 @@ const path = require('path'); const chalk = require('chalk'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); -const Blueprint = require('ember-cli/lib/models/blueprint'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/commands/build.ts b/packages/angular-cli/commands/build.ts index 744b405fe567..36674a0d5831 100644 --- a/packages/angular-cli/commands/build.ts +++ b/packages/angular-cli/commands/build.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import WebpackBuild from '../tasks/build-webpack'; import WebpackBuildWatch from '../tasks/build-webpack-watch'; diff --git a/packages/angular-cli/commands/completion.ts b/packages/angular-cli/commands/completion.ts index 57e004cfbdd3..27cc430adea6 100644 --- a/packages/angular-cli/commands/completion.ts +++ b/packages/angular-cli/commands/completion.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const CompletionCommand = Command.extend({ name: 'completion', diff --git a/packages/angular-cli/commands/destroy.ts b/packages/angular-cli/commands/destroy.ts index fb1b5c30edf8..198f38d56260 100644 --- a/packages/angular-cli/commands/destroy.ts +++ b/packages/angular-cli/commands/destroy.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const SilentError = require('silent-error'); diff --git a/packages/angular-cli/commands/doc.ts b/packages/angular-cli/commands/doc.ts index f69ecec5b748..06fdae1b1f95 100644 --- a/packages/angular-cli/commands/doc.ts +++ b/packages/angular-cli/commands/doc.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import { DocTask } from '../tasks/doc'; const DocCommand = Command.extend({ diff --git a/packages/angular-cli/commands/e2e.ts b/packages/angular-cli/commands/e2e.ts index 0f423e159c24..d4d5fec7a2ee 100644 --- a/packages/angular-cli/commands/e2e.ts +++ b/packages/angular-cli/commands/e2e.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import {E2eTask} from '../tasks/e2e'; import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/easter-egg.ts b/packages/angular-cli/commands/easter-egg.ts index 4aa1a01ae827..7d5921da3070 100644 --- a/packages/angular-cli/commands/easter-egg.ts +++ b/packages/angular-cli/commands/easter-egg.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const stringUtils = require('ember-cli-string-utils'); import * as chalk from 'chalk'; diff --git a/packages/angular-cli/commands/generate.ts b/packages/angular-cli/commands/generate.ts index 6392ce89c3f7..7dd55cc40432 100644 --- a/packages/angular-cli/commands/generate.ts +++ b/packages/angular-cli/commands/generate.ts @@ -3,8 +3,8 @@ import * as path from 'path'; import * as os from 'os'; const chalk = require('chalk'); -const EmberGenerateCommand = require('ember-cli/lib/commands/generate'); -const Blueprint = require('ember-cli/lib/models/blueprint'); +const EmberGenerateCommand = require('@angular-cli/ember-cli/lib/commands/generate'); +const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); const SilentError = require('silent-error'); diff --git a/packages/angular-cli/commands/get.ts b/packages/angular-cli/commands/get.ts index 9b605b4d6028..0626913f7925 100644 --- a/packages/angular-cli/commands/get.ts +++ b/packages/angular-cli/commands/get.ts @@ -1,7 +1,7 @@ import * as chalk from 'chalk'; import {CliConfig} from '../models/config'; -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const GetCommand = Command.extend({ name: 'get', diff --git a/packages/angular-cli/commands/github-pages-deploy.ts b/packages/angular-cli/commands/github-pages-deploy.ts index 631c882b3949..d50f3f2c238c 100644 --- a/packages/angular-cli/commands/github-pages-deploy.ts +++ b/packages/angular-cli/commands/github-pages-deploy.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const SilentError = require('silent-error'); import denodeify = require('denodeify'); diff --git a/packages/angular-cli/commands/help.ts b/packages/angular-cli/commands/help.ts index 7dd1412c295f..134a576c0e04 100644 --- a/packages/angular-cli/commands/help.ts +++ b/packages/angular-cli/commands/help.ts @@ -1,9 +1,9 @@ import * as fs from 'fs'; import * as path from 'path'; -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const stringUtils = require('ember-cli-string-utils'); -const lookupCommand = require('ember-cli/lib/cli/lookup-command'); +const lookupCommand = require('@angular-cli/ember-cli/lib/cli/lookup-command'); const commandsToIgnore = [ 'easter-egg', diff --git a/packages/angular-cli/commands/init.ts b/packages/angular-cli/commands/init.ts index ebd5e6e4c54f..c520fdbba461 100644 --- a/packages/angular-cli/commands/init.ts +++ b/packages/angular-cli/commands/init.ts @@ -1,11 +1,12 @@ import LinkCli from '../tasks/link-cli'; import NpmInstall from '../tasks/npm-install'; -const Command = require('ember-cli/lib/models/command'); -const Promise = require('ember-cli/lib/ext/promise'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Promise = require('@angular-cli/ember-cli/lib/ext/promise'); const SilentError = require('silent-error'); -const validProjectName = require('ember-cli/lib/utilities/valid-project-name'); -const normalizeBlueprint = require('ember-cli/lib/utilities/normalize-blueprint-option'); +const validProjectName = require('@angular-cli/ember-cli/lib/utilities/valid-project-name'); +const normalizeBlueprint = require( + '@angular-cli/ember-cli/lib/utilities/normalize-blueprint-option'); const GitInit = require('../tasks/git-init'); diff --git a/packages/angular-cli/commands/lint.ts b/packages/angular-cli/commands/lint.ts index 18e313c251d3..ff8cc3fd323e 100644 --- a/packages/angular-cli/commands/lint.ts +++ b/packages/angular-cli/commands/lint.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import LintTask from '../tasks/lint'; export default Command.extend({ diff --git a/packages/angular-cli/commands/new.ts b/packages/angular-cli/commands/new.ts index 5737c0afaee8..ce1cd844c806 100644 --- a/packages/angular-cli/commands/new.ts +++ b/packages/angular-cli/commands/new.ts @@ -1,10 +1,10 @@ import * as chalk from 'chalk'; import InitCommand from './init'; -const Command = require('ember-cli/lib/models/command'); -const Project = require('ember-cli/lib/models/project'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Project = require('@angular-cli/ember-cli/lib/models/project'); const SilentError = require('silent-error'); -const validProjectName = require('ember-cli/lib/utilities/valid-project-name'); +const validProjectName = require('@angular-cli/ember-cli/lib/utilities/valid-project-name'); const NewCommand = Command.extend({ diff --git a/packages/angular-cli/commands/serve.ts b/packages/angular-cli/commands/serve.ts index 7c16c49993b8..9ab7853d0806 100644 --- a/packages/angular-cli/commands/serve.ts +++ b/packages/angular-cli/commands/serve.ts @@ -1,6 +1,6 @@ import * as assign from 'lodash/assign'; import * as denodeify from 'denodeify'; -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); const SilentError = require('silent-error'); const PortFinder = require('portfinder'); import ServeWebpackTask from '../tasks/serve-webpack'; @@ -157,5 +157,4 @@ const ServeCommand = Command.extend({ } }); -ServeCommand.overrideCore = true; export default ServeCommand; diff --git a/packages/angular-cli/commands/set.ts b/packages/angular-cli/commands/set.ts index a1c2733cca03..7bca42730592 100644 --- a/packages/angular-cli/commands/set.ts +++ b/packages/angular-cli/commands/set.ts @@ -1,5 +1,5 @@ const SilentError = require('silent-error'); -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/test.ts b/packages/angular-cli/commands/test.ts index 55a1e3b8b7a8..ba82276b5908 100644 --- a/packages/angular-cli/commands/test.ts +++ b/packages/angular-cli/commands/test.ts @@ -1,4 +1,4 @@ -const TestCommand = require('ember-cli/lib/commands/test'); +const TestCommand = require('@angular-cli/ember-cli/lib/commands/test'); import TestTask from '../tasks/test'; import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/version.ts b/packages/angular-cli/commands/version.ts index 8dc5e5883253..29c8fd8d1bec 100644 --- a/packages/angular-cli/commands/version.ts +++ b/packages/angular-cli/commands/version.ts @@ -1,4 +1,4 @@ -const Command = require('ember-cli/lib/models/command'); +const Command = require('@angular-cli/ember-cli/lib/models/command'); import * as path from 'path'; import * as child_process from 'child_process'; diff --git a/packages/angular-cli/lib/cli/index.js b/packages/angular-cli/lib/cli/index.js index aa24ec8e5c78..8e7082978b7a 100644 --- a/packages/angular-cli/lib/cli/index.js +++ b/packages/angular-cli/lib/cli/index.js @@ -1,9 +1,9 @@ /*eslint-disable no-console */ // This file hooks up on require calls to transpile TypeScript. -const cli = require('ember-cli/lib/cli'); -const UI = require('ember-cli/lib/ui'); -const Watcher = require('ember-cli/lib/models/watcher'); +const cli = require('@angular-cli/ember-cli/lib/cli'); +const UI = require('@angular-cli/ember-cli/lib/ui'); +const Watcher = require('@angular-cli/ember-cli/lib/models/watcher'); const path = require('path'); Error.stackTraceLimit = Infinity; diff --git a/packages/angular-cli/package.json b/packages/angular-cli/package.json index 5a24f0bea295..6db5ec962d60 100644 --- a/packages/angular-cli/package.json +++ b/packages/angular-cli/package.json @@ -27,6 +27,7 @@ "dependencies": { "@angular-cli/ast-tools": "^1.0.1", "@angular-cli/base-href-webpack": "^1.0.0", + "@angular-cli/ember-cli": "^1.0.0", "@angular/common": "~2.1.0", "@angular/compiler": "~2.1.0", "@angular/compiler-cli": "~2.1.0", @@ -43,7 +44,6 @@ "core-js": "^2.4.0", "css-loader": "^0.23.1", "denodeify": "^1.2.1", - "ember-cli": "2.5.0", "ember-cli-string-utils": "^1.0.0", "enhanced-resolve": "^2.2.2", "exit": "^0.1.2", @@ -54,7 +54,6 @@ "fs-extra": "^0.30.0", "fs.realpath": "^1.0.0", "glob": "^7.0.3", - "handlebars": "^4.0.5", "html-webpack-plugin": "^2.19.0", "istanbul-instrumenter-loader": "^0.2.0", "json-loader": "^0.5.4", @@ -87,7 +86,6 @@ "style-loader": "^0.13.1", "stylus": "^0.54.5", "stylus-loader": "^2.1.0", - "symlink-or-copy": "^1.0.3", "ts-loader": "^0.8.2", "tslint": "^3.15.1", "tslint-loader": "^2.1.4", diff --git a/packages/angular-cli/tasks/build-webpack-watch.ts b/packages/angular-cli/tasks/build-webpack-watch.ts index 700c977298e4..9b8b8be50537 100644 --- a/packages/angular-cli/tasks/build-webpack-watch.ts +++ b/packages/angular-cli/tasks/build-webpack-watch.ts @@ -1,6 +1,6 @@ import * as rimraf from 'rimraf'; import * as path from 'path'; -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as webpack from 'webpack'; const ProgressPlugin = require('webpack/lib/ProgressPlugin'); import { NgCliWebpackConfig } from '../models/webpack-config'; diff --git a/packages/angular-cli/tasks/build-webpack.ts b/packages/angular-cli/tasks/build-webpack.ts index 48c27c8f1b3c..fba722378042 100644 --- a/packages/angular-cli/tasks/build-webpack.ts +++ b/packages/angular-cli/tasks/build-webpack.ts @@ -1,6 +1,6 @@ import * as rimraf from 'rimraf'; import * as path from 'path'; -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as webpack from 'webpack'; import { BuildOptions } from '../commands/build'; import { NgCliWebpackConfig } from '../models/webpack-config'; diff --git a/packages/angular-cli/tasks/create-github-repo.ts b/packages/angular-cli/tasks/create-github-repo.ts index ecf008bf4373..0a3d9b9255fe 100644 --- a/packages/angular-cli/tasks/create-github-repo.ts +++ b/packages/angular-cli/tasks/create-github-repo.ts @@ -1,5 +1,5 @@ import * as denodeify from 'denodeify'; -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); const SilentError = require('silent-error'); import { exec } from 'child_process'; import * as https from 'https'; diff --git a/packages/angular-cli/tasks/doc.ts b/packages/angular-cli/tasks/doc.ts index 05b8b2cb4183..d400d91d01b9 100644 --- a/packages/angular-cli/tasks/doc.ts +++ b/packages/angular-cli/tasks/doc.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); const opn = require('opn'); export const DocTask: any = Task.extend({ diff --git a/packages/angular-cli/tasks/e2e.ts b/packages/angular-cli/tasks/e2e.ts index 778856424d7f..afee9c5abda6 100644 --- a/packages/angular-cli/tasks/e2e.ts +++ b/packages/angular-cli/tasks/e2e.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/git-init.js b/packages/angular-cli/tasks/git-init.js index afb53a630bd7..5d58640224b3 100644 --- a/packages/angular-cli/tasks/git-init.js +++ b/packages/angular-cli/tasks/git-init.js @@ -1,12 +1,12 @@ 'use strict'; -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var exec = Promise.denodeify(require('child_process').exec); var path = require('path'); var pkg = require('../package.json'); var fs = require('fs'); var template = require('lodash/template'); -var Task = require('ember-cli/lib/models/task'); +var Task = require('@angular-cli/ember-cli/lib/models/task'); var gitEnvironmentVariables = { GIT_AUTHOR_NAME: 'angular-cli', diff --git a/packages/angular-cli/tasks/link-cli.ts b/packages/angular-cli/tasks/link-cli.ts index bddf702fc965..d6a8c390365a 100644 --- a/packages/angular-cli/tasks/link-cli.ts +++ b/packages/angular-cli/tasks/link-cli.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/lint.ts b/packages/angular-cli/tasks/lint.ts index 0277bb20b404..0cf1bafc9a2f 100644 --- a/packages/angular-cli/tasks/lint.ts +++ b/packages/angular-cli/tasks/lint.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/npm-install.ts b/packages/angular-cli/tasks/npm-install.ts index abf491061847..57c17c053c94 100644 --- a/packages/angular-cli/tasks/npm-install.ts +++ b/packages/angular-cli/tasks/npm-install.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/serve-webpack.ts b/packages/angular-cli/tasks/serve-webpack.ts index 585af628b829..177e88eca36a 100644 --- a/packages/angular-cli/tasks/serve-webpack.ts +++ b/packages/angular-cli/tasks/serve-webpack.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as chalk from 'chalk'; const SilentError = require('silent-error'); -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as webpack from 'webpack'; const WebpackDevServer = require('webpack-dev-server'); const ProgressPlugin = require('webpack/lib/ProgressPlugin'); diff --git a/packages/angular-cli/tasks/test.ts b/packages/angular-cli/tasks/test.ts index e539c075199a..df3de3147c72 100644 --- a/packages/angular-cli/tasks/test.ts +++ b/packages/angular-cli/tasks/test.ts @@ -1,4 +1,4 @@ -const Task = require('ember-cli/lib/models/task'); +const Task = require('@angular-cli/ember-cli/lib/models/task'); import * as path from 'path'; // require dependencies within the target project diff --git a/packages/ast-tools/src/change.spec.ts b/packages/ast-tools/src/change.spec.ts index 0bebb3230169..28d25e204051 100644 --- a/packages/ast-tools/src/change.spec.ts +++ b/packages/ast-tools/src/change.spec.ts @@ -8,7 +8,7 @@ import {InsertChange, NodeHost, RemoveChange, ReplaceChange} from './change'; import fs = require('fs'); let path = require('path'); -let Promise = require('ember-cli/lib/ext/promise'); +let Promise = require('@angular-cli/ember-cli/lib/ext/promise'); const readFile = Promise.denodeify(fs.readFile); diff --git a/packages/ember-cli/LICENSE.md b/packages/ember-cli/LICENSE.md new file mode 100644 index 000000000000..3a86b810c14a --- /dev/null +++ b/packages/ember-cli/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 Stefan Penner, Robert Jackson and ember-cli contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/ember-cli/bin/ember b/packages/ember-cli/bin/ember new file mode 100755 index 000000000000..7ccd04fde179 --- /dev/null +++ b/packages/ember-cli/bin/ember @@ -0,0 +1,35 @@ +#!/usr/bin/env node +'use strict'; + +// Provide a title to the process in `ps` +process.title = 'ember'; + +var resolve = require('resolve'); +var exit = require('exit'); + +resolve('ember-cli', { + basedir: process.cwd() +}, function(error, projectLocalCli) { + var cli; + if (error) { + // If there is an error, resolve could not find the ember-cli + // library from a package.json. Instead, include it from a relative + // path to this script file (which is likely a globally installed + // npm package). Most common cause for hitting this is `ember new` + cli = require('../lib/cli'); + } else { + // No error implies a projectLocalCli, which will load whatever + // version of ember-cli you have installed in a local package.json + cli = require(projectLocalCli); + } + + cli({ + cliArgs: process.argv.slice(2), + inputStream: process.stdin, + outputStream: process.stdout, + errorStream: process.stderr + }).then(function(result) { + var exitCode = typeof result === 'object' ? result.exitCode : result; + exit(exitCode); + }); +}); diff --git a/packages/ember-cli/lib/cli/cli.js b/packages/ember-cli/lib/cli/cli.js new file mode 100644 index 000000000000..4eb143364666 --- /dev/null +++ b/packages/ember-cli/lib/cli/cli.js @@ -0,0 +1,165 @@ +'use strict'; + +var lookupCommand = require('./lookup-command'); +var Promise = require('../ext/promise'); +var UpdateChecker = require('../models/update-checker'); +var getOptionArgs = require('../utilities/get-option-args'); +var debug = require('debug')('ember-cli:cli'); +var debugTesting = require('debug')('ember-cli:testing'); +var PlatformChecker = require('../utilities/platform-checker'); +var InstallationChecker = require('../models/installation-checker'); + +function CLI(options) { + this.name = options.name; + this.ui = options.ui; + this.analytics = options.analytics; + this.testing = options.testing; + this.disableDependencyChecker = options.disableDependencyChecker; + this.root = options.root; + this.npmPackage = options.npmPackage; + + debug('testing %o', !!this.testing); +} + +module.exports = CLI; + +CLI.prototype.run = function(environment) { + return Promise.hash(environment).then(function(environment) { + var args = environment.cliArgs.slice(); + var commandName = args.shift(); + var commandArgs = args; + var helpOptions; + var update; + + var CurrentCommand = lookupCommand(environment.commands, commandName, commandArgs, { + project: environment.project, + ui: this.ui + }); + + var command = new CurrentCommand({ + ui: this.ui, + analytics: this.analytics, + commands: environment.commands, + tasks: environment.tasks, + project: environment.project, + settings: environment.settings, + testing: this.testing, + cli: this + }); + + getOptionArgs('--verbose', commandArgs).forEach(function(arg) { + process.env['EMBER_VERBOSE_' + arg.toUpperCase()] = 'true'; + }); + + var platform = new PlatformChecker(process.version); + if (!platform.isValid && !this.testing) { + if (platform.isDeprecated) { + this.ui.writeDeprecateLine('Node ' + process.version + + ' is no longer supported by Ember CLI. Please update to a more recent version of Node'); + } + + if (platform.isUntested) { + this.ui.writeWarnLine('WARNING: Node ' + process.version + + ' has currently not been tested against Ember CLI and may result in unexpected behaviour.'); + } + } + + debug('command: %s', commandName); + + if (commandName !== 'update' && !this.testing) { + var a = new UpdateChecker(this.ui, environment.settings); + update = a.checkForUpdates(); + } + + if (!this.testing) { + process.chdir(environment.project.root); + var skipInstallationCheck = commandArgs.indexOf('--skip-installation-check') !== -1; + if (environment.project.isEmberCLIProject() && !skipInstallationCheck) { + new InstallationChecker({ project: environment.project }).checkInstallations(); + } + } + + command.beforeRun(commandArgs); + + return Promise.resolve(update).then(function() { + debugTesting('cli: command.validateAndRun'); + return command.validateAndRun(commandArgs); + }).then(function(result) { + // if the help option was passed, call the help command + if (result === 'callHelp') { + helpOptions = { + environment: environment, + commandName: commandName, + commandArgs: commandArgs + }; + + return this.callHelp(helpOptions); + } + + return result; + }.bind(this)).then(function(exitCode) { + debugTesting('cli: command run complete. exitCode: ' + exitCode); + // TODO: fix this + // Possibly this issue: https://github.com/joyent/node/issues/8329 + // Wait to resolve promise when running on windows. + // This ensures that stdout is flushed so acceptance tests get full output + + return new Promise(function(resolve) { + if (process.platform === 'win32') { + setTimeout(resolve, 250, exitCode); + } else { + resolve(exitCode); + } + }); + }.bind(this)); + + }.bind(this)).catch(this.logError.bind(this)); +}; + +CLI.prototype.callHelp = function(options) { + var environment = options.environment; + var commandName = options.commandName; + var commandArgs = options.commandArgs; + var helpIndex = commandArgs.indexOf('--help'); + var hIndex = commandArgs.indexOf('-h'); + + var HelpCommand = lookupCommand(environment.commands, 'help', commandArgs, { + project: environment.project, + ui: this.ui + }); + + var help = new HelpCommand({ + ui: this.ui, + analytics: this.analytics, + commands: environment.commands, + tasks: environment.tasks, + project: environment.project, + settings: environment.settings, + testing: this.testing + }); + + if (helpIndex > -1) { + commandArgs.splice(helpIndex,1); + } + + if (hIndex > -1) { + commandArgs.splice(hIndex,1); + } + + commandArgs.unshift(commandName); + + return help.validateAndRun(commandArgs); +}; + +CLI.prototype.logError = function(error) { + if (this.testing && error) { + console.error(error.message); + if (error.stack) { + console.error(error.stack); + } + throw error; + } + this.ui.errorLog.push(error); + this.ui.writeError(error); + return 1; +}; diff --git a/packages/ember-cli/lib/cli/index.js b/packages/ember-cli/lib/cli/index.js new file mode 100644 index 000000000000..1a4168965b8c --- /dev/null +++ b/packages/ember-cli/lib/cli/index.js @@ -0,0 +1,105 @@ +'use strict'; + +// Main entry point +var Project = require('../models/project'); +var requireAsHash = require('../utilities/require-as-hash'); +var Command = require('../models/command'); +var commands = requireAsHash('../commands/*.js', Command); +var Task = require('../models/task'); +var tasks = requireAsHash('../tasks/*.js', Task); +var CLI = require('./cli'); +var packageConfig = require('../../package.json'); +var debug = require('debug')('ember-cli:cli/index'); +var merge = require('lodash/merge'); +var path = require('path'); + +var version = packageConfig.version; +var name = packageConfig.name; +var trackingCode = packageConfig.trackingCode; + +function clientId() { + var ConfigStore = require('configstore'); + var configStore = new ConfigStore('ember-cli'); + var id = configStore.get('client-id'); + + if (id) { + return id; + } else { + id = require('node-uuid').v4().toString(); + configStore.set('client-id', id); + return id; + } +} + +// Options: Array cliArgs, Stream inputStream, Stream outputStream +module.exports = function(options) { + var UI = options.UI || require('../ui'); + var Leek = options.Leek || require('leek'); + var Yam = options.Yam || require('yam'); + + // TODO: one UI (lib/models/project.js also has one for now...) + var ui = new UI({ + inputStream: options.inputStream, + outputStream: options.outputStream, + errorStream: options.errorStream || process.stderr, + errorLog: options.errorLog || [], + ci: process.env.CI || /^(dumb|emacs)$/.test(process.env.TERM), + writeLevel: ~process.argv.indexOf('--silent') ? 'ERROR' : undefined + }); + + var config = new Yam('ember-cli', { + primary: Project.getProjectRoot() + }); + + var leekOptions; + + var disableAnalytics = options.cliArgs && + (options.cliArgs.indexOf('--disable-analytics') > -1 || + options.cliArgs.indexOf('-v') > -1 || + options.cliArgs.indexOf('--version') > -1) || + config.get('disableAnalytics'); + + var defaultLeekOptions = { + trackingCode: trackingCode, + globalName: name, + name: clientId(), + version: version, + silent: disableAnalytics + }; + + var defaultUpdateCheckerOptions = { + checkForUpdates: false + }; + + if (config.get('leekOptions')) { + leekOptions = merge(defaultLeekOptions, config.get('leekOptions')); + } else { + leekOptions = defaultLeekOptions; + } + + debug('leek: %o', leekOptions); + + var leek = new Leek(leekOptions); + + var cli = new CLI({ + ui: ui, + analytics: leek, + testing: options.testing, + name: options.cli ? options.cli.name : 'ember', + disableDependencyChecker: options.disableDependencyChecker, + root: options.cli ? options.cli.root : path.resolve(__dirname, '..', '..'), + npmPackage: options.cli ? options.cli.npmPackage : 'ember-cli' + }); + + var project = Project.projectOrnullProject(ui, cli); + + var environment = { + tasks: tasks, + cliArgs: options.cliArgs, + commands: commands, + project: project, + settings: merge(defaultUpdateCheckerOptions, config.getAll()) + }; + + return cli.run(environment); +}; diff --git a/packages/ember-cli/lib/cli/lookup-command.js b/packages/ember-cli/lib/cli/lookup-command.js new file mode 100644 index 000000000000..fba6b9369a7f --- /dev/null +++ b/packages/ember-cli/lib/cli/lookup-command.js @@ -0,0 +1,64 @@ +'use strict'; + +var UnknownCommand = require('../commands/unknown'); + +module.exports = function(commands, commandName, commandArgs, optionHash) { + var options = optionHash || {}; + var project = options.project; + var ui = options.ui; + + function aliasMatches(alias) { + return alias === commandName; + } + + function findCommand(commands, commandName) { + for (var key in commands) { + var command = commands[key]; + + var name = command.prototype.name; + var aliases = command.prototype.aliases || []; + + if (name === commandName || aliases.some(aliasMatches)) { + return command; + } + } + } + + // Attempt to find command in ember-cli core commands + var command = findCommand(commands, commandName); + + var addonCommand; + // Attempt to find command within addons + if (project && project.eachAddonCommand) { + project.eachAddonCommand(function(addonName, commands) { + addonCommand = findCommand(commands, commandName); + return !addonCommand; + }); + } + + if (command && addonCommand) { + if (addonCommand.overrideCore) { + ui.writeWarnLine('An ember-addon has attempted to override the core command "' + + command.prototype.name + '". The addon command will be used as the overridding was explicit.'); + + return addonCommand; + } + + ui.writeWarnLine('An ember-addon has attempted to override the core command "' + + command.prototype.name + '". The core command will be used.'); + return command; + } + + if (command) { + return command; + } + + if (addonCommand) { + return addonCommand; + } + + // if we didn't find anything, return an "UnknownCommand" + return UnknownCommand.extend({ + name: commandName + }); +}; diff --git a/packages/ember-cli/lib/commands/addon.js b/packages/ember-cli/lib/commands/addon.js new file mode 100644 index 000000000000..d52ba17073b0 --- /dev/null +++ b/packages/ember-cli/lib/commands/addon.js @@ -0,0 +1,22 @@ +'use strict'; + +var NewCommand = require('./new'); + +module.exports = NewCommand.extend({ + name: 'addon', + description: 'Generates a new folder structure for building an addon, complete with test harness.', + + availableOptions: [ + { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'blueprint', type: String, default: 'addon', aliases: ['b'] }, + { name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] }, + { name: 'skip-bower', type: Boolean, default: false, aliases: ['sb'] }, + { name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] }, + { name: 'directory', type: String , aliases: ['dir'] } + ], + + anonymousOptions: [ + '' + ] +}); diff --git a/packages/ember-cli/lib/commands/asset-sizes.js b/packages/ember-cli/lib/commands/asset-sizes.js new file mode 100644 index 000000000000..93641c320961 --- /dev/null +++ b/packages/ember-cli/lib/commands/asset-sizes.js @@ -0,0 +1,19 @@ +'use strict'; + +var Command = require('../models/command'); + +module.exports = Command.extend({ + name: 'asset-sizes', + description: 'Shows the sizes of your asset files.', + + availableOptions: [ + { name: 'output-path', type: 'Path', default: 'dist/', aliases: ['o'] }, + ], + + run: function(commandOptions) { + var task = new this.tasks.ShowAssetSizes({ + ui: this.ui + }); + return task.run(commandOptions); + } +}); diff --git a/packages/ember-cli/lib/commands/build.js b/packages/ember-cli/lib/commands/build.js new file mode 100644 index 000000000000..2d4a12b14477 --- /dev/null +++ b/packages/ember-cli/lib/commands/build.js @@ -0,0 +1,50 @@ +'use strict'; + +var Command = require('../models/command'); +var win = require('../utilities/windows-admin'); + +module.exports = Command.extend({ + name: 'build', + description: 'Builds your app and places it into the output path (dist/ by default).', + aliases: ['b'], + + availableOptions: [ + { name: 'environment', type: String, default: 'development', aliases: ['e', { 'dev': 'development' }, { 'prod': 'production' }] }, + { name: 'output-path', type: 'Path', default: 'dist/', aliases: ['o'] }, + { name: 'watch', type: Boolean, default: false, aliases: ['w'] }, + { name: 'watcher', type: String }, + { name: 'suppress-sizes', type: Boolean, default: false } + ], + + run: function(commandOptions) { + var BuildTask = this.taskFor(commandOptions); + var buildTask = new BuildTask({ + ui: this.ui, + analytics: this.analytics, + project: this.project + }); + var ShowAssetSizesTask = this.tasks.ShowAssetSizes; + var showTask = new ShowAssetSizesTask({ + ui: this.ui + }); + + return win.checkWindowsElevation(this.ui).then(function () { + return buildTask.run(commandOptions) + .then(function () { + if (!commandOptions.suppressSizes && commandOptions.environment === 'production') { + return showTask.run({ + outputPath: commandOptions.outputPath + }); + } + }); + }); + }, + + taskFor: function(options) { + if (options.watch) { + return this.tasks.BuildWatch; + } else { + return this.tasks.Build; + } + } +}); diff --git a/packages/ember-cli/lib/commands/destroy.js b/packages/ember-cli/lib/commands/destroy.js new file mode 100644 index 000000000000..b87c1fa545e5 --- /dev/null +++ b/packages/ember-cli/lib/commands/destroy.js @@ -0,0 +1,77 @@ +'use strict'; + +var Command = require('../models/command'); +var Promise = require('../ext/promise'); +var mergeBlueprintOptions = require('../utilities/merge-blueprint-options'); +var merge = require('lodash/merge'); +var SilentError = require('silent-error'); + +module.exports = Command.extend({ + name: 'destroy', + description: 'Destroys code generated by `generate` command.', + aliases: ['d'], + works: 'insideProject', + + availableOptions: [ + { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'pod', type: Boolean, default: false, aliases: ['p'] }, + { name: 'classic', type: Boolean, default: false, aliases: ['c'] }, + { name: 'dummy', type: Boolean, default: false, aliases: ['dum', 'id'] }, + { name: 'in-repo-addon', type: String, default: null, aliases: ['in-repo', 'ir'] } + ], + + anonymousOptions: [ + '' + ], + + beforeRun: mergeBlueprintOptions, + + run: function(commandOptions, rawArgs) { + var blueprintName = rawArgs[0]; + var entityName = rawArgs[1]; + + if (!blueprintName) { + return Promise.reject(new SilentError('The `ember destroy` command requires a ' + + 'blueprint name to be specified. ' + + 'For more details, use `ember help`.')); + } + + if (!entityName) { + return Promise.reject(new SilentError('The `ember destroy` command requires an ' + + 'entity name to be specified. ' + + 'For more details, use `ember help`.')); + } + + var Task = this.tasks.DestroyFromBlueprint; + var task = new Task({ + ui: this.ui, + analytics: this.analytics, + project: this.project, + settings: this.settings + }); + + var taskArgs = { + args: rawArgs + }; + + if (this.settings && this.settings.usePods && !commandOptions.classic) { + commandOptions.pod = !commandOptions.pod; + } + + var taskOptions = merge(taskArgs, commandOptions || {}); + + if (this.project.initializeAddons) { + this.project.initializeAddons(); + } + + return task.run(taskOptions); + }, + + printDetailedHelp: function() { + var ui = this.ui; + + ui.writeLine(''); + ui.writeLine(' Run `ember help generate` to view a list of available blueprints.'); + } +}); diff --git a/packages/ember-cli/lib/commands/generate.js b/packages/ember-cli/lib/commands/generate.js new file mode 100644 index 000000000000..cfb67b535065 --- /dev/null +++ b/packages/ember-cli/lib/commands/generate.js @@ -0,0 +1,155 @@ +'use strict'; + +var chalk = require('chalk'); +var Command = require('../models/command'); +var Promise = require('../ext/promise'); +var Blueprint = require('../models/blueprint'); +var mergeBlueprintOptions = require('../utilities/merge-blueprint-options'); +var merge = require('lodash/merge'); +var reject = require('lodash/reject'); +var EOL = require('os').EOL; +var SilentError = require('silent-error'); + +module.exports = Command.extend({ + name: 'generate', + description: 'Generates new code from blueprints.', + aliases: ['g'], + works: 'insideProject', + + availableOptions: [ + { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'pod', type: Boolean, default: false, aliases: ['p'] }, + { name: 'classic', type: Boolean, default: false, aliases: ['c'] }, + { name: 'dummy', type: Boolean, default: false, aliases: ['dum', 'id'] }, + { name: 'in-repo-addon', type: String, default: null, aliases: ['in-repo', 'ir'] } + ], + + anonymousOptions: [ + '' + ], + + beforeRun: mergeBlueprintOptions, + + run: function(commandOptions, rawArgs) { + var blueprintName = rawArgs[0]; + + if (!blueprintName) { + return Promise.reject(new SilentError('The `ember generate` command requires a ' + + 'blueprint name to be specified. ' + + 'For more details, use `ember help`.')); + } + var Task = this.tasks.GenerateFromBlueprint; + var task = new Task({ + ui: this.ui, + analytics: this.analytics, + project: this.project, + testing: this.testing, + settings: this.settings + }); + + var taskArgs = { + args: rawArgs + }; + + if (this.settings && this.settings.usePods && !commandOptions.classic) { + commandOptions.pod = !commandOptions.pod; + } + + var taskOptions = merge(taskArgs, commandOptions || {}); + + if (this.project.initializeAddons) { + this.project.initializeAddons(); + } + + return task.run(taskOptions); + }, + + printDetailedHelp: function(options) { + this.ui.writeLine(this.getAllBlueprints(options)); + }, + + addAdditionalJsonForHelp: function(json, options) { + json.availableBlueprints = this.getAllBlueprints(options); + }, + + getAllBlueprints: function(options) { + var lookupPaths = this.project.blueprintLookupPaths(); + var blueprintList = Blueprint.list({ paths: lookupPaths }); + + var output = ''; + + var singleBlueprintName; + if (options.rawArgs) { + singleBlueprintName = options.rawArgs[0]; + } + + if (!singleBlueprintName && !options.json) { + output += EOL + ' Available blueprints:' + EOL; + } + + var collectionsJson = []; + + blueprintList.forEach(function(collection) { + var result = this.getPackageBlueprints(collection, options, singleBlueprintName); + if (options.json) { + var collectionJson = {}; + collectionJson[collection.source] = result; + collectionsJson.push(collectionJson); + } else { + output += result; + } + }, this); + + if (singleBlueprintName && !output && !options.json) { + output = chalk.yellow('The \'' + singleBlueprintName + + '\' blueprint does not exist in this project.') + EOL; + } + + if (options.json) { + return collectionsJson; + } else { + return output; + } + }, + + getPackageBlueprints: function(collection, options, singleBlueprintName) { + var verbose = options.verbose; + var blueprints = collection.blueprints; + + if (!verbose) { + blueprints = reject(blueprints, 'overridden'); + } + + var output = ''; + + if (blueprints.length && !singleBlueprintName && !options.json) { + output += ' ' + collection.source + ':' + EOL; + } + + var blueprintsJson = []; + + blueprints.forEach(function(blueprint) { + var singleMatch = singleBlueprintName === blueprint.name; + if (singleMatch) { + verbose = true; + } + if (!singleBlueprintName || singleMatch) { + // this may add default keys for printing + blueprint.availableOptions.forEach(this.normalizeOption); + + if (options.json) { + blueprintsJson.push(blueprint.getJson(verbose)); + } else { + output += blueprint.printBasicHelp(verbose) + EOL; + } + } + }, this); + + if (options.json) { + return blueprintsJson; + } else { + return output; + } + } +}); diff --git a/packages/ember-cli/lib/commands/help.js b/packages/ember-cli/lib/commands/help.js new file mode 100644 index 000000000000..c8e57b5e1023 --- /dev/null +++ b/packages/ember-cli/lib/commands/help.js @@ -0,0 +1,132 @@ +'use strict'; + +var Command = require('../models/command'); +var lookupCommand = require('../cli/lookup-command'); +var stringUtils = require('ember-cli-string-utils'); +var assign = require('lodash/assign'); +var GenerateCommand = require('./generate'); +var RootCommand = require('../utilities/root-command'); +var JsonGenerator = require('../utilities/json-generator'); + +module.exports = Command.extend({ + name: 'help', + description: 'Outputs the usage instructions for all commands or the provided command', + aliases: [undefined, 'h', '--help', '-h'], + works: 'everywhere', + + availableOptions: [ + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'json', type: Boolean, default: false } + ], + + anonymousOptions: [ + '' + ], + + run: function(commandOptions, rawArgs) { + if (commandOptions.json) { + this._printJsonHelp(commandOptions, rawArgs); + } else { + this._printHelp(commandOptions, rawArgs); + } + }, + + _printHelp: function(commandOptions, rawArgs) { + var rootCommand = new RootCommand({ + ui: this.ui, + project: this.project, + commands: this.commands, + tasks: this.tasks + }); + + if (rawArgs.length === 0) { + this.ui.writeLine(rootCommand.printBasicHelp(commandOptions)); + // Display usage for all commands. + this.ui.writeLine('Available commands in ember-cli:'); + this.ui.writeLine(''); + + Object.keys(this.commands).forEach(function(commandName) { + this._printHelpForCommand(commandName, false, commandOptions); + }, this); + + if (this.project.eachAddonCommand) { + this.project.eachAddonCommand(function(addonName, commands) { + this.commands = commands; + + this.ui.writeLine(''); + this.ui.writeLine('Available commands from ' + addonName + ':'); + + Object.keys(this.commands).forEach(function(commandName) { + this._printHelpForCommand(commandName, false, commandOptions); + }, this); + }.bind(this)); + } + } else { + // If args were passed to the help command, + // attempt to look up the command for each of them. + + this.ui.writeLine('Requested ember-cli commands:'); + this.ui.writeLine(''); + + if (this.project.eachAddonCommand) { + this.project.eachAddonCommand(function(addonName, commands) { + assign(this.commands, commands); + }.bind(this)); + } + + var multipleCommands = [GenerateCommand.prototype.name].concat(GenerateCommand.prototype.aliases); + if (multipleCommands.indexOf(rawArgs[0]) > -1) { + var command = rawArgs.shift(); + if (rawArgs.length > 0) { + commandOptions.rawArgs = rawArgs; + } + rawArgs = [command]; + } + + // Iterate through each arg beyond the initial 'help' command, + // and try to display usage instructions. + rawArgs.forEach(function(commandName) { + this._printHelpForCommand(commandName, true, commandOptions); + }, this); + } + }, + + _printJsonHelp: function(commandOptions, rawArgs) { + var generator = new JsonGenerator({ + ui: this.ui, + project: this.project, + commands: this.commands, + tasks: this.tasks + }); + + var json = generator.generate(commandOptions, rawArgs); + + var outputJsonString = JSON.stringify(json, null, 2); + + this.ui.writeLine(outputJsonString); + }, + + _printHelpForCommand: function(commandName, detailed, options) { + var command = this._lookupCommand(commandName); + + if (!command.skipHelp || detailed) { + this.ui.writeLine(command.printBasicHelp(options)); + } + + if (detailed) { + command.printDetailedHelp(options); + } + }, + + _lookupCommand: function(commandName) { + var Command = this.commands[stringUtils.classify(commandName)] || + lookupCommand(this.commands, commandName); + + return new Command({ + ui: this.ui, + project: this.project, + commands: this.commands, + tasks: this.tasks + }); + } +}); diff --git a/packages/ember-cli/lib/commands/init.js b/packages/ember-cli/lib/commands/init.js new file mode 100644 index 000000000000..5fc4dac2fadf --- /dev/null +++ b/packages/ember-cli/lib/commands/init.js @@ -0,0 +1,125 @@ +'use strict'; + +var clone = require('lodash/clone'); +var merge = require('lodash/merge'); +var Command = require('../models/command'); +var Promise = require('../ext/promise'); +var SilentError = require('silent-error'); +var validProjectName = require('../utilities/valid-project-name'); +var normalizeBlueprint = require('../utilities/normalize-blueprint-option'); +var mergeBlueprintOptions = require('../utilities/merge-blueprint-options'); +var debug = require('debug')('ember-cli:command:init'); + +module.exports = Command.extend({ + name: 'init', + description: 'Creates a new ember-cli project in the current folder.', + works: 'everywhere', + + availableOptions: [ + { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'blueprint', type: String, aliases: ['b'] }, + { name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] }, + { name: 'skip-bower', type: Boolean, default: false, aliases: ['sb'] }, + { name: 'name', type: String, default: '', aliases: ['n'] } + ], + + anonymousOptions: [ + '' + ], + + _defaultBlueprint: function() { + if (this.project.isEmberCLIAddon()) { + return 'addon'; + } else { + return 'app'; + } + }, + + beforeRun: mergeBlueprintOptions, + + run: function(commandOptions, rawArgs) { + if (commandOptions.dryRun) { + commandOptions.skipNpm = true; + commandOptions.skipBower = true; + } + + var installBlueprint = new this.tasks.InstallBlueprint({ + ui: this.ui, + analytics: this.analytics, + project: this.project + }); + + // needs an explicit check in case it's just 'undefined' + // due to passing of options from 'new' and 'addon' + if (commandOptions.skipGit === false) { + var gitInit = new this.tasks.GitInit({ + ui: this.ui, + project: this.project + }); + } + + if (!commandOptions.skipNpm) { + var npmInstall = new this.tasks.NpmInstall({ + ui: this.ui, + analytics: this.analytics, + project: this.project + }); + } + + if (!commandOptions.skipBower) { + var bowerInstall = new this.tasks.BowerInstall({ + ui: this.ui, + analytics: this.analytics, + project: this.project + }); + } + + var project = this.project; + var packageName = commandOptions.name !== '.' && commandOptions.name || project.name(); + + if (!packageName) { + var message = 'The `ember ' + this.name + '` command requires a ' + + 'package.json in current folder with name attribute or a specified name via arguments. ' + + 'For more details, use `ember help`.'; + + return Promise.reject(new SilentError(message)); + } + + var blueprintOpts = clone(commandOptions); + merge(blueprintOpts, { + rawName: packageName, + targetFiles: rawArgs || '', + rawArgs: rawArgs.toString(), + blueprint: normalizeBlueprint(blueprintOpts.blueprint || this._defaultBlueprint()) + }); + + if (!validProjectName(packageName)) { + return Promise.reject(new SilentError('We currently do not support a name of `' + packageName + '`.')); + } + + debug('before:installblueprint'); + return installBlueprint.run(blueprintOpts) + .then(function() { + debug('after:installblueprint'); + if (commandOptions.skipGit === false) { + return gitInit.run(commandOptions, rawArgs); + } + }) + .then(function() { + if (!commandOptions.skipNpm) { + return npmInstall.run({ + verbose: commandOptions.verbose, + optional: false + }); + } + }) + .then(function() { + if (!commandOptions.skipBower) { + return bowerInstall.run({ + verbose: commandOptions.verbose + }); + } + }); + } +}); diff --git a/packages/ember-cli/lib/commands/install-addon.js b/packages/ember-cli/lib/commands/install-addon.js new file mode 100644 index 000000000000..797657e3206a --- /dev/null +++ b/packages/ember-cli/lib/commands/install-addon.js @@ -0,0 +1,17 @@ +'use strict'; + +var InstallCommand = require('./install'); + +module.exports = InstallCommand.extend({ + name: 'install:addon', + description: 'This command has been deprecated. Please use `ember install` instead.', + aliases: [], + skipHelp: true, + + run: function() { + var warning = 'This command has been deprecated. Please use `ember '; + warning += 'install ` instead.'; + this.ui.writeDeprecateLine(warning); + return this._super.run.apply(this, arguments); + } +}); diff --git a/packages/ember-cli/lib/commands/install-bower.js b/packages/ember-cli/lib/commands/install-bower.js new file mode 100644 index 000000000000..d3153b402257 --- /dev/null +++ b/packages/ember-cli/lib/commands/install-bower.js @@ -0,0 +1,22 @@ +'use strict'; + +var Command = require('../models/command'); +var SilentError = require('silent-error'); +var Promise = require('../ext/promise'); + +module.exports = Command.extend({ + name: 'install:bower', + description: 'Bower package install are now managed by the user.', + works: 'insideProject', + skipHelp: true, + + anonymousOptions: [ + '' + ], + + run: function() { + var err = 'This command has been removed. Please use `bower install '; + err += ' --save-dev --save-exact` instead.'; + return Promise.reject(new SilentError(err)); + } +}); diff --git a/packages/ember-cli/lib/commands/install-npm.js b/packages/ember-cli/lib/commands/install-npm.js new file mode 100644 index 000000000000..7473fa92e031 --- /dev/null +++ b/packages/ember-cli/lib/commands/install-npm.js @@ -0,0 +1,22 @@ +'use strict'; + +var Command = require('../models/command'); +var SilentError = require('silent-error'); +var Promise = require('../ext/promise'); + +module.exports = Command.extend({ + name: 'install:npm', + description: 'Npm package installs are now managed by the user.', + works: 'insideProject', + skipHelp: true, + + anonymousOptions: [ + '' + ], + + run: function() { + var err = 'This command has been removed. Please use `npm install '; + err += ' --save-dev --save-exact` instead.'; + return Promise.reject(new SilentError(err)); + } +}); diff --git a/packages/ember-cli/lib/commands/install.js b/packages/ember-cli/lib/commands/install.js new file mode 100644 index 000000000000..bf123e850912 --- /dev/null +++ b/packages/ember-cli/lib/commands/install.js @@ -0,0 +1,39 @@ +'use strict'; + +var Command = require('../models/command'); +var SilentError = require('silent-error'); +var Promise = require('../ext/promise'); + +module.exports = Command.extend({ + name: 'install', + description: 'Installs an ember-cli addon from npm.', + aliases: ['i'], + works: 'insideProject', + + anonymousOptions: [ + '' + ], + + run: function(commandOptions, addonNames) { + if (!addonNames.length) { + var msg = 'The `install` command must take an argument with the name'; + msg += ' of an ember-cli addon. For installing all npm and bower '; + msg += 'dependencies you can run `npm install && bower install`.'; + return Promise.reject(new SilentError(msg)); + } + + var AddonInstallTask = this.tasks.AddonInstall; + var addonInstall = new AddonInstallTask({ + ui: this.ui, + analytics: this.analytics, + project: this.project, + NpmInstallTask: this.tasks.NpmInstall, + BlueprintTask: this.tasks.GenerateFromBlueprint + }); + + return addonInstall.run({ + 'packages': addonNames, + blueprintOptions: commandOptions + }); + } +}); diff --git a/packages/ember-cli/lib/commands/new.js b/packages/ember-cli/lib/commands/new.js new file mode 100644 index 000000000000..469b46abfadd --- /dev/null +++ b/packages/ember-cli/lib/commands/new.js @@ -0,0 +1,102 @@ +'use strict'; + +var chalk = require('chalk'); +var Command = require('../models/command'); +var Promise = require('../ext/promise'); +var Project = require('../models/project'); +var SilentError = require('silent-error'); +var rimraf = require('rimraf'); +var rmdir = Promise.denodeify(rimraf); +var validProjectName = require('../utilities/valid-project-name'); +var normalizeBlueprint = require('../utilities/normalize-blueprint-option'); +var mergeBlueprintOptions = require('../utilities/merge-blueprint-options'); + +module.exports = Command.extend({ + name: 'new', + description: 'Creates a new directory and runs ' + chalk.green('ember init') + ' in it.', + works: 'outsideProject', + + availableOptions: [ + { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, + { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, + { name: 'blueprint', type: String, default: 'app', aliases: ['b'] }, + { name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] }, + { name: 'skip-bower', type: Boolean, default: false, aliases: ['sb'] }, + { name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] }, + { name: 'directory', type: String , aliases: ['dir'] } + ], + + anonymousOptions: [ + '' + ], + + beforeRun: mergeBlueprintOptions, + + run: function(commandOptions, rawArgs) { + var packageName = rawArgs[0], + message; + + commandOptions.name = rawArgs.shift(); + + if (!packageName) { + message = chalk.yellow('The `ember ' + this.name + '` command requires a ' + + 'name to be specified. For more details, use `ember help`.'); + + return Promise.reject(new SilentError(message)); + } + + if (commandOptions.dryRun) { + commandOptions.skipGit = true; + } + + if (packageName === '.') { + var blueprintName = commandOptions.blueprint === 'app' ? 'application' : commandOptions.blueprint; + message = 'Trying to generate an ' + blueprintName + ' structure in this directory? Use `ember init` instead.'; + + return Promise.reject(new SilentError(message)); + } + + if (!validProjectName(packageName)) { + message = 'We currently do not support a name of `' + packageName + '`.'; + + return Promise.reject(new SilentError(message)); + } + + commandOptions.blueprint = normalizeBlueprint(commandOptions.blueprint); + + if (!commandOptions.directory) { + commandOptions.directory = packageName; + } + + var createAndStepIntoDirectory = new this.tasks.CreateAndStepIntoDirectory({ + ui: this.ui, + analytics: this.analytics + }); + var InitCommand = this.commands.Init; + + var initCommand = new InitCommand({ + ui: this.ui, + analytics: this.analytics, + tasks: this.tasks, + project: Project.nullProject(this.ui, this.cli) + }); + + return createAndStepIntoDirectory + .run({ + directoryName: commandOptions.directory, + dryRun: commandOptions.dryRun + }) + .then(function(opts) { + return initCommand + .run(commandOptions, rawArgs) + .catch(function(err) { + var dirName = commandOptions.directory; + process.chdir(opts.initialDirectory); + return rmdir(dirName).then(function() { + console.log(chalk.red('Error creating new application. Removing generated directory `./' + dirName + '`')); + throw err; + }); + }); + }); + } +}); diff --git a/packages/ember-cli/lib/commands/test.js b/packages/ember-cli/lib/commands/test.js new file mode 100644 index 000000000000..dc9ade4264b3 --- /dev/null +++ b/packages/ember-cli/lib/commands/test.js @@ -0,0 +1,175 @@ +'use strict'; + +var Command = require('../models/command'); +var Watcher = require('../models/watcher'); +var Builder = require('../models/builder'); +var SilentError = require('silent-error'); +var path = require('path'); +var win = require('../utilities/windows-admin'); +var existsSync = require('exists-sync'); + +var defaultPort = 7357; + +module.exports = Command.extend({ + name: 'test', + description: 'Runs your app\'s test suite.', + aliases: ['t'], + + availableOptions: [ + { name: 'environment', type: String, default: 'test', aliases: ['e'] }, + { name: 'config-file', type: String, aliases: ['c', 'cf']}, + { name: 'server', type: Boolean, default: false, aliases: ['s'] }, + { name: 'host', type: String, aliases: ['H'] }, + { name: 'test-port', type: Number, default: defaultPort, aliases: ['tp'], description: 'The test port to use when running with --server.' }, + { name: 'filter', type: String, aliases: ['f'], description: 'A string to filter tests to run' }, + { name: 'module', type: String, aliases: ['m'], description: 'The name of a test module to run' }, + { name: 'watcher', type: String, default: 'events', aliases: ['w'] }, + { name: 'launch', type: String, default: false, description: 'A comma separated list of browsers to launch for tests.' }, + { name: 'reporter', type: String, aliases: ['r'], description: 'Test reporter to use [tap|dot|xunit] (default: tap)' }, + { name: 'silent', type: Boolean, default: false, description: 'Suppress any output except for the test report' }, + { name: 'test-page', type: String, description: 'Test page to invoke' }, + { name: 'path', type: 'Path', description: 'Reuse an existing build at given path.' }, + { name: 'query', type: String, description: 'A query string to append to the test page URL.' } + ], + + init: function() { + this.assign = require('lodash/assign'); + this.quickTemp = require('quick-temp'); + + this.Builder = this.Builder || Builder; + this.Watcher = this.Watcher || Watcher; + + if (!this.testing) { + process.env.EMBER_CLI_TEST_COMMAND = true; + } + }, + + tmp: function() { + return this.quickTemp.makeOrRemake(this, '-testsDist'); + }, + + rmTmp: function() { + this.quickTemp.remove(this, '-testsDist'); + this.quickTemp.remove(this, '-customConfigFile'); + }, + + _generateCustomConfigs: function(options) { + var config = {}; + if (!options.filter && !options.module && !options.launch && !options.query && !options['test-page']) { return config; } + + var testPage = options['test-page']; + var queryString = this.buildTestPageQueryString(options); + if (testPage) { + var containsQueryString = testPage.indexOf('?') > -1; + var testPageJoinChar = containsQueryString ? '&' : '?'; + config.testPage = testPage + testPageJoinChar + queryString; + } + if (queryString) { + config.queryString = queryString; + } + + if (options.launch) { + config.launch = options.launch; + } + + return config; + }, + + _generateTestPortNumber: function(options) { + if (options.port && options.testPort !== defaultPort || !isNaN(parseInt(options.testPort)) && !options.port) { return options.testPort; } + if (options.port) { return parseInt(options.port, 10) + 1; } + }, + + buildTestPageQueryString: function(options) { + var params = []; + + if (options.module) { + params.push('module=' + options.module); + } + + if (options.filter) { + params.push('filter=' + options.filter.toLowerCase()); + } + + if (options.query) { + params.push(options.query); + } + + return params.join('&'); + }, + + run: function(commandOptions) { + var hasBuild = !!commandOptions.path; + var outputPath; + + if (hasBuild) { + outputPath = path.resolve(commandOptions.path); + + if (!existsSync(outputPath)) { + throw new SilentError('The path ' + commandOptions.path + ' does not exist. Please specify a valid build directory to test.'); + } + } else { + outputPath = this.tmp(); + } + + process.env['EMBER_CLI_TEST_OUTPUT'] = outputPath; + + var testOptions = this.assign({}, commandOptions, { + ui: this.ui, + outputPath: outputPath, + project: this.project, + port: this._generateTestPortNumber(commandOptions) + }, this._generateCustomConfigs(commandOptions)); + + var options = { + ui: this.ui, + analytics: this.analytics, + project: this.project + }; + + return win.checkWindowsElevation(this.ui).then(function() { + var session; + + if (commandOptions.server) { + if (hasBuild) { + throw new SilentError('Specifying a build is not allowed with the `--server` option.'); + } + + var TestServerTask = this.tasks.TestServer; + var testServer = new TestServerTask(options); + var builder = new this.Builder(testOptions); + + testOptions.watcher = new this.Watcher(this.assign(options, { + builder: builder, + verbose: false, + options: commandOptions + })); + + session = testServer.run(testOptions).finally(function() { + return builder.cleanup(); + }); + + } else { + var TestTask = this.tasks.Test; + var test = new TestTask(options); + + if (hasBuild) { + session = test.run(testOptions); + } else { + var BuildTask = this.tasks.Build; + var build = new BuildTask(options); + + session = build.run({ + environment: commandOptions.environment, + outputPath: outputPath + }) + .then(function() { + return test.run(testOptions); + }) + } + } + + return session.finally(this.rmTmp.bind(this)); + }.bind(this)); + } +}); diff --git a/packages/ember-cli/lib/commands/uninstall-npm.js b/packages/ember-cli/lib/commands/uninstall-npm.js new file mode 100644 index 000000000000..5681d4ee2676 --- /dev/null +++ b/packages/ember-cli/lib/commands/uninstall-npm.js @@ -0,0 +1,22 @@ +'use strict'; + +var Command = require('../models/command'); +var SilentError = require('silent-error'); +var Promise = require('../ext/promise'); + +module.exports = Command.extend({ + name: 'uninstall:npm', + description: 'Npm package uninstall are now managed by the user.', + works: 'insideProject', + skipHelp: true, + + anonymousOptions: [ + '' + ], + + run: function() { + var err = 'This command has been removed. Please use `npm uninstall '; + err += ' --save-dev` instead.'; + return Promise.reject(new SilentError(err)); + } +}); diff --git a/packages/ember-cli/lib/commands/unknown.js b/packages/ember-cli/lib/commands/unknown.js new file mode 100644 index 000000000000..9b81633dd7d3 --- /dev/null +++ b/packages/ember-cli/lib/commands/unknown.js @@ -0,0 +1,20 @@ +'use strict'; + +var Command = require('../models/command'); +var SilentError = require('silent-error'); +var chalk = require('chalk'); + +module.exports = Command.extend({ + skipHelp: true, + unknown: true, + + printBasicHelp: function() { + return chalk.red('No help entry for \'' + this.name + '\''); + }, + + validateAndRun: function() { + throw new SilentError('The specified command ' + this.name + + ' is invalid. For available options, see' + + ' `ember help`.'); + } +}); diff --git a/packages/ember-cli/lib/commands/version.js b/packages/ember-cli/lib/commands/version.js new file mode 100644 index 000000000000..f91fa7c71e27 --- /dev/null +++ b/packages/ember-cli/lib/commands/version.js @@ -0,0 +1,34 @@ +'use strict'; + +var Command = require('../models/command'); +var emberCLIVersion = require('../utilities/version-utils').emberCLIVersion; + +module.exports = Command.extend({ + name: 'version', + description: 'outputs ember-cli version', + aliases: ['v', '--version', '-v'], + works: 'everywhere', + + availableOptions: [ + { name: 'verbose', type: Boolean, default: false } + ], + + run: function(options) { + this.printVersion('ember-cli', emberCLIVersion()); + + var versions = process.versions; + versions['os'] = process.platform + ' ' + process.arch; + + var alwaysPrint = ['node', 'os']; + + for (var module in versions) { + if (options.verbose || alwaysPrint.indexOf(module) > -1) { + this.printVersion(module, versions[module]); + } + } + }, + + printVersion: function(module, version) { + this.ui.writeLine(module + ': ' + version); + } +}); diff --git a/packages/ember-cli/lib/errors/silent.js b/packages/ember-cli/lib/errors/silent.js new file mode 100644 index 000000000000..25be58c57161 --- /dev/null +++ b/packages/ember-cli/lib/errors/silent.js @@ -0,0 +1,11 @@ +'use strict'; + +var SilentError = require('silent-error'); +var deprecate = require('../utilities/deprecate'); + +Object.defineProperty(module, 'exports', { + get: function () { + deprecate('`ember-cli/lib/errors/silent.js` is deprecated, use `silent-error` instead.', true); + return SilentError; + } +}); diff --git a/packages/ember-cli/lib/ext/promise.js b/packages/ember-cli/lib/ext/promise.js new file mode 100644 index 000000000000..c83af6a0dc7c --- /dev/null +++ b/packages/ember-cli/lib/ext/promise.js @@ -0,0 +1,68 @@ +'use strict'; + +var RSVP = require('rsvp'); +var Promise = RSVP.Promise; + +module.exports = PromiseExt; + +// Utility functions on the native CTOR need some massaging +module.exports.hash = function() { + return this.resolve(RSVP.hash.apply(null, arguments)); +}; + +module.exports.denodeify = function() { + var fn = RSVP.denodeify.apply(null, arguments); + var Constructor = this; + var newFn = function() { + return Constructor.resolve(fn.apply(null, arguments)); + }; + newFn.__proto__ = arguments[0]; + return newFn; +}; + +module.exports.filter = function() { + return this.resolve(RSVP.filter.apply(null, arguments)); +}; + +module.exports.map = function() { + return this.resolve(RSVP.map.apply(null, arguments)); +}; + +function PromiseExt(resolver, label) { + this._superConstructor(resolver, label); +} + +PromiseExt.prototype = Object.create(Promise.prototype); +PromiseExt.prototype.constructor = PromiseExt; +PromiseExt.prototype._superConstructor = Promise; +PromiseExt.__proto__ = Promise; + +PromiseExt.prototype.returns = function(value) { + return this.then(function() { + return value; + }); +}; + +PromiseExt.prototype.invoke = function(method) { + var args = Array.prototype.slice(arguments, 1); + + return this.then(function(value) { + return value[method].apply(value, args); + }, undefined, 'invoke: ' + method + ' with: ' + args); +}; + +function constructorMethod(promise, methodName, fn) { + var Constructor = promise.constructor; + + return promise.then(function(values) { + return Constructor[methodName](values, fn); + }); +} + +PromiseExt.prototype.map = function(mapFn) { + return constructorMethod(this, 'map', mapFn); +}; + +PromiseExt.prototype.filter = function(filterFn) { + return constructorMethod(this, 'filter', filterFn); +}; diff --git a/packages/ember-cli/lib/models/addon-discovery.js b/packages/ember-cli/lib/models/addon-discovery.js new file mode 100644 index 000000000000..d4ba7b41872a --- /dev/null +++ b/packages/ember-cli/lib/models/addon-discovery.js @@ -0,0 +1,260 @@ +'use strict'; + +/** +@module ember-cli +*/ + +var assign = require('lodash/assign'); +var debug = require('debug')('ember-cli:addon-discovery'); +var existsSync = require('exists-sync'); +var path = require('path'); +var CoreObject = require('core-object'); +var resolve = require('resolve'); +var findup = require('findup'); + +/** + AddonDiscovery is responsible for collecting information about all of the + addons that will be used with a project. + + @class AddonDiscovery + @extends CoreObject + @constructor +*/ + +function AddonDiscovery(ui) { + this.ui = ui; +} + +AddonDiscovery.__proto__ = CoreObject; +AddonDiscovery.prototype.constructor = AddonDiscovery; + +/** + This is one of the primary APIs for this class and is called by the project. + It returns a tree of plain objects that each contain information about a + discovered addon. Each node has `name`, `path`, `pkg` and + `childAddons` properties. The latter is an array containing any addons + discovered from applying the discovery process to that addon. + + @private + @method discoverProjectAddons + */ +AddonDiscovery.prototype.discoverProjectAddons = function(project) { + var projectAsAddon = this.discoverFromProjectItself(project); + var internalAddons = this.discoverFromInternalProjectAddons(project); + var cliAddons = this.discoverFromCli(project.cli); + var dependencyAddons; + + if (project.hasDependencies()) { + dependencyAddons = this.discoverFromDependencies(project.root, project.nodeModulesPath, project.pkg, false); + } else { + dependencyAddons = []; + } + + var inRepoAddons = this.discoverInRepoAddons(project.root, project.pkg); + var addons = projectAsAddon.concat(cliAddons, internalAddons, dependencyAddons, inRepoAddons); + + return addons; +}; + +/** + This is one of the primary APIs for this class and is called by addons. + It returns a tree of plain objects that each contain information about a + discovered addon. Each node has `name`, `path`, `pkg` and + `childAddons` properties. The latter is an array containing any addons + discovered from applying the discovery process to that addon. + + @private + @method discoverProjectAddons + */ +AddonDiscovery.prototype.discoverChildAddons = function(addon) { + debug('discoverChildAddons: %s(%s)', addon.name, addon.root); + var dependencyAddons = this.discoverFromDependencies(addon.root, addon.nodeModulesPath, addon.pkg, true); + var inRepoAddons = this.discoverInRepoAddons(addon.root, addon.pkg); + var addons = dependencyAddons.concat(inRepoAddons); + + addons = addons.filter(function(childAddon) { + return !addon.shouldIncludeChildAddon || addon.shouldIncludeChildAddon(childAddon); + }); + + return addons; +}; + +/** + Returns an array containing zero or one nodes, depending on whether or not + the passed project is an addon. + + @private + @method discoverFromProjectItself + */ +AddonDiscovery.prototype.discoverFromProjectItself = function(project) { + if (project.isEmberCLIAddon()) { + var addonPkg = this.discoverAtPath(project.root); + if (addonPkg) { + return [addonPkg]; + } + } + return []; +}; + +/** + Returns a tree based on the addons referenced in the provided `pkg` through + the package.json `dependencies` and optionally `devDependencies` collections, + as well as those discovered addons' child addons. + + @private + @method discoverFromDependencies + */ +AddonDiscovery.prototype.discoverFromDependencies = function(root, nodeModulesPath, pkg, excludeDevDeps) { + var discovery = this; + var addons = Object.keys(this.dependencies(pkg, excludeDevDeps)).map(function(name) { + if (name !== 'ember-cli') { + var addonPath = this.resolvePackage(root, name); + + if (addonPath) { + return discovery.discoverAtPath(addonPath); + } + + // this supports packages that do not have a valid entry point + // script (aka `main` entry in `package.json` or `index.js`) + addonPath = path.join(nodeModulesPath, name); + var addon = discovery.discoverAtPath(addonPath); + if (addon) { + var chalk = require('chalk'); + + discovery.ui.writeLine(chalk.yellow('The package `' + name + '` is not a properly formatted package, we have used a fallback lookup to resolve it at `' + addonPath + '`. This is generally caused by an addon not having a `main` entry point (or `index.js`).'), 'WARNING'); + + return addon; + } + } + }, this).filter(Boolean); + return addons; +}; + +AddonDiscovery.prototype.resolvePackage = function(root, packageName) { + try { + + var entryModulePath = resolve.sync(packageName, { basedir: root }); + + return findup.sync(entryModulePath, 'package.json'); + } catch (e) { + var acceptableError = 'Cannot find module \'' + packageName + '\' from \'' + root + '\''; + // pending: https://github.com/substack/node-resolve/pull/80 + var workAroundError = 'Cannot read property \'isFile\' of undefined'; + + if (e.message === workAroundError || e.message === acceptableError) { + return; + } + throw e; + } +}; + +/** + Returns a tree based on the in-repo addons referenced in the provided `pkg` + through paths listed in the `ember-addon` entry, as well as those discovered + addons' child addons. + + @private + @method discoverInRepoAddons + */ +AddonDiscovery.prototype.discoverInRepoAddons = function(root, pkg) { + if (!pkg || !pkg['ember-addon'] || !pkg['ember-addon'].paths) { + return []; + } + var discovery = this; + var addons = pkg['ember-addon'].paths.map(function(addonPath) { + addonPath = path.join(root, addonPath); + return discovery.discoverAtPath(addonPath); + }, this).filter(Boolean); + return addons; +}; + +/** + Returns a tree based on the internal addons that may be defined within the project. + It does this by consulting the projects `supportedInternalAddonPaths()` method, which + is primarily used for middleware addons. + + @private + @method discoverFromInternalProjectAddons + */ +AddonDiscovery.prototype.discoverFromInternalProjectAddons = function(project) { + var discovery = this; + return project.supportedInternalAddonPaths().map(function(path) { + return discovery.discoverAtPath(path); + }).filter(Boolean); +}; + +AddonDiscovery.prototype.discoverFromCli = function (cli) { + if (!cli) { return []; } + + var cliPkg = require(path.resolve(cli.root, 'package.json')); + return this.discoverInRepoAddons(cli.root, cliPkg); +}; + +/** + Given a particular path, return undefined if the path is not an addon, or if it is, + a node with the info about the addon. + + @private + @method discoverAtPath + */ +AddonDiscovery.prototype.discoverAtPath = function(addonPath) { + var pkgPath = path.join(addonPath, 'package.json'); + debug('attemping to add: %s', addonPath); + + if (existsSync(pkgPath)) { + var addonPkg = require(pkgPath); + var keywords = addonPkg.keywords || []; + debug(' - module found: %s', addonPkg.name); + + addonPkg['ember-addon'] = addonPkg['ember-addon'] || {}; + + if (keywords.indexOf('ember-addon') > -1) { + debug(' - is addon, adding...'); + var addonInfo = { + name: addonPkg.name, + path: addonPath, + pkg: addonPkg, + }; + return addonInfo; + } else { + debug(' - no ember-addon keyword, not including.'); + } + } else { + debug(' - no package.json (looked at ' + pkgPath + ').'); + } + + return null; +}; + +/** + Returns the dependencies from a package.json + + @private + @method dependencies + @param {Object} pkg Package object. If false, the current package is used. + @param {Boolean} excludeDevDeps Whether or not development dependencies should be excluded, defaults to false. + @return {Object} Dependencies + */ +AddonDiscovery.prototype.dependencies = function(pkg, excludeDevDeps) { + pkg = pkg || {}; + + var devDependencies = pkg['devDependencies']; + if (excludeDevDeps) { + devDependencies = {}; + } + + return assign({}, devDependencies, pkg['dependencies']); +}; + +AddonDiscovery.prototype.addonPackages = function(addonsList) { + var addonPackages = {}; + + addonsList.forEach(function(addonPkg) { + addonPackages[addonPkg.name] = addonPkg; + }); + + return addonPackages; +}; + +// Export +module.exports = AddonDiscovery; diff --git a/packages/ember-cli/lib/models/addon.js b/packages/ember-cli/lib/models/addon.js new file mode 100644 index 000000000000..89fda6453014 --- /dev/null +++ b/packages/ember-cli/lib/models/addon.js @@ -0,0 +1,979 @@ +'use strict'; + +/** +@module ember-cli +*/ + +var existsSync = require('exists-sync'); +var path = require('path'); +var assign = require('lodash/assign'); +var SilentError = require('silent-error'); +var debug = require('debug')('ember-cli:addon'); + +var nodeModulesPath = require('node-modules-path'); + +var p = require('ember-cli-preprocess-registry/preprocessors'); +var preprocessJs = p.preprocessJs; +var preprocessCss = p.preprocessCss; +var preprocessTemplates = p.preprocessTemplates; + +var AddonDiscovery = require('../models/addon-discovery'); +var AddonsFactory = require('../models/addons-factory'); +var CoreObject = require('core-object'); +var Project = require('./project'); + +var upstreamMergeTrees = require('broccoli-merge-trees'); +var Funnel = require('broccoli-funnel'); +var walkSync = require('walk-sync'); + + +function mergeTrees(inputTree, options) { + options = options || {}; + options.description = options.annotation; + var tree = upstreamMergeTrees(inputTree, options); + + tree.description = options && options.description; + + return tree; +} + + +/** + Root class for an Addon. If your addon module exports an Object this + will be extended from this base class. If you export a constructor (function), + it will **not** extend from this class. + + Hooks: + + - {{#crossLink "Addon/config:method"}}config{{/crossLink}} + - {{#crossLink "Addon/blueprintsPath:method"}}blueprintsPath{{/crossLink}} + - {{#crossLink "Addon/includedCommands:method"}}includedCommands{{/crossLink}} + - {{#crossLink "Addon/serverMiddleware:method"}}serverMiddleware{{/crossLink}} + - {{#crossLink "Addon/postBuild:method"}}postBuild{{/crossLink}} + - {{#crossLink "Addon/outputReady:method"}}outputReady{{/crossLink}} + - {{#crossLink "Addon/preBuild:method"}}preBuild{{/crossLink}} + - {{#crossLink "Addon/buildError:method"}}buildError{{/crossLink}} + - {{#crossLink "Addon/included:method"}}included{{/crossLink}} + - {{#crossLink "Addon/postprocessTree:method"}}postprocessTree{{/crossLink}} + - {{#crossLink "Addon/treeFor:method"}}treeFor{{/crossLink}} + + @class Addon + @extends CoreObject + @constructor + @param {(Project|Addon)} parent The project or addon that directly depends on this addon + @param {Project} project The current project (deprecated) +*/ +function Addon(parent, project) { + this.parent = parent; + this.project = project; + this.ui = project && project.ui; + this.addonPackages = {}; + this.addons = []; + this.addonDiscovery = new AddonDiscovery(this.ui); + this.addonsFactory = new AddonsFactory(this, this.project); + this.registry = p.defaultRegistry(this); + this._didRequiredBuildPackages = false; + + if (!this.root) { + throw new Error('Addon classes must be instantiated with the `root` property'); + } + this.nodeModulesPath = nodeModulesPath(this.root); + + this.treePaths = { + app: 'app', + styles: 'app/styles', + templates: 'app/templates', + addon: 'addon', + 'addon-styles': 'addon/styles', + 'addon-templates': 'addon/templates', + vendor: 'vendor', + 'test-support': 'test-support', + 'addon-test-support': 'addon-test-support', + public: 'public' + }; + + this.treeForMethods = { + app: 'treeForApp', + styles: 'treeForStyles', + templates: 'treeForTemplates', + 'addon-templates': 'treeForAddonTemplates', + addon: 'treeForAddon', + vendor: 'treeForVendor', + 'test-support': 'treeForTestSupport', + 'addon-test-support': 'treeForAddonTestSupport', + public: 'treeForPublic' + }; + + p.setupRegistry(this); + + if (!this.name) { + throw new SilentError('An addon must define a `name` property.'); + } +} + +Addon.__proto__ = CoreObject; +Addon.prototype.constructor = Addon; + +Addon.prototype.hintingEnabled = function() { + var isProduction = process.env.EMBER_ENV === 'production'; + var testsEnabledDefault = process.env.EMBER_CLI_TEST_COMMAND || !isProduction; + + return testsEnabledDefault; +}; + +/** + Loads all required modules for a build + + @private + @method _requireBuildPackages + */ + +Addon.prototype._requireBuildPackages = function() { + if (this._didRequiredBuildPackages === true) { + return; + } else { + this._didRequiredBuildPackages = true; + } + + this.transpileModules = deprecatedAddonFilters(this, 'this.transpileModules', 'broccoli-es6modules', function(tree, options) { + return new (require('broccoli-es6modules'))(tree, options); + }); + + this.pickFiles = deprecatedAddonFilters(this, 'this.pickFiles', 'broccoli-funnel', function(tree, options) { + return new Funnel(tree, options); + }); + + + this.Funnel = deprecatedAddonFilters(this, 'new this.Funnel(..)', 'broccoli-funnel', function(tree, options) { + return new Funnel(tree, options); + }); + + this.mergeTrees = deprecatedAddonFilters(this, 'this.mergeTrees', 'broccoli-merge-trees', mergeTrees); + this.walkSync = deprecatedAddonFilters(this, 'this.walkSync', 'node-walk-sync', walkSync); +}; + +function deprecatedAddonFilters(addon, name, insteadUse, fn) { + return function(tree, options) { + var message = name + ' is deprecated, please use ' + + insteadUse + ' directly instead [addon: ' + addon.name + ']'; + + this.ui && this.ui.writeDeprecateLine(message); + + if (!this.ui) { + console.warn(message); + } + + return fn(tree, options); + }; +} + +/** + Shorthand method for [broccoli-concat](https://github.com/ember-cli/broccoli-concat) + + @private + @method concatFiles + @param {tree} tree Tree of files + @param {Object} options Options for broccoli-concat + @return {tree} Modified tree +*/ +Addon.prototype.concatFiles = function(tree, options) { + options.sourceMapConfig = this.app.options.sourcemaps; + return require('broccoli-concat')(tree, options); +}; + +/** + Returns whether or not this addon is running in development + + @public + @method isDevelopingAddon + @return {Boolean} +*/ +Addon.prototype.isDevelopingAddon = function() { + if (process.env.EMBER_ADDON_ENV === 'development' && (this.parent instanceof Project)) { + return this.parent.name() === this.name; + } + return false; +}; + +/** + Discovers all child addons of this addon and stores their names and + package.json contents in this.addonPackages as key-value pairs + + @private + @method discoverAddons + */ +Addon.prototype.discoverAddons = function() { + var addonsList = this.addonDiscovery.discoverChildAddons(this); + + this.addonPackages = this.addonDiscovery.addonPackages(addonsList); +}; + +Addon.prototype.initializeAddons = function() { + if (this._addonsInitialized) { + return; + } + this._addonsInitialized = true; + + debug('initializeAddons for: %s', this.name); + + this.discoverAddons(); + this.addons = this.addonsFactory.initializeAddons(this.addonPackages); + + this.addons.forEach(function(addon) { + debug('addon: %s', addon.name); + }); +}; + +/** + Invoke the specified method for each enabled addon. + + @private + @method eachAddonInvoke + @param {String} methodName the method to invoke on each addon + @param {Array} args the arguments to pass to the invoked method +*/ +Addon.prototype.eachAddonInvoke = function eachAddonInvoke(methodName, args) { + this.initializeAddons(); + + var invokeArguments = args || []; + + return this.addons.map(function(addon) { + if (addon[methodName]) { + return addon[methodName].apply(addon, invokeArguments); + } + }).filter(Boolean); +}; + +/** + Returns a given type of tree (if present), merged with the + application tree. For each of the trees available using this + method, you can also use a direct method called treeFor[Type] (eg. `treeForApp`). + + Available tree names: + - {{#crossLink "Addon/treeForApp:method"}}app{{/crossLink}} + - {{#crossLink "Addon/treeForStyles:method"}}styles{{/crossLink}} + - {{#crossLink "Addon/treeForTemplates:method"}}templates{{/crossLink}} + - {{#crossLink "Addon/treeForAddonTemplates:method"}}addon-templates{{/crossLink}} + - {{#crossLink "Addon/treeForAddon:method"}}addon{{/crossLink}} + - {{#crossLink "Addon/treeForVendor:method"}}vendor{{/crossLink}} + - {{#crossLink "Addon/treeForTestSupport:method"}}test-support{{/crossLink}} + - {{#crossLink "Addon/treeForPublic:method"}}public{{/crossLink}} + + @public + @method treeFor + @param {String} name + @return {tree} +*/ +Addon.prototype.treeFor = function treeFor(name) { + this._requireBuildPackages(); + + var trees = this.eachAddonInvoke('treeFor', [name]); + var tree = this._treeFor(name); + + if (tree) { + trees.push(tree); + } + + if (this.isDevelopingAddon() && this.hintingEnabled() && name === 'app') { + trees.push(this.jshintAddonTree()); + } + + return mergeTrees(trees.filter(Boolean), { + overwrite: true, + annotation: 'Addon#treeFor (' + this.name + ' - ' + name + ')' + }); +}; + +/** + @private + @param {String} name + @method _treeFor + @return {tree} +*/ +Addon.prototype._treeFor = function _treeFor(name) { + var treePath = path.resolve(this.root, this.treePaths[name]); + var treeForMethod = this.treeForMethods[name]; + var tree; + + // if (existsSync(treePath)) { + // tree = this.treeGenerator(treePath); + // } + + if (this[treeForMethod]) { + tree = this[treeForMethod](tree); + } + + return tree; +}; + +/** + This method is called when the addon is included in a build. You + would typically use this hook to perform additional imports + + ```js + included: function(app) { + app.import(somePath); + } + ``` + + @public + @method included + @param {EmberApp} app The application object +*/ +Addon.prototype.included = function(/* app */) { + if (!this._addonsInitialized) { + // someone called `this._super.included` without `apply` (because of older + // core-object issues that prevent a "real" super call from working properly) + return; + } + + this.eachAddonInvoke('included', [this]); +}; + +/** + Returns the tree for all app files + + @public + @method treeForApp + @param {Tree} tree + @return {Tree} App file tree +*/ +Addon.prototype.treeForApp = function(tree) { + return tree; +}; + +/** + Returns the tree for all template files + + @public + @method treeForTemplates + @param {Tree} tree + @return {Tree} Template file tree +*/ +Addon.prototype.treeForTemplates = function(tree) { + return tree; +}; + +/** + Returns the tree for this addon's templates + + @public + @method treeForAddonTemplates + @param {Tree} tree + @return {Tree} Addon Template file tree +*/ +Addon.prototype.treeForAddonTemplates = function(tree) { + return tree; +}; + +/** + Returns a tree for this addon + + @public + @method treeForAddon + @param {Tree} tree + @return {Tree} Addon file tree +*/ +Addon.prototype.treeForAddon = function(tree) { + this._requireBuildPackages(); + + if (!tree) { + return tree; + } + + var addonTree = this.compileAddon(tree); + var stylesTree = this.compileStyles(this._treeFor('addon-styles')); + + return mergeTrees([addonTree, stylesTree].filter(Boolean), { + annotation: 'Addon#treeForAddon(' + this.name + ')' + }); +}; + +/** + Returns the tree for all style files + + @public + @method treeForStyles + @param {Tree} tree The tree to process, usually `app/styles/` in the addon. + @returns {Tree} The return tree has the same contents as the input tree, but is moved so that the `app/styles/` path is preserved. +*/ +Addon.prototype.treeForStyles = function(tree) { + this._requireBuildPackages(); + + if (!tree) { + return tree; + } + + return new Funnel(tree, { + destDir: 'app/styles' + }); +}; + +/** + Returns the tree for all vendor files + + @public + @method treeForVendor + @param {Tree} tree + @return {Tree} Vendor file tree +*/ +Addon.prototype.treeForVendor = function(tree) { + return tree; +}; + +/** + Returns the tree for all test support files + + @public + @method treeForTestSupport + @param {Tree} tree + @return {Tree} Test Support file tree +*/ +Addon.prototype.treeForTestSupport = function(tree) { + return tree; +}; + +/** + Returns the tree for all public files + + @public + @method treeForPublic + @param {Tree} tree + @return {Tree} Public file tree +*/ +Addon.prototype.treeForPublic = function(tree) { + this._requireBuildPackages(); + + if (!tree) { + return tree; + } + + return new Funnel(tree, { + srcDir: '/', + destDir: '/' + this.moduleName() + }); +}; + +/** + Returns the tree for all test files namespaced to a given addon. + + @public + @method treeForAddonTestSupport + @param {Tree} tree + @return {Tree} + */ +Addon.prototype.treeForAddonTestSupport = function(tree) { + if (!tree) { + return tree; + } + + var processed = this.preprocessJs(tree, '/', this.name, { + registry: this.registry + }); + + return new Funnel(processed, { + srcDir: '/', + destDir: '/' + this.moduleName() + '/test-support' + }); +}; + +/** + Runs the styles tree through preprocessors. + + @private + @method compileStyles + @param {Tree} tree Styles file tree + @return {Tree} Compiled styles tree +*/ +Addon.prototype.compileStyles = function(tree) { + this._requireBuildPackages(); + + if (tree) { + return preprocessCss(tree, '/', '/', { + outputPaths: { 'addon': this.name + '.css' }, + registry: this.registry + }); + } +}; + +/** + Looks in the addon/ and addon/templates trees to determine if template files + exists that need to be precompiled. + + This is executed once when building, but not on rebuilds. + + @private + @method shouldCompileTemplates + @returns Boolean indicates if templates need to be compiled for this addon +*/ +Addon.prototype.shouldCompileTemplates = function() { + var templateExtensions = this.registry.extensionsForType('template'); + var addonTreePath = path.join(this.root, this.treePaths['addon']); + var addonTemplatesTreePath = path.join(this.root, this.treePaths['addon-templates']); + + var files = []; + + if (existsSync(addonTreePath)) { + files = files.concat(walkSync(addonTreePath)); + } + + if (existsSync(addonTemplatesTreePath)) { + files = files.concat(walkSync(addonTemplatesTreePath)); + } + + var extensionMatcher = new RegExp('(' + templateExtensions.join('|') + ')$'); + + return files.some(function(file) { + return file.match(extensionMatcher); + }); +}; + +Addon.prototype._addonTemplateFiles = function addonTemplateFiles(tree) { + this._requireBuildPackages(); + + if (this._cachedAddonTemplateFiles) { + return this._cachedAddonTemplateFiles; + } + + var trees = []; + var addonTemplates = this._treeFor('addon-templates'); + var standardTemplates; + + if (addonTemplates) { + standardTemplates = new Funnel(addonTemplates, { + srcDir: '/', + destDir: 'modules/' + this.name + '/templates' + }); + + trees.push(standardTemplates); + } + + var includePatterns = this.registry.extensionsForType('template').map(function(extension) { + return '**/*/template.' + extension; + }); + + var podTemplates = new Funnel(tree, { + include: includePatterns, + destDir: 'modules/' + this.name + '/', + annotation: 'Funnel: Addon Pod Templates' + }); + + trees.push(podTemplates); + + this._cachedAddonTemplateFiles = mergeTrees(trees, { + annotation: 'TreeMerge (' + this.name + ' templates)' + }); + + return this._cachedAddonTemplateFiles; +}; + +/** + Invoke the specified method for each of the project's addons. + + @private + @method _eachProjectAddonInvoke + @param {String} methodName the method to invoke on each addon + @param {Array} args the arguments to pass to the invoked method +*/ +Addon.prototype._eachProjectAddonInvoke = function eachProjectAddonInvoke(methodName, args) { + this.initializeAddons(); + + var invokeArguments = args || []; + + return this.project.addons.map(function(addon) { + if (addon[methodName]) { + return addon[methodName].apply(addon, invokeArguments); + } + }).filter(Boolean); +}; + +/** + Runs the templates tree through preprocessors. + + @private + @method compileTemplates + @param {Tree} tree Templates file tree + @return {Tree} Compiled templates tree +*/ +Addon.prototype.compileTemplates = function(tree) { + this._requireBuildPackages(); + + if (this.shouldCompileTemplates()) { + var plugins = this.registry.load('template'); + + if (plugins.length === 0) { + throw new SilentError('Addon templates were detected, but there ' + + 'are no template compilers registered for `' + this.name + '`. ' + + 'Please make sure your template precompiler (commonly `ember-cli-htmlbars`) ' + + 'is listed in `dependencies` (NOT `devDependencies`) in ' + + '`' + this.name + '`\'s `package.json`.'); + } + + + return preprocessTemplates(this._addonTemplateFiles(tree), { + annotation: 'compileTemplates(' + this.name + ')', + registry: this.registry + }); + } +}; + +/** + Runs the addon tree through preprocessors. + + @private + @method compileAddon + @param {Tree} tree Addon file tree + @return {Tree} Compiled addon tree +*/ +Addon.prototype.compileAddon = function(tree) { + this._requireBuildPackages(); + + var reexported; + + var addonJs = this.processedAddonJsFiles(tree); + var templatesTree = this.compileTemplates(tree); + + var trees = [addonJs, templatesTree, reexported].filter(Boolean); + + return mergeTrees(trees, { + annotation: 'Addon#compileAddon(' + this.name + ') ' + }); +}; + +/** + Returns a tree with JSHhint output for all addon JS. + + @private + @method jshintAddonTree + @return {Tree} Tree with JShint output (tests) +*/ +Addon.prototype.jshintAddonTree = function() { + this._requireBuildPackages(); + + var addonPath = path.join(this.root, this.treePaths['addon']); + + if (!existsSync(addonPath)) { + return; + } + + var addonJs = this.addonJsFiles(addonPath); + var addonTemplates = this._addonTemplateFiles(addonPath); + var lintJsTrees = this._eachProjectAddonInvoke('lintTree', ['addon', addonJs]); + var lintTemplateTrees = this._eachProjectAddonInvoke('lintTree', ['templates', addonTemplates]); + var lintTrees = [].concat(lintJsTrees, lintTemplateTrees).filter(Boolean); + var lintedAddon = mergeTrees(lintTrees, { + overwrite: true, + annotation: 'TreeMerger (addon-lint)' + }); + + return new Funnel(lintedAddon, { + srcDir: '/', + destDir: this.name + '/tests/' + }); +}; + +/** + Returns a tree containing the addon's js files + + @private + @method addonJsFiles + @return {Tree} The filtered addon js files +*/ +Addon.prototype.addonJsFiles = function(tree) { + this._requireBuildPackages(); + + if (this._cachedAddonJsFiles) { + return this._cachedAddonJsFiles; + } + + var includePatterns = this.registry.extensionsForType('js').map(function(extension) { + return new RegExp(extension + '$'); + }); + + this._cachedAddonJsFiles = new Funnel(tree, { + include: includePatterns, + destDir: 'modules/' + this.moduleName(), + description: 'Funnel: Addon JS' + }); + + return this._cachedAddonJsFiles; +}; + + +/** + Preprocesses a javascript tree. + + @private + @method preprocessJs + @return {Tree} Preprocessed javascript +*/ +Addon.prototype.preprocessJs = function() { + return preprocessJs.apply(preprocessJs, arguments); +}; + +/** + Returns a tree with all javascript for this addon. + + @private + @method processedAddonJsFiles + @param {Tree} the tree to preprocess + @return {Tree} Processed javascript file tree +*/ +Addon.prototype.processedAddonJsFiles = function(tree) { + return this.preprocessJs(this.addonJsFiles(tree), '/', this.name, { + registry: this.registry + }); +}; + +/** + Returns the module name for this addon. + + @public + @method moduleName + @return {String} module name +*/ +Addon.prototype.moduleName = function() { + if (!this.modulePrefix) { + this.modulePrefix = (this.modulePrefix || this.name).toLowerCase().replace(/\s/g, '-'); + } + + return this.modulePrefix; +}; + +/** + Returns the path for addon blueprints. + + @private + @method blueprintsPath + @return {String} The path for blueprints +*/ +Addon.prototype.blueprintsPath = function() { + var blueprintPath = path.join(this.root, 'blueprints'); + + if (existsSync(blueprintPath)) { + return blueprintPath; + } +}; + +/** + Augments the applications configuration settings. + Object returned from this hook is merged with the application's configuration object. + Application's configuration always take precedence. + + + ```js + config: function(environment, appConfig) { + return { + someAddonDefault: "foo" + }; + } + ``` + + @public + @method config + @param {String} env Name of current environment (ie "developement") + @param {Object} baseConfig Initial application configuration + @return {Object} Configuration object to be merged with application configuration. +*/ +Addon.prototype.config = function (env, baseConfig) { + var configPath = path.join(this.root, 'config', 'environment.js'); + + if (existsSync(configPath)) { + var configGenerator = require(configPath); + + return configGenerator(env, baseConfig); + } +}; + +/** + @public + @method dependencies + @return {Object} The addon's dependencies based on the addon's package.json +*/ +Addon.prototype.dependencies = function() { + var pkg = this.pkg || {}; + return assign({}, pkg['devDependencies'], pkg['dependencies']); +}; + +/** + @public + @method isEnabled + @return {Boolean} Whether or not this addon is enabled +*/ +Addon.prototype.isEnabled = function() { + return true; +}; + +/** + @public + @method shouldIncludeChildAddon + @return {Boolean} Whether or not a child addon is supposed to be included +*/ +Addon.prototype.shouldIncludeChildAddon = function() { + return true; +}; + +/** + Returns the absolute path for a given addon + + @private + @method resolvePath + @param {String} addon Addon name + @return {String} Absolute addon path +*/ +Addon.resolvePath = function(addon) { + var addonMain = addon.pkg['ember-addon-main']; + + if (addonMain) { + this.ui && this.ui.writeDeprecateLine(addon.pkg.name + ' is using the deprecated ember-addon-main definition. It should be updated to {\'ember-addon\': {\'main\': \'' + addon.pkg['ember-addon-main'] + '\'}}'); + } else { + addonMain = (addon.pkg['ember-addon'] && addon.pkg['ember-addon'].main) || addon.pkg['main'] || 'index.js'; + } + + // Resolve will fail unless it has an extension + if (!path.extname(addonMain)) { + addonMain += '.js'; + } + + return path.resolve(addon.path, addonMain); +}; + +/** + Returns the addon class for a given addon name. + If the Addon exports a function, that function is used + as constructor. If an Object is exported, a subclass of + `Addon` is returned with the exported hash merged into it. + + @private + @static + @method lookup + @param {String} addon Addon name + @return {Addon} Addon class +*/ +Addon.lookup = function(addon) { + var Constructor, addonModule, modulePath, moduleDir; + + modulePath = Addon.resolvePath(addon); + moduleDir = path.dirname(modulePath); + + if (existsSync(modulePath)) { + addonModule = require(modulePath); + + if (typeof addonModule === 'function') { + Constructor = addonModule; + Constructor.prototype.root = Constructor.prototype.root || moduleDir; + Constructor.prototype.pkg = Constructor.prototype.pkg || addon.pkg; + } else { + Constructor = Addon.extend(assign({ + root: moduleDir, + pkg: addon.pkg + }, addonModule)); + } + } + + if (!Constructor) { + throw new SilentError('The `' + addon.pkg.name + '` addon could not be found at `' + addon.path + '`.'); + } + + return Constructor; +}; + + +// Methods without default implementation + +/** + CLI commands included with this addon. This function should return + an object with command names and command instances/create options. + + This function is not implemented by default + + ```js + includedCommands: function() { + return { + 'do-foo': require('./lib/commands/foo') + }; + } + ``` + + @public + @method includedCommands + @return {Object} An object with included commands +*/ + + +/** + Post-process a tree + + @public + @method postProcessTree + @param {String} type What kind of tree (eg. 'javascript', 'styles') + @param {Tree} Tree to process + @return {Tree} Processed tree +*/ + +/** + This hook allows you to make changes to the express server run by ember-cli. + It's passed an `startOptions` object which contains: + - `app` Express server instance + - `options` A hash with: + - `project` Current {{#crossLink "Project"}}project{{/crossLink}} + - `watcher` + - `environment` + + This function is not implemented by default + + ```js + serverMiddleware: function(startOptions) { + var app = startOptions.app; + + app.use(function(req, res, next) { + // Some middleware + }); + } + ``` + + @public + @method serverMiddleware + @param {Object} startOptions Express server start options +*/ + +/** + This hook is called before a build takes place. + + @public + @method preBuild + @param {Object} result Build object +*/ + +/** + This hook is called after a build is complete. + + It's passed an `result` object which contains: + - `directory` Path to build output + + @public + @method postBuild + @param {Object} result Build result object +*/ + +/** + This hook is called after the build files have been copied to the output directory + + It's passed an `result` object which contains: + - `directory` Path to build output + + @public + @method outputReady + @param {Object} result Build result object +*/ + +/** + This hook is called when an error occurs during the preBuild, postBuild or outputReady hooks + for addons, or when the build fails + + @public + @method buildError + @param {Error} error The error that was caught during the processes listed above +*/ + +module.exports = Addon; diff --git a/packages/ember-cli/lib/models/addons-factory.js b/packages/ember-cli/lib/models/addons-factory.js new file mode 100644 index 000000000000..eca484b1b85d --- /dev/null +++ b/packages/ember-cli/lib/models/addons-factory.js @@ -0,0 +1,66 @@ +'use strict'; + +/** +@module ember-cli +*/ + +var CoreObject = require('core-object'); +var DAG = require('../utilities/DAG'); +var debug = require('debug')('ember-cli:addons-factory'); + +/** + AddonsFactory is responsible for instantiating a collection of addons, in the right order. + + @class AddonsFactory + @extends CoreObject + @constructor +*/ +function AddonsFactory(addonParent, project) { + this.addonParent = addonParent; + this.project = project; +} + +AddonsFactory.__proto__ = CoreObject; +AddonsFactory.prototype.constructor = AddonsFactory; + +AddonsFactory.prototype.initializeAddons = function(addonPackages) { + var addonParent = this.addonParent; + var project = this.project; + var graph = new DAG(); + var Addon = require('../models/addon'); + var addonInfo, emberAddonConfig; + + debug('initializeAddons for: ', typeof addonParent.name === 'function' ? addonParent.name() : addonParent.name); + debug(' addon names are:', Object.keys(addonPackages)); + + for (var name in addonPackages) { + addonInfo = addonPackages[name]; + emberAddonConfig = addonInfo.pkg['ember-addon']; + + graph.addEdges(name, addonInfo, emberAddonConfig.before, emberAddonConfig.after); + } + + var addons = []; + graph.topsort(function (vertex) { + var addonInfo = vertex.value; + if (addonInfo) { + var AddonConstructor = Addon.lookup(addonInfo); + var addon = new AddonConstructor(addonParent, project); + if (addon.initializeAddons) { + addon.initializeAddons(); + } else { + addon.addons = []; + } + addons.push(addon); + } + }); + + debug(' addons ordered as:', addons.map(function(addon) { + return addon.name; + })); + + return addons; +}; + +// Export +module.exports = AddonsFactory; diff --git a/packages/ember-cli/lib/models/blueprint.js b/packages/ember-cli/lib/models/blueprint.js new file mode 100644 index 000000000000..b5f56fdb44e8 --- /dev/null +++ b/packages/ember-cli/lib/models/blueprint.js @@ -0,0 +1,1637 @@ +'use strict'; + +/** +@module ember-cli +*/ +var FileInfo = require('./file-info'); +var Promise = require('../ext/promise'); +var chalk = require('chalk'); +var MarkdownColor = require('../utilities/markdown-color'); +var printableProperties = require('../utilities/printable-properties').blueprint; +var sequence = require('../utilities/sequence'); +var printCommand = require('../utilities/print-command'); +var fs = require('fs-extra'); +var existsSync = require('exists-sync'); +var inflector = require('inflection'); +var minimatch = require('minimatch'); +var path = require('path'); +var stat = Promise.denodeify(fs.stat); +var stringUtils = require('ember-cli-string-utils'); +var compact = require('lodash/compact'); +var intersect = require('lodash/intersection'); +var uniq = require('lodash/uniq'); +var zipObject = require('lodash/zipObject'); +var includes = require('lodash/includes'); +var any = require('lodash/some'); +var cloneDeep = require('lodash/cloneDeep'); +var keys = require('lodash/keys'); +var merge = require('lodash/merge'); +var values = require('lodash/values'); +var walkSync = require('walk-sync'); +var writeFile = Promise.denodeify(fs.outputFile); +var removeFile = Promise.denodeify(fs.remove); +var SilentError = require('silent-error'); +var CoreObject = require('core-object'); +var EOL = require('os').EOL; +var debug = require('debug')('ember-cli:blueprint'); +var normalizeEntityName = require('ember-cli-normalize-entity-name'); + +module.exports = Blueprint; + +/** + A blueprint is a bundle of template files with optional install + logic. + + Blueprints follow a simple structure. Let's take the built-in + `controller` blueprint as an example: + + ``` + blueprints/controller + ├── files + │ ├── app + │ │ └── __path__ + │ │ └── __name__.js + └── index.js + + blueprints/controller-test + ├── files + │ └── tests + │ └── unit + │ └── controllers + │ └── __test__.js + └── index.js + ``` + + ## Files + + `files` contains templates for the all the files to be + installed into the target directory. + + The `__name__` token is subtituted with the dasherized + entity name at install time. For example, when the user + invokes `ember generate controller foo` then `__name__` becomes + `foo`. When the `--pod` flag is used, for example `ember + generate controller foo --pod` then `__name__` becomes + `controller`. + + The `__path__` token is substituted with the blueprint + name at install time. For example, when the user invokes + `ember generate controller foo` then `__path__` becomes + `controller`. When the `--pod` flag is used, for example + `ember generate controller foo --pod` then `__path__` + becomes `foo` (or `/foo` if the + podModulePrefix is defined). This token is primarily for + pod support, and is only necessary if the blueprint can be + used in pod structure. If the blueprint does not require pod + support, simply use the blueprint name instead of the + `__path__` token. + + The `__test__` token is substituted with the dasherized + entity name and appended with `-test` at install time. + This token is primarily for pod support and only necessary + if the blueprint requires support for a pod structure. If + the blueprint does not require pod support, simply use the + `__name__` token instead. + + ## Template Variables (AKA Locals) + + Variables can be inserted into templates with + `<%= someVariableName %>`. + + For example, the built-in `util` blueprint + `files/app/utils/__name__.js` looks like this: + + ```js + export default function <%= camelizedModuleName %>() { + return true; + } + ``` + + `<%= camelizedModuleName %>` is replaced with the real + value at install time. + + The following template variables are provided by default: + + - `dasherizedPackageName` + - `classifiedPackageName` + - `dasherizedModuleName` + - `classifiedModuleName` + - `camelizedModuleName` + + `packageName` is the project name as found in the project's + `package.json`. + + `moduleName` is the name of the entity being generated. + + The mechanism for providing custom template variables is + described below. + + ## Index.js + + Custom installation and uninstallation behaviour can be added + by overriding the hooks documented below. `index.js` should + export a plain object, which will extend the prototype of the + `Blueprint` class. If needed, the original `Blueprint` prototype + can be accessed through the `_super` property. + + ```js + module.exports = { + locals: function(options) { + // Return custom template variables here. + return {}; + }, + + normalizeEntityName: function(entityName) { + // Normalize and validate entity name here. + return entityName; + }, + + fileMapTokens: function(options) ( + // Return custom tokens to be replaced in your files + return { + __token__: function(options){ + // logic to determine value goes here + return 'value'; + } + } + }, + + filesPath: function(options) { + return path.join(this.path, 'files'); + }, + + beforeInstall: function(options) {}, + afterInstall: function(options) {}, + beforeUninstall: function(options) {}, + afterUninstall: function(options) {} + + }; + ``` + + ## Blueprint Hooks + + As shown above, the following hooks are available to + blueprint authors: + + - `locals` + - `normalizeEntityName` + - `fileMapTokens` + - `filesPath` + - `beforeInstall` + - `afterInstall` + - `beforeUninstall` + - `afterUninstall` + + ### locals + + Use `locals` to add custom tempate variables. The method + receives one argument: `options`. Options is an object + containing general and entity-specific options. + + When the following is called on the command line: + + ```sh + ember generate controller foo --type=array --dry-run + ``` + + The object passed to `locals` looks like this: + + ```js + { + entity: { + name: 'foo', + options: { + type: 'array' + } + }, + dryRun: true + } + ``` + + This hook must return an object or a Promise which resolves to an object. + The resolved object will be merged with the aforementioned default locals. + + ### normalizeEntityName + + Use the `normalizeEntityName` hook to add custom normalization and + validation of the provided entity name. The default hook does not + make any changes to the entity name, but makes sure an entity name + is present and that it doesn't have a trailing slash. + + This hook receives the entity name as its first argument. The string + returned by this hook will be used as the new entity name. + + ### fileMapTokens + + Use `fileMapTokens` to add custom fileMap tokens for use + in the `mapFile` method. The hook must return an object in the + following pattern: + + ```js + { + __token__: function(options){ + // logic to determine value goes here + return 'value'; + } + } + ``` + + It will be merged with the default `fileMapTokens`, and can be used + to override any of the default tokens. + + Tokens are used in the files folder (see `files`), and get replaced with + values when the `mapFile` method is called. + + ### filesPath + + Use `filesPath` to define where the blueprint files to install are located. + This can be used to customize which set of files to install based on options + or environmental variables. It defaults to the `files` directory within the + blueprint's folder. + + ### beforeInstall & beforeUninstall + + Called before any of the template files are processed and receives + the the `options` and `locals` hashes as parameters. Typically used for + validating any additional command line options or for any asynchronous + setup that is needed. As an example, the `controller` blueprint validates + its `--type` option in this hook. If you need to run any asynchronous code, + wrap it in a promise and return that promise from these hooks. This will + ensure that your code is executed correctly. + + ### afterInstall & afterUninstall + + The `afterInstall` and `afterUninstall` hooks receives the same + arguments as `locals`. Use it to perform any custom work after the + files are processed. For example, the built-in `route` blueprint + uses these hooks to add and remove relevant route declarations in + `app/router.js`. + + ### Overriding Install + + If you don't want your blueprint to install the contents of + `files` you can override the `install` method. It receives the + same `options` object described above and must return a promise. + See the built-in `resource` blueprint for an example of this. + + @class Blueprint + @constructor + @extends CoreObject + @param {String} [blueprintPath] +*/ +function Blueprint(blueprintPath) { + this.path = blueprintPath; + this.name = path.basename(blueprintPath); +} + +Blueprint.__proto__ = CoreObject; +Blueprint.prototype.constructor = Blueprint; + +Blueprint.prototype.availableOptions = []; +Blueprint.prototype.anonymousOptions = ['name']; + +/** + Hook to specify the path to the blueprint's files. By default this is + `path.join(this.path, 'files)`. + + @method filesPath + @param {Object} options + @return {String} Path to the blueprints files directory. +*/ + +Blueprint.prototype.filesPath = function() { + return path.join(this.path, 'files'); +}; + +/** + Used to retrieve files for blueprint. The `file` param is an + optional string that is turned into a glob. + + @method files + @return {Array} Contents of the blueprint's files directory +*/ +Blueprint.prototype.files = function() { + if (this._files) { return this._files; } + + var filesPath = this.filesPath(this.options); + if (existsSync(filesPath)) { + this._files = walkSync(filesPath); + } else { + this._files = []; + } + + return this._files; +}; + +/** + @method srcPath + @param {String} file + @return {String} Resolved path to the file +*/ +Blueprint.prototype.srcPath = function(file) { + return path.resolve(this.filesPath(this.options), file); +}; + +/** + Hook for normalizing entity name + @method normalizeEntityName + @param {String} entityName + @return {null} +*/ +Blueprint.prototype.normalizeEntityName = function(entityName) { + return normalizeEntityName(entityName); +}; + +/** + Write a status and message to the UI + @private + @method _writeStatusToUI + @param {Function} chalkColor + @param {String} keyword + @param {String} message +*/ +Blueprint.prototype._writeStatusToUI = function(chalkColor, keyword, message) { + if (this.ui) { + this.ui.writeLine(' ' + chalkColor(keyword) + ' ' + message); + } +}; + +/** + @private + @method _writeFile + @param {Object} info + @return {Promise} +*/ +Blueprint.prototype._writeFile = function(info) { + if (!this.dryRun) { + return writeFile(info.outputPath, info.render()); + } +}; + +/** + Actions lookup + @private +*/ + +Blueprint.prototype._actions = { + write: function(info) { + this._writeStatusToUI(chalk.green, 'create', info.displayPath); + return this._writeFile(info); + }, + skip: function(info) { + var label = 'skip'; + + if (info.resolution === 'identical') { + label = 'identical'; + } + + this._writeStatusToUI(chalk.yellow, label, info.displayPath); + }, + + overwrite: function(info) { + this._writeStatusToUI(chalk.yellow, 'overwrite', info.displayPath); + return this._writeFile(info); + }, + + edit: function(info) { + this._writeStatusToUI(chalk.green, 'edited', info.displayPath); + }, + + remove: function(info) { + this._writeStatusToUI(chalk.red, 'remove', info.displayPath); + if (!this.dryRun) { + return removeFile(info.outputPath); + } + } +}; + +/** + Calls an action. + @private + @method _commit + @param {Object} result + @return {Promise} + @throws {Error} Action doesn't exist. +*/ +Blueprint.prototype._commit = function(result) { + var action = this._actions[result.action]; + + if (action) { + return action.call(this, result); + } else { + throw new Error('Tried to call action \"' + result.action + '\" but it does not exist'); + } +}; + +/** + Prints warning for pod unsupported. + @private + @method _checkForPod +*/ +Blueprint.prototype._checkForPod = function(verbose) { + if (!this.hasPathToken && this.pod && verbose) { + this.ui.writeLine(chalk.yellow('You specified the pod flag, but this' + + ' blueprint does not support pod structure. It will be generated with' + + ' the default structure.')); + } +}; + +/** + @private + @method _normalizeEntityName + @param {Object} entity +*/ +Blueprint.prototype._normalizeEntityName = function(entity) { + if (entity) { + entity.name = this.normalizeEntityName(entity.name); + } +}; + +/** + @private + @method _checkInRepoAddonExists + @param {String} inRepoAddon +*/ +Blueprint.prototype._checkInRepoAddonExists = function(inRepoAddon) { + if (inRepoAddon) { + if (!inRepoAddonExists(inRepoAddon, this.project.root)) { + throw new SilentError('You specified the in-repo-addon flag, but the' + + ' in-repo-addon \'' + inRepoAddon + '\' does not exist. Please' + + ' check the name and try again.'); + } + } +}; + +/** + @private + @method _process + @param {Object} options + @param {Function} beforeHook + @param {Function} process + @param {Function} afterHook +*/ +Blueprint.prototype._process = function(options, beforeHook, process, afterHook) { + var self = this; + var intoDir = options.target; + + return this._locals(options).then(function (locals) { + return Promise.resolve() + .then(beforeHook.bind(self, options, locals)) + .then(process.bind(self, intoDir, locals)).map(self._commit.bind(self)) + .then(afterHook.bind(self, options)); + }); +}; + +/** + @method install + @param {Object} options + @return {Promise} +*/ +Blueprint.prototype.install = function(options) { + var ui = this.ui = options.ui; + var dryRun = this.dryRun = options.dryRun; + this.project = options.project; + this.pod = options.pod; + this.options = options; + this.hasPathToken = hasPathToken(this.files()); + + podDeprecations(this.project.config(), ui); + + ui.writeLine('installing ' + this.name); + + if (dryRun) { + ui.writeLine(chalk.yellow('You specified the dry-run flag, so no' + + ' changes will be written.')); + } + + this._normalizeEntityName(options.entity); + this._checkForPod(options.verbose); + this._checkInRepoAddonExists(options.inRepoAddon); + + debug('START: processing blueprint: `%s`', this.name); + var start = new Date(); + return this._process( + options, + this.beforeInstall, + this.processFiles, + this.afterInstall).finally(function() { + debug('END: processing blueprint: `%s` in (%dms)', this.name, new Date() - start); + }.bind(this)); +}; + +/** + @method uninstall + @param {Object} options + @return {Promise} +*/ +Blueprint.prototype.uninstall = function(options) { + var ui = this.ui = options.ui; + var dryRun = this.dryRun = options.dryRun; + this.project = options.project; + this.pod = options.pod; + this.options = options; + this.hasPathToken = hasPathToken(this.files()); + + podDeprecations(this.project.config(), ui); + + ui.writeLine('uninstalling ' + this.name); + + if (dryRun) { + ui.writeLine(chalk.yellow('You specified the dry-run flag, so no' + + ' files will be deleted.')); + } + + this._normalizeEntityName(options.entity); + this._checkForPod(options.verbose); + + return this._process( + options, + this.beforeUninstall, + this.processFilesForUninstall, + this.afterUninstall); +}; + +/** + Hook for running operations before install. + @method beforeInstall + @return {Promise|null} +*/ +Blueprint.prototype.beforeInstall = function() {}; + +/** + Hook for running operations after install. + @method afterInstall + @return {Promise|null} +*/ +Blueprint.prototype.afterInstall = function() {}; + +/** + Hook for running operations before uninstall. + @method beforeUninstall + @return {Promise|null} +*/ +Blueprint.prototype.beforeUninstall = function() {}; + +/** + Hook for running operations after uninstall. + @method afterUninstall + @return {Promise|null} +*/ +Blueprint.prototype.afterUninstall = function() {}; + +/** + Hook for adding additional locals + @method locals + @return {Object|null} +*/ +Blueprint.prototype.locals = function() {}; + +/** + Hook to add additional or override existing fileMapTokens. + @method fileMapTokens + @return {Object|null} +*/ +Blueprint.prototype.fileMapTokens = function() { +}; + +/** + @private + @method _fileMapTokens + @param {Object} options + @return {Object} +*/ +Blueprint.prototype._fileMapTokens = function(options) { + var standardTokens = { + __name__: function(options) { + if (options.pod && options.hasPathToken) { + return options.blueprintName; + } + return options.dasherizedModuleName; + }, + __path__: function(options) { + var blueprintName = options.blueprintName; + + if (blueprintName.match(/-test/)) { + blueprintName = options.blueprintName.slice(0, options.blueprintName.indexOf('-test')); + } + if (options.pod && options.hasPathToken) { + return path.join(options.podPath, options.dasherizedModuleName); + } + return inflector.pluralize(blueprintName); + }, + __root__: function(options) { + if (options.inRepoAddon) { + return path.join('lib',options.inRepoAddon, 'addon'); + } + if (options.inDummy) { + return path.join('tests','dummy','app'); + } + if (options.inAddon) { + return 'addon'; + } + return 'app'; + }, + __test__: function(options) { + if (options.pod && options.hasPathToken) { + return options.blueprintName; + } + return options.dasherizedModuleName + '-test'; + } + }; + + var customTokens = this.fileMapTokens(options) || options.fileMapTokens || {}; + return merge(standardTokens, customTokens); +}; + +/** + Used to generate fileMap tokens for mapFile. + + @method generateFileMap + @param {Object} fileMapVariables + @return {Object} +*/ +Blueprint.prototype.generateFileMap = function(fileMapVariables) { + var tokens = this._fileMapTokens(fileMapVariables); + var fileMapValues = values(tokens); + var tokenValues = fileMapValues.map(function(token) { return token(fileMapVariables); }); + var tokenKeys = keys(tokens); + return zipObject(tokenKeys,tokenValues); +}; + +/** + @method buildFileInfo + @param {Function} destPath + @param {Object} templateVariables + @param {String} file + @return {FileInfo} +*/ +Blueprint.prototype.buildFileInfo = function(destPath, templateVariables, file) { + var mappedPath = this.mapFile(file, templateVariables); + + return new FileInfo({ + action: 'write', + outputPath: destPath(mappedPath), + displayPath: path.normalize(mappedPath), + inputPath: this.srcPath(file), + templateVariables: templateVariables, + ui: this.ui + }); +}; + +/** + @method isUpdate + @return {Boolean} +*/ +Blueprint.prototype.isUpdate = function() { + if (this.project && this.project.isEmberCLIProject) { + return this.project.isEmberCLIProject(); + } +}; + +/** + @private + @method _getFileInfos + @param {Array} files + @param {String} intoDir + @param {Object} templateVariables + @return {Array} file infos +*/ +Blueprint.prototype._getFileInfos = function(files, intoDir, templateVariables) { + return files.map(this.buildFileInfo.bind(this, destPath.bind(null, intoDir), templateVariables)); +}; + +/** + Add update files to ignored files + @private + @method _ignoreUpdateFiles +*/ +Blueprint.prototype._ignoreUpdateFiles = function() { + if (this.isUpdate()) { + Blueprint.ignoredFiles = Blueprint.ignoredFiles.concat(Blueprint.ignoredUpdateFiles); + } +}; + +/** + @private + @method _getFilesForInstall + @param {Array} targetFiles + @return {Array} files +*/ +Blueprint.prototype._getFilesForInstall = function(targetFiles) { + var files = this.files(); + + // if we've defined targetFiles, get file info on ones that match + return targetFiles && targetFiles.length > 0 && intersect(files, targetFiles) || files; +}; + +/** + @private + @method _checkForNoMatch + @param {Array} fileInfos + @param {String} rawArgs +*/ +Blueprint.prototype._checkForNoMatch = function(fileInfos, rawArgs) { + if (fileInfos.filter(isFilePath).length < 1 && rawArgs) { + this.ui.writeLine(chalk.yellow('The globPattern \"' + rawArgs + + '\" did not match any files, so no file updates will be made.')); + } +}; + +function finishProcessingForInstall(infos) { + infos.forEach(markIdenticalToBeSkipped); + + var infosNeedingConfirmation = infos.reduce(gatherConfirmationMessages, []); + + return sequence(infosNeedingConfirmation).returns(infos); +} + +function finishProcessingForUninstall(infos) { + infos.forEach(markToBeRemoved); + return infos; +} + +/** + @method processFiles + @param {String} intoDir + @param {Object} templateVariables +*/ +Blueprint.prototype.processFiles = function(intoDir, templateVariables) { + var files = this._getFilesForInstall(templateVariables.targetFiles); + var fileInfos = this._getFileInfos(files, intoDir, templateVariables); + this._checkForNoMatch(fileInfos, templateVariables.rawArgs); + + this._ignoreUpdateFiles(); + + return Promise.filter(fileInfos, isValidFile). + map(prepareConfirm). + then(finishProcessingForInstall); +}; + +/** + @method processFilesForUninstall + @param {String} intoDir + @param {Object} templateVariables +*/ +Blueprint.prototype.processFilesForUninstall = function(intoDir, templateVariables) { + var fileInfos = this._getFileInfos(this.files(), intoDir, templateVariables); + + this._ignoreUpdateFiles(); + + return Promise.filter(fileInfos, isValidFile). + then(finishProcessingForUninstall); +}; + + +/** + @method mapFile + @param {String} file + @return {String} +*/ +Blueprint.prototype.mapFile = function(file, locals) { + var pattern, i; + var fileMap = locals.fileMap || { __name__: locals.dasherizedModuleName }; + file = Blueprint.renamedFiles[file] || file; + for (i in fileMap) { + pattern = new RegExp(i, 'g'); + file = file.replace(pattern, fileMap[i]); + } + return file; +}; + +/** + Looks for a __root__ token in the files folder. Must be present for + the blueprint to support addon tokens. The `server`, `blueprints`, and `test` + + @private + @method supportsAddon + @return {Boolean} +*/ +Blueprint.prototype.supportsAddon = function() { + return this.files().join().match(/__root__/); +}; + +/** + @private + @method _generateFileMapVariables + @param {Object} options + @return {Object} +*/ +Blueprint.prototype._generateFileMapVariables = function(moduleName, locals, options) { + var originBlueprintName = options.originBlueprintName || this.name; + var podModulePrefix = this.project.config().podModulePrefix || ''; + var podPath = podModulePrefix.substr(podModulePrefix.lastIndexOf('/') + 1); + var inAddon = this.project.isEmberCLIAddon() || !!options.inRepoAddon; + var inDummy = this.project.isEmberCLIAddon() ? options.dummy : false; + + return { + pod: this.pod, + podPath: podPath, + hasPathToken: this.hasPathToken, + inAddon: inAddon, + inRepoAddon: options.inRepoAddon, + inDummy: inDummy, + blueprintName: this.name, + originBlueprintName: originBlueprintName, + dasherizedModuleName: stringUtils.dasherize(moduleName), + locals: locals + }; +}; + +/** + @private + @method _locals + @param {Object} options + @return {Object} +*/ +Blueprint.prototype._locals = function(options) { + var packageName = options.project.name(); + var moduleName = options.entity && options.entity.name || packageName; + var sanitizedModuleName = moduleName.replace(/\//g, '-'); + + return new Promise(function(resolve) { + resolve(this.locals(options)); + }.bind(this)).then(function (customLocals) { + var fileMapVariables = this._generateFileMapVariables(moduleName, customLocals, options); + var fileMap = this.generateFileMap(fileMapVariables); + var standardLocals = { + dasherizedPackageName: stringUtils.dasherize(packageName), + classifiedPackageName: stringUtils.classify(packageName), + dasherizedModuleName: stringUtils.dasherize(moduleName), + classifiedModuleName: stringUtils.classify(sanitizedModuleName), + camelizedModuleName: stringUtils.camelize(sanitizedModuleName), + decamelizedModuleName: stringUtils.decamelize(sanitizedModuleName), + fileMap: fileMap, + hasPathToken: this.hasPathToken, + targetFiles: options.targetFiles, + rawArgs: options.rawArgs + }; + + return merge({}, standardLocals, customLocals); + }.bind(this)); +}; + +/** + Used to add a package to the project's `package.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + @method addPackageToProject + @param {String} packageName + @param {String} target + @return {Promise} +*/ +Blueprint.prototype.addPackageToProject = function(packageName, target) { + var packageObject = {name: packageName}; + + if (target) { + packageObject.target = target; + } + + return this.addPackagesToProject([packageObject]); +}; + +/** + Used to add multiple packages to the project's `package.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + Expects each array item to be an object with a `name`. Each object + may optionally have a `target` to specify a specific version. + + @method addPackagesToProject + @param {Array} packages + @return {Promise} +*/ +Blueprint.prototype.addPackagesToProject = function(packages) { + var task = this.taskFor('npm-install'); + var installText = (packages.length > 1) ? 'install packages' : 'install package'; + var packageNames = []; + var packageArray = []; + + for (var i = 0; i < packages.length; i++) { + packageNames.push(packages[i].name); + + var packageNameAndVersion = packages[i].name; + + if (packages[i].target) { + packageNameAndVersion += '@' + packages[i].target; + } + + packageArray.push(packageNameAndVersion); + } + + this._writeStatusToUI(chalk.green, installText, packageNames.join(', ')); + + return task.run({ + 'save-dev': true, + verbose: false, + packages: packageArray + }); +}; + +/** + Used to remove a package from the project's `package.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that any package conflicts can be resolved before the + addon is used. + + @method removePackageFromProject + @param {String} packageName + @return {Promise} +*/ +Blueprint.prototype.removePackageFromProject = function(packageName) { + var packageObject = {name: packageName}; + + return this.removePackagesFromProject([packageObject]); +}; + +/** + Used to remove multiple packages from the project's `package.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that any package conflicts can be resolved before the + addon is used. + + Expects each array item to be an object with a `name` property. + + @method removePackagesFromProject + @param {Array} packages + @return {Promise} +*/ +Blueprint.prototype.removePackagesFromProject = function(packages) { + var task = this.taskFor('npm-uninstall'); + var installText = (packages.length > 1) ? 'uninstall packages' : 'uninstall package'; + var packageNames = []; + var packageArray = []; + + for (var i = 0; i < packages.length; i++) { + packageNames.push(packages[i].name); + + var packageNameAndVersion = packages[i].name; + + packageArray.push(packageNameAndVersion); + } + + this._writeStatusToUI(chalk.green, installText, packageNames.join(', ')); + + return task.run({ + 'save-dev': true, + verbose: false, + packages: packageArray + }); +}; + +/** + Used to add a package to the projects `bower.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + `localPackageName` and `target` may be thought of as equivalent + to the key-value pairs in the `dependency` or `devDepencency` + objects contained within a bower.json file. + + Examples: + + addBowerPackageToProject('jquery', '~1.11.1'); + addBowerPackageToProject('old_jquery', 'jquery#~1.9.1'); + addBowerPackageToProject('bootstrap-3', 'http://twitter.github.io/bootstrap/assets/bootstrap'); + + @method addBowerPackageToProject + @param {String} localPackageName + @param {String} target + @param {Object} installOptions + @return {Promise} +*/ +Blueprint.prototype.addBowerPackageToProject = function(localPackageName, target, installOptions) { + // var lpn = localPackageName; + // var tar = target; + // if (localPackageName.indexOf('#') >= 0) { + // if (arguments.length === 1) { + // var parts = localPackageName.split('#'); + // lpn = parts[0]; + // tar = parts[1]; + // this.ui.writeDeprecateLine('passing ' + localPackageName + + // ' directly to `addBowerPackageToProject` will soon be unsupported. \n' + + // 'You may want to replace this with ' + + // '`addBowerPackageToProject(\'' + lpn + '\', \'' + tar + '\')`'); + // } else { + // this.ui.writeDeprecateLine('passing ' + localPackageName + + // ' directly to `addBowerPackageToProject` will soon be unsupported'); + // } + // } + // var packageObject = bowEpParser.json2decomposed(lpn, tar); + // return this.addBowerPackagesToProject([packageObject], installOptions); + return Promise.resolve(); +}; + +/** + Used to add an array of packages to the projects `bower.json`. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + Expects each array item to be an object with a `name`. Each object + may optionally have a `target` to specify a specific version. + + @method addBowerPackagesToProject + @param {Array} packages + @param {Object} installOptions + @return {Promise} +*/ +Blueprint.prototype.addBowerPackagesToProject = function(packages, installOptions) { + var task = this.taskFor('bower-install'); + var installText = (packages.length > 1) ? 'install bower packages' : 'install bower package'; + var packageNames = []; + var packageNamesAndVersions = packages.map(function (pkg) { + pkg.source = pkg.source || pkg.name; + packageNames.push(pkg.name); + return pkg; + }).map(bowEpParser.compose); + + this._writeStatusToUI(chalk.green, installText, packageNames.join(', ')); + + return task.run({ + verbose: true, + packages: packageNamesAndVersions, + installOptions: installOptions + }); +}; + +/** + Used to add an addon to the project's `package.json` and run it's + `defaultBlueprint` if it provides one. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + @method addAddonToProject + @param {Object} options + @return {Promise} +*/ +Blueprint.prototype.addAddonToProject = function(options) { + return this.addAddonsToProject({ + packages: [options], + extraArgs: options.extraArgs || {}, + blueprintOptions: options.blueprintOptions || {} + }); +}; + +/** + Used to add multiple addons to the project's `package.json` and run their + `defaultBlueprint` if they provide one. + + Generally, this would be done from the `afterInstall` hook, to + ensure that a package that is required by a given blueprint is + available. + + @method addAddonsToProject + @param {Object} options + @return {Promise} +*/ +Blueprint.prototype.addAddonsToProject = function (options) { + var taskOptions = { + packages: [], + extraArgs: options.extraArgs || [], + blueprintOptions: options.blueprintOptions || {} + }; + + var packages = options.packages; + if (packages && packages.length) { + taskOptions.packages = packages.map(function (pkg) { + if (typeof pkg === 'string') { + return pkg; + } + + if (!pkg.name) { + throw new SilentError('You must provide a package `name` to addAddonsToProject'); + } + + if (pkg.target) { + pkg.name += '@' + pkg.target; + } + + return pkg.name; + }); + } else { + throw new SilentError('You must provide package to addAddonsToProject'); + } + + var installText = (packages.length > 1) ? 'install addons' : 'install addon'; + this._writeStatusToUI(chalk.green, installText, taskOptions['packages'].join(', ')); + + return this.taskFor('addon-install').run(taskOptions); +}; + +/** + Used to retrieve a task with the given name. Passes the new task + the standard information available (like `ui`, `analytics`, `project`, etc). + + @method taskFor + @param dasherizedName + @public +*/ +Blueprint.prototype.taskFor = function(dasherizedName) { + var Task = require('../tasks/' + dasherizedName); + + return new Task({ + ui: this.ui, + project: this.project, + analytics: this.analytics + }); +}; + +/* + + Inserts the given content into a file. If the `contentsToInsert` string is already + present in the current contents, the file will not be changed unless `force` option + is passed. + + If `options.before` is specified, `contentsToInsert` will be inserted before + the first instance of that string. If `options.after` is specified, the + contents will be inserted after the first instance of that string. + If the string specified by options.before or options.after is not in the file, + no change will be made. + + If neither `options.before` nor `options.after` are present, `contentsToInsert` + will be inserted at the end of the file. + + Example: + ``` + // app/router.js + Router.map(function() { + }); + + insertIntoFile('app/router.js', + ' this.route("admin");', + {after:'Router.map(function() {'+EOL}); + + // new app/router.js + Router.map(function() { + this.route("admin"); + }); + ``` + + @method insertIntoFile + @param {String} pathRelativeToProjectRoot + @param {String} contentsToInsert + @param {Object} options + @return {Promise} +*/ +Blueprint.prototype.insertIntoFile = function(pathRelativeToProjectRoot, contentsToInsert, providedOptions) { + var fullPath = path.join(this.project.root, pathRelativeToProjectRoot); + var originalContents = ''; + + if (existsSync(fullPath)) { + originalContents = fs.readFileSync(fullPath, { encoding: 'utf8' }); + } + + var contentsToWrite = originalContents; + + var options = providedOptions || {}; + var alreadyPresent = originalContents.indexOf(contentsToInsert) > -1; + var insert = !alreadyPresent; + var insertBehavior = 'end'; + + if (options.before) { insertBehavior = 'before'; } + if (options.after) { insertBehavior = 'after'; } + + if (options.force) { insert = true; } + + if (insert) { + if (insertBehavior === 'end') { + contentsToWrite += contentsToInsert; + } else { + var contentMarker = options[insertBehavior]; + var contentMarkerIndex = contentsToWrite.indexOf(contentMarker); + + if (contentMarkerIndex !== -1) { + var insertIndex = contentMarkerIndex; + if (insertBehavior === 'after') { insertIndex += contentMarker.length; } + + contentsToWrite = contentsToWrite.slice(0, insertIndex) + + contentsToInsert + EOL + + contentsToWrite.slice(insertIndex); + } + } + } + + var returnValue = { + path: fullPath, + originalContents: originalContents, + contents: contentsToWrite, + inserted: false + }; + + if (contentsToWrite !== originalContents) { + returnValue.inserted = true; + + return writeFile(fullPath, contentsToWrite) + .then(function() { + return returnValue; + }); + } else { + return Promise.resolve(returnValue); + } +}; + +Blueprint.prototype._printCommand = printCommand; + +Blueprint.prototype.printBasicHelp = function(verbose) { + var initialMargin = ' '; + var output = initialMargin; + if (this.overridden) { + output += chalk.grey('(overridden) ' + this.name); + } else { + output += this.name; + + output += this._printCommand(initialMargin, true); + + if (verbose) { + output += EOL + this.printDetailedHelp(this.availableOptions); + } + } + + return output; +}; + +Blueprint.prototype.printDetailedHelp = function() { + var markdownColor = new MarkdownColor(); + var filePath = getDetailedHelpPath(this.path); + + if (existsSync(filePath)) { + return markdownColor.renderFile(filePath, { indent: ' ' }); + } + return ''; +}; + +Blueprint.prototype.getJson = function(verbose) { + var json = {}; + + printableProperties.forEachWithProperty(function(key) { + var value = this[key]; + if (key === 'availableOptions') { + value = cloneDeep(value); + value.forEach(function(option) { + if (typeof option.type === 'function') { + option.type = option.type.name; + } + }); + } + json[key] = value; + }, this); + + if (verbose) { + var detailedHelp = this.printDetailedHelp(this.availableOptions); + if (detailedHelp) { + json.detailedHelp = detailedHelp; + } + } + + return json; +}; + +/** + Used to retrieve a blueprint with the given name. + + @method lookupBlueprint + @param dasherizedName + @public +*/ +Blueprint.prototype.lookupBlueprint = function(dasherizedName) { + var projectPaths = this.project ? this.project.blueprintLookupPaths() : []; + + return Blueprint.lookup(dasherizedName, { + paths: projectPaths + }); +}; + +/** + @static + @method lookup + @namespace Blueprint + @param {String} [name] + @param {Object} [options] + @param {Array} [options.paths] Extra paths to search for blueprints + @param {Object} [options.properties] Properties + @return {Blueprint} +*/ +Blueprint.lookup = function(name, options) { + options = options || {}; + + var lookupPaths = generateLookupPaths(options.paths); + + var lookupPath; + var blueprintPath; + + for (var i = 0; (lookupPath = lookupPaths[i]); i++) { + blueprintPath = path.resolve(lookupPath, name); + + if (existsSync(blueprintPath)) { + return Blueprint.load(blueprintPath); + } + } + + if (!options.ignoreMissing) { + throw new SilentError('Unknown blueprint: ' + name); + } +}; + +/** + Loads a blueprint from given path. + @static + @method load + @namespace Blueprint + @param {String} blueprintPath + @return {Blueprint} blueprint instance +*/ +Blueprint.load = function(blueprintPath) { + var constructorPath = path.resolve(blueprintPath, 'index.js'); + var blueprintModule; + var Constructor = Blueprint; + + if (fs.lstatSync(blueprintPath).isDirectory()) { + + if (existsSync(constructorPath)) { + blueprintModule = require(constructorPath); + + if (typeof blueprintModule === 'function') { + Constructor = blueprintModule; + } else { + Constructor = Blueprint.extend(blueprintModule); + } + } + + return new Constructor(blueprintPath); + } + + return; +}; + +/** + @static + @method list + @namespace Blueprint + @param {Object} [options] + @param {Array} [options.paths] Extra paths to search for blueprints + @return {Blueprint} +*/ +Blueprint.list = function(options) { + options = options || {}; + + var lookupPaths = generateLookupPaths(options.paths); + var seen = []; + + return lookupPaths.map(function(lookupPath) { + var blueprints = dir(lookupPath); + var packagePath = path.join(lookupPath, '../package.json'); + var source; + + if (existsSync(packagePath)) { + source = require(packagePath).name; + } else { + source = path.basename(path.join(lookupPath, '..')); + } + + blueprints = blueprints.map(function(blueprintPath) { + var blueprint = Blueprint.load(blueprintPath); + var name; + + if (blueprint) { + name = blueprint.name; + blueprint.overridden = includes(seen, name); + seen.push(name); + + return blueprint; + } + + return; + }); + + return { + source: source, + blueprints: compact(blueprints) + }; + }); +}; + +/** + @static + @property renameFiles +*/ +Blueprint.renamedFiles = { + 'gitignore': '.gitignore' +}; + +/** + @static + @property ignoredFiles +*/ +Blueprint.ignoredFiles = [ + '.DS_Store' +]; + +/** + @static + @property ignoredUpdateFiles +*/ +Blueprint.ignoredUpdateFiles = [ + '.gitkeep', + 'app.css' +]; + +/** + @static + @property defaultLookupPaths +*/ +Blueprint.defaultLookupPaths = function() { + return [ + path.resolve(__dirname, '..', '..', 'blueprints') + ]; +}; + +/** + @private + @method prepareConfirm + @param {FileInfo} info + @return {Promise} +*/ +function prepareConfirm(info) { + return info.checkForConflict().then(function(resolution) { + info.resolution = resolution; + return info; + }); +} + +/** + @private + @method markIdenticalToBeSkipped + @param {FileInfo} info +*/ +function markIdenticalToBeSkipped(info) { + if (info.resolution === 'identical') { + info.action = 'skip'; + } +} + +/** + @private + @method markToBeRemoved + @param {FileInfo} info +*/ +function markToBeRemoved(info) { + info.action = 'remove'; +} + +/** + @private + @method gatherConfirmationMessages + @param {Array} collection + @param {FileInfo} info + @return {Array} +*/ +function gatherConfirmationMessages(collection, info) { + if (info.resolution === 'confirm') { + collection.push(info.confirmOverwriteTask()); + } + return collection; +} + +/** + @private + @method isFile + @param {FileInfo} info + @return {Boolean} +*/ +function isFile(info) { + return stat(info.inputPath).invoke('isFile'); +} + +/** + @private + @method isIgnored + @param {FileInfo} info + @return {Boolean} +*/ +function isIgnored(info) { + var fn = info.inputPath; + + return any(Blueprint.ignoredFiles, function(ignoredFile) { + return minimatch(fn, ignoredFile, { matchBase: true }); + }); +} + +/** + Combines provided lookup paths with defaults and removes + duplicates. + + @private + @method generateLookupPaths + @param {Array} lookupPaths + @return {Array} +*/ +function generateLookupPaths(lookupPaths) { + lookupPaths = lookupPaths || []; + lookupPaths = lookupPaths.concat(Blueprint.defaultLookupPaths()); + return uniq(lookupPaths); +} + +/** + Looks for a __path__ token in the files folder. Must be present for + the blueprint to support pod tokens. + + @private + @method hasPathToken + @param {files} files + @return {Boolean} +*/ +function hasPathToken(files) { + return files.join().match(/__path__/); +} + +function inRepoAddonExists(name, root) { + var addonPath = path.join(root, 'lib', name); + return existsSync(addonPath); +} + +function podDeprecations(config, ui) { + /* + var podModulePrefix = config.podModulePrefix || ''; + var podPath = podModulePrefix.substr(podModulePrefix.lastIndexOf('/') + 1); + // Disabled until we are ready to deprecate podModulePrefix + deprecateUI(ui)('`podModulePrefix` is deprecated and will be removed from future versions of ember-cli.'+ + ' Please move existing pods from \'app/' + podPath + '/\' to \'app/\'.', config.podModulePrefix); + */ + if (config.usePodsByDefault) { + ui.writeDeprecateLine('`usePodsByDefault` is no longer supported in \'config/environment.js\',' + + ' use `usePods` in \'.ember-cli\' instead.'); + } +} + +/** + @private + @method destPath + @param {String} intoDir + @param {String} file + @return {String} new path +*/ +function destPath(intoDir, file) { + return path.join(intoDir, file); +} + +/** + @private + @method isValidFile + @param {Object} fileInfo + @return {Promise} +*/ +function isValidFile(fileInfo) { + if (isIgnored(fileInfo)) { + return Promise.resolve(false); + } else { + return isFile(fileInfo); + } +} + +/** + @private + @method isFilePath + @param {Object} fileInfo + @return {Promise} +*/ +function isFilePath(fileInfo) { + return fs.statSync(fileInfo.inputPath).isFile(); +} + +/** + @private + @method dir + @returns {Array} list of files in the given directory or and empty array if no directory exists +*/ +function dir(fullPath) { + if (existsSync(fullPath)) { + return fs.readdirSync(fullPath).map(function(fileName) { + return path.join(fullPath, fileName); + }); + } else { + return []; + } +} + +/** + @private + @method getDetailedHelpPath + @param {String} thisPath + @return {String} help path +*/ +function getDetailedHelpPath(thisPath) { + return path.join(thisPath, './HELP.md'); +} diff --git a/packages/ember-cli/lib/models/builder.js b/packages/ember-cli/lib/models/builder.js new file mode 100644 index 000000000000..71050d2d846f --- /dev/null +++ b/packages/ember-cli/lib/models/builder.js @@ -0,0 +1,187 @@ +'use strict'; + +var fs = require('fs-extra'); +var existsSync = require('exists-sync'); +var path = require('path'); +var Promise = require('../ext/promise'); +var Task = require('./task'); +var SilentError = require('silent-error'); +var chalk = require('chalk'); +var attemptNeverIndex = require('../utilities/attempt-never-index'); +var findBuildFile = require('../utilities/find-build-file'); +// var viz = require('broccoli-viz'); +var FSMonitor = require('fs-monitor-stack'); +var Sync = require('tree-sync'); +var mkdirp = require('mkdirp'); + +var signalsTrapped = false; +var buildCount = 0; + + +module.exports = Task.extend({ + setupBroccoliBuilder: function() { + this.environment = this.environment || 'development'; + process.env.EMBER_ENV = process.env.EMBER_ENV || this.environment; + + var broccoli = require('ember-cli-broccoli'); + var hasBrocfile = existsSync(path.join('.', 'Brocfile.js')); + var buildFile = findBuildFile('ember-cli-build.js'); + + if (hasBrocfile) { + this.ui.writeDeprecateLine('Brocfile.js has been deprecated in favor of ember-cli-build.js. Please see the transition guide: https://github.com/ember-cli/ember-cli/blob/master/TRANSITION.md#user-content-brocfile-transition.'); + this.tree = broccoli.loadBrocfile(); + } else if (buildFile) { + this.tree = buildFile({ project: this.project }); + } else { + throw new Error('No ember-cli-build.js found. Please see the transition guide: https://github.com/ember-cli/ember-cli/blob/master/TRANSITION.md#user-content-brocfile-transition.'); + } + + this.builder = new broccoli.Builder(this.tree); + + var builder = this; + + if (process.env.BROCCOLI_VIZ) { + this.builder.on('start', function() { + builder.monitor = new FSMonitor(); + }); + + this.builder.on('nodeStart', function(node) { + builder.monitor.push(node); + }); + + this.builder.on('nodeEnd', function() { + builder.monitor.pop(); + }); + } + }, + + trapSignals: function() { + if (!signalsTrapped) { + process.on('SIGINT', this.onSIGINT.bind(this)); + process.on('SIGTERM', this.onSIGTERM.bind(this)); + process.on('message', this.onMessage.bind(this)); + signalsTrapped = true; + } + }, + + init: function() { + this.setupBroccoliBuilder(); + this.trapSignals(); + }, + + /** + Determine whether the output path is safe to delete. If the outputPath + appears anywhere in the parents of the project root, the build would + delete the project directory. In this case return `false`, otherwise + return `true`. + */ + canDeleteOutputPath: function(outputPath) { + var rootPathParents = [this.project.root]; + var dir = path.dirname(this.project.root); + rootPathParents.push(dir); + while (dir !== path.dirname(dir)) { + dir = path.dirname(dir); + rootPathParents.push(dir); + } + return rootPathParents.indexOf(outputPath) === -1; + }, + + copyToOutputPath: function(inputPath) { + var outputPath = this.outputPath; + + mkdirp.sync(outputPath); + + if (!this.canDeleteOutputPath(outputPath)) { + throw new SilentError('Using a build destination path of `' + outputPath + '` is not supported.'); + } + + var sync = this._sync; + if (sync === undefined) { + this._sync = sync = new Sync(inputPath, path.resolve(this.outputPath)); + } + + sync.sync(); + }, + + processBuildResult: function(results) { + var self = this; + + return Promise.resolve() + .then(function() { + return self.copyToOutputPath(results.directory); + }) + .then(function() { + return results; + }); + }, + + processAddonBuildSteps: function(buildStep, results) { + var addonPromises = []; + if (this.project && this.project.addons.length) { + addonPromises = this.project.addons.map(function(addon) { + if (addon[buildStep]) { + return addon[buildStep](results); + } + }).filter(Boolean); + } + + return Promise.all(addonPromises).then(function() { + return results; + }); + }, + + build: function() { + var self = this; + var args = []; + for (var i = 0, l = arguments.length; i < l; i++) { + args.push(arguments[i]); + } + + attemptNeverIndex('tmp'); + + return this.processAddonBuildSteps('preBuild') + .then(function() { + return self.builder.build.apply(self.builder, args); + }) + .then(function(result) { + // if (process.env.BROCCOLI_VIZ) { + // outputViz(buildCount++, result, self.monitor); + // } + return result; + }) + .then(this.processAddonBuildSteps.bind(this, 'postBuild')) + .then(this.processBuildResult.bind(this)) + .then(this.processAddonBuildSteps.bind(this, 'outputReady')) + .catch(function(error) { + this.processAddonBuildSteps('buildError', error); + throw error; + }.bind(this)); + }, + + cleanup: function() { + var ui = this.ui; + + return this.builder.cleanup().catch(function(err) { + ui.writeLine(chalk.red('Cleanup error.')); + ui.writeError(err); + }); + }, + + cleanupAndExit: function() { + this.cleanup().finally(function() { + process.exit(1); + }); + }, + + onSIGINT: function() { + this.cleanupAndExit(); + }, + onSIGTERM: function() { + this.cleanupAndExit(); + }, + onMessage: function(message) { + if (message.kill) { + this.cleanupAndExit(); + } + } +}); diff --git a/packages/ember-cli/lib/models/command.js b/packages/ember-cli/lib/models/command.js new file mode 100644 index 000000000000..d5f43cc3d0b3 --- /dev/null +++ b/packages/ember-cli/lib/models/command.js @@ -0,0 +1,510 @@ +'use strict'; + +var nopt = require('nopt'); +var chalk = require('chalk'); +var path = require('path'); +var isGitRepo = require('is-git-url'); +var camelize = require('ember-cli-string-utils').camelize; +var getCallerFile = require('get-caller-file'); +var printableProperties = require('../utilities/printable-properties').command; +var printCommand = require('../utilities/print-command'); +var Promise = require('../ext/promise'); +var union = require('lodash/union'); +var uniq = require('lodash/uniq'); +var uniqBy = require('lodash/uniqBy'); +var map = require('lodash/map'); +var reject = require('lodash/reject'); +var filter = require('lodash/filter'); +var assign = require('lodash/assign'); +var defaults = require('lodash/defaults'); +var keys = require('lodash/keys'); +var EOL = require('os').EOL; +var CoreObject = require('core-object'); +var debug = require('debug')('ember-cli:command'); +var Watcher = require('../models/watcher'); +var SilentError = require('silent-error'); + +var allowedWorkOptions = { + insideProject: true, + outsideProject: true, + everywhere: true +}; + +path.name = 'Path'; +// extend nopt to recognize 'gitUrl' as a type +nopt.typeDefs.gitUrl = { + type: 'gitUrl', + validate: function(data, k, val) { + if (isGitRepo(val)) { + data[k] = val; + return true; + } else { + return false; + } + } +}; + +module.exports = Command; + +function Command() { + CoreObject.apply(this, arguments); + + this.isWithinProject = this.project.isEmberCLIProject(); + this.name = this.name || path.basename(getCallerFile(), '.js'); + + debug('initialize: name: %s, name: %s', this.name); + this.aliases = this.aliases || []; + + // Works Property + if (!allowedWorkOptions[this.works]) { + throw new Error('The "' + this.name + '" command\'s works field has to ' + + 'be either "everywhere", "insideProject" or "outsideProject".'); + } + + // Options properties + this.availableOptions = this.availableOptions || []; + this.anonymousOptions = this.anonymousOptions || []; + this.registerOptions(); +} +/* + Registers options with command. This method provides the ability to extend or override command options. + Expects an object containing anonymousOptions or availableOptions, which it will then merge with + existing availableOptions before building the optionsAliases which are used to define shorthands. +*/ +Command.prototype.registerOptions = function(options) { + var extendedAvailableOptions = options && options.availableOptions || []; + var extendedAnonymousOptions = options && options.anonymousOptions || []; + + this.anonymousOptions = union(this.anonymousOptions.slice(0), extendedAnonymousOptions); + + // merge any availableOptions + this.availableOptions = union(this.availableOptions.slice(0), extendedAvailableOptions); + + var optionKeys = uniq(map(this.availableOptions, 'name')); + + optionKeys.map(this.mergeDuplicateOption.bind(this)); + + this.optionsAliases = this.optionsAliases || {}; + + this.availableOptions.map(this.validateOption.bind(this)); +}; + +Command.__proto__ = CoreObject; + +Command.prototype.description = null; +Command.prototype.works = 'insideProject'; +Command.prototype.constructor = Command; +/* + Hook for extending a command before it is run in the cli.run command. + Most common use case would be to extend availableOptions. + @method beforeRun + @return {Promise|null} +*/ +Command.prototype.beforeRun = function() { + +}; + +/* + @method validateAndRun + @return {Promise} +*/ +Command.prototype.validateAndRun = function(args) { + var commandOptions = this.parseArgs(args); + // if the help option was passed, resolve with 'callHelp' to call help command + if (commandOptions && (commandOptions.options.help || commandOptions.options.h)) { + debug(this.name + ' called with help option'); + return Promise.resolve('callHelp'); + } + + this.analytics.track({ + name: 'ember ', + message: this.name + }); + + if (commandOptions === null) { + return Promise.resolve(); + } + + if (this.works === 'insideProject' && !this.isWithinProject) { + return Promise.reject(new SilentError( + 'You have to be inside an ember-cli project in order to use ' + + 'the ' + chalk.green(this.name) + ' command.' + )); + } + + if (this.works === 'outsideProject' && this.isWithinProject) { + return Promise.reject(new SilentError( + 'You cannot use the ' + chalk.green(this.name) + ' command inside an ember-cli project.' + )); + } + + if (this.works === 'insideProject') { + if (!this.project.hasDependencies()) { + throw new SilentError('node_modules appears empty, you may need to run `npm install`'); + } + } + + return Watcher.detectWatcher(this.ui, commandOptions.options).then(function(options) { + if (options._watchmanInfo) { + this.project._watchmanInfo = options._watchmanInfo; + } + + return this.run(options, commandOptions.args); + }.bind(this)); +}; + +/* + Merges any options with duplicate keys in the availableOptions array. + Used primarily by registerOptions. + @method mergeDuplicateOption + @param {String} key + @return {Object} +*/ +Command.prototype.mergeDuplicateOption = function(key) { + var duplicateOptions, mergedOption, mergedAliases; + // get duplicates to merge + duplicateOptions = filter(this.availableOptions, { 'name': key }); + + if (duplicateOptions.length > 1) { + // TODO: warn on duplicates and overwriting + mergedAliases = []; + + map(duplicateOptions, 'aliases').map(function(alias) { + alias.map(function(a) { + mergedAliases.push(a); + }); + }); + + // merge duplicate options + mergedOption = assign.apply(null,duplicateOptions); + + // replace aliases with unique aliases + mergedOption.aliases = uniqBy(mergedAliases, function(alias) { + if (typeof alias === 'object') { + return alias[Object.keys(alias)[0]]; + } + return alias; + }); + + // remove duplicates from options + this.availableOptions = reject(this.availableOptions, { 'name': key }); + this.availableOptions.push(mergedOption); + } + return this.availableOptions; +}; + +/* + Normalizes option, filling in implicit values + @method normalizeOption + @param {Object} option + @return {Object} +*/ +Command.prototype.normalizeOption = function(option) { + option.key = camelize(option.name); + option.required = option.required || false; + return option; +}; + +/* + Assigns option + @method assignOption + @param {Object} option + @param {Object} parsedOptions + @param {Object} commandOptions + @return {Boolean} +*/ +Command.prototype.assignOption = function(option, parsedOptions, commandOptions) { + var isValid = isValidParsedOption(option, parsedOptions[option.name]); + if (isValid) { + if (parsedOptions[option.name] === undefined) { + if (option.default !== undefined) { + commandOptions[option.key] = option.default; + } + + if (this.settings[option.name] !== undefined) { + commandOptions[option.key] = this.settings[option.name]; + } else if (this.settings[option.key] !== undefined) { + commandOptions[option.key] = this.settings[option.key]; + } + } else { + commandOptions[option.key] = parsedOptions[option.name]; + delete parsedOptions[option.name]; + } + } else { + this.ui.writeLine('The specified command ' + chalk.green(this.name) + + ' requires the option ' + chalk.green(option.name) + '.'); + } + return isValid; +}; + +/* + Validates option + @method validateOption + @param {Object} option + @return {Boolean} +*/ +Command.prototype.validateOption = function(option) { + var parsedAliases; + + if (!option.name || !option.type) { + throw new Error('The command "' + this.name + '" has an option ' + + 'without the required type and name fields.'); + } + + if (option.name !== option.name.toLowerCase()) { + throw new Error('The "' + option.name + '" option\'s name of the "' + + this.name + '" command contains a capital letter.'); + } + + this.normalizeOption(option); + + if (option.aliases) { + parsedAliases = option.aliases.map(this.parseAlias.bind(this, option)); + return parsedAliases.map(this.assignAlias.bind(this, option)).indexOf(false) === -1; + } + return false; +}; + +/* + Parses alias for an option and adds it to optionsAliases + @method parseAlias + @param {Object} option + @param {Object|String} alias + @return {Object} +*/ +Command.prototype.parseAlias = function(option, alias) { + var aliasType = typeof alias; + var key, value, aliasValue; + + if (isValidAlias(alias, option.type)) { + if (aliasType === 'string') { + key = alias; + value = ['--' + option.name]; + } else if (aliasType === 'object') { + key = Object.keys(alias)[0]; + value = ['--' + option.name, alias[key]]; + } + } else { + if (Array.isArray(alias)) { + aliasType = 'array'; + aliasValue = alias.join(','); + } else { + aliasValue = alias; + try { + aliasValue = JSON.parse(alias); + } catch (e) { + var debug = require('debug')('@angular-cli/ember-cli/models/command'); + debug(e); + } + } + throw new Error('The "' + aliasValue + '" [type:' + aliasType + + '] alias is not an acceptable value. It must be a string or single key' + + ' object with a string value (for example, "value" or { "key" : "value" }).'); + } + + return { + key: key, + value: value, + original: alias + }; + +}; +Command.prototype.assignAlias = function(option, alias) { + var isValid = this.validateAlias(option, alias); + + if (isValid) { + this.optionsAliases[alias.key] = alias.value; + } + return isValid; +}; + +/* + Validates alias value + @method validateAlias + @params {Object} alias + @return {Boolean} +*/ +Command.prototype.validateAlias = function(option, alias) { + var key = alias.key; + var value = alias.value; + + if (!this.optionsAliases[key]) { + return true; + } else { + if (value[0] !== this.optionsAliases[key][0]) { + throw new SilentError('The "' + key + '" alias is already in use by the "' + this.optionsAliases[key][0] + + '" option and cannot be used by the "' + value[0] + '" option. Please use a different alias.'); + } else { + if (value[1] !== this.optionsAliases[key][1]) { + this.ui.writeLine(chalk.yellow('The "' + key + '" alias cannot be overridden. Please use a different alias.')); + // delete offending alias from options + var index = this.availableOptions.indexOf(option); + var aliasIndex = this.availableOptions[index].aliases.indexOf(alias.original); + if (this.availableOptions[index].aliases[aliasIndex]) { + delete this.availableOptions[index].aliases[aliasIndex]; + } + } + } + return false; + } +}; + +/* + Parses command arguments and processes + @method parseArgs + @param {Object} commandArgs + @return {Object|null} +*/ +Command.prototype.parseArgs = function(commandArgs) { + var knownOpts = {}; // Parse options + var commandOptions = {}; + var parsedOptions; + + var assembleAndValidateOption = function(option) { + return this.assignOption(option, parsedOptions, commandOptions); + }; + + var validateParsed = function(key) { + // ignore 'argv', 'h', and 'help' + if (!commandOptions.hasOwnProperty(key) && key !== 'argv' && key !== 'h' && key !== 'help') { + this.ui.writeLine(chalk.yellow('The option \'--' + key + '\' is not registered with the ' + this.name + ' command. ' + + 'Run `ember ' + this.name + ' --help` for a list of supported options.')); + } + if (typeof parsedOptions[key] !== 'object') { + commandOptions[camelize(key)] = parsedOptions[key]; + } + }; + + this.availableOptions.forEach(function(option) { + if (typeof option.type !== 'string') { + knownOpts[option.name] = option.type; + } else if (option.type === 'Path') { + knownOpts[option.name] = path; + } else { + knownOpts[option.name] = String; + } + }); + + parsedOptions = nopt(knownOpts, this.optionsAliases, commandArgs, 0); + + if (!this.availableOptions.every(assembleAndValidateOption.bind(this))) { + return null; + } + + keys(parsedOptions).map(validateParsed.bind(this)); + + return { + options: defaults(commandOptions, this.settings), + args: parsedOptions.argv.remain + }; +}; + +/* + +*/ +Command.prototype.run = function(commandArgs) { + throw new Error('command must implement run' + commandArgs.toString()); +}; + +Command.prototype._printCommand = printCommand; + +/* + Prints basic help for the command. + + Basic help looks like this: + + ember generate + Generates new code from blueprints + aliases: g + --dry-run (Default: false) + --verbose (Default: false) + + The default implementation is designed to cover all bases + but may be overriden if necessary. + + @method printBasicHelp +*/ +Command.prototype.printBasicHelp = function() { + // ember command-name + var output; + if (this.isRoot) { + output = 'Usage: ' + this.name; + } else { + output = 'ember ' + this.name; + } + + output += this._printCommand(); + output += EOL; + + return output; +}; + +/* + Prints detailed help for the command. + + The default implementation is no-op and should be overridden + for each command where further help text is required. + + @method printDetailedHelp +*/ +Command.prototype.printDetailedHelp = function() {}; + +Command.prototype.getJson = function(options) { + var json = {}; + + printableProperties.forEachWithProperty(function(key) { + json[key] = this[key]; + }, this); + + if (this.addAdditionalJsonForHelp) { + this.addAdditionalJsonForHelp(json, options); + } + + return json; +}; + +/* + Validates options parsed by nopt +*/ +function isValidParsedOption(option, parsedOption) { + // option.name didn't parse + if (parsedOption === undefined) { + // no default + if (option.default === undefined) { + if (option.required) { + return false; + } + } + } + + return true; +} + +/* + Validates alias. Must be a string or single key object +*/ +function isValidAlias(alias, expectedType) { + var type = typeof alias; + var value, valueType; + if (type === 'string') { + return true; + } else if (type === 'object') { + + // no arrays, no multi-key objects + if (!Array.isArray(alias) && Object.keys(alias).length === 1) { + value = alias[Object.keys(alias)[0]]; + valueType = typeof value; + if (!Array.isArray(expectedType)) { + if (valueType === expectedType.name.toLowerCase()) { + return true; + } + } else { + if (expectedType.indexOf(value) > -1) { + return true; + } + } + } + } + + return false; +} diff --git a/packages/ember-cli/lib/models/edit-file-diff.js b/packages/ember-cli/lib/models/edit-file-diff.js new file mode 100644 index 000000000000..eeeb5d155ccf --- /dev/null +++ b/packages/ember-cli/lib/models/edit-file-diff.js @@ -0,0 +1,63 @@ +'use strict'; + +var fs = require('fs'); +var Promise = require('../ext/promise'); +var readFile = Promise.denodeify(fs.readFile); +var writeFile = Promise.denodeify(fs.writeFile); +var jsdiff = require('diff'); +var quickTemp = require('quick-temp'); +var path = require('path'); +var SilentError = require('silent-error'); +var openEditor = require('../utilities/open-editor'); + +function EditFileDiff(options) { + this.info = options.info; + + quickTemp.makeOrRemake(this, 'tmpDifferenceDir'); +} + +EditFileDiff.prototype.edit = function() { + return Promise.hash({ + input: this.info.render(), + output: readFile(this.info.outputPath) + }) + .then(invokeEditor.bind(this)) + .then(applyPatch.bind(this)) + .finally(cleanUp.bind(this)); +}; + +function cleanUp() { + quickTemp.remove(this, 'tmpDifferenceDir'); // jshint ignore:line +} + +function applyPatch(resultHash) { + /*jshint validthis:true */ + return Promise.hash({ + diffString: readFile(resultHash.diffPath), + currentString: readFile(resultHash.outputPath) + }).then(function(result) { + var appliedDiff = jsdiff.applyPatch(result.currentString.toString(), result.diffString.toString()); + + if (!appliedDiff) { + var message = 'Patch was not cleanly applied.'; + this.info.ui.writeLine(message + ' Please choose another action.'); + throw new SilentError(message); + } + + return writeFile(resultHash.outputPath, appliedDiff); + }.bind(this)); +} + +function invokeEditor(result) { + var info = this.info; // jshint ignore:line + var diff = jsdiff.createPatch(info.outputPath, result.output.toString(), result.input); + var diffPath = path.join(this.tmpDifferenceDir, 'currentDiff.diff'); // jshint ignore:line + + return writeFile(diffPath, diff).then(function() { + return openEditor(diffPath); + }).then(function() { + return { outputPath: info.outputPath, diffPath: diffPath }; + }); +} + +module.exports = EditFileDiff; diff --git a/packages/ember-cli/lib/models/file-info.js b/packages/ember-cli/lib/models/file-info.js new file mode 100644 index 000000000000..d029a0335b21 --- /dev/null +++ b/packages/ember-cli/lib/models/file-info.js @@ -0,0 +1,173 @@ +'use strict'; + +var fs = require('fs'); +var Promise = require('../ext/promise'); +var readFile = Promise.denodeify(fs.readFile); +var lstat = Promise.denodeify(fs.stat); +var chalk = require('chalk'); +var EditFileDiff = require('./edit-file-diff'); +var EOL = require('os').EOL; +var isBinaryFile = require('isbinaryfile'); +var template = require('lodash/template'); +var canEdit = require('../utilities/open-editor').canEdit; + +function processTemplate(content, context) { + var options = { + evaluate: /<%([\s\S]+?)%>/g, + interpolate: /<%=([\s\S]+?)%>/g, + escape: /<%-([\s\S]+?)%>/g + }; + return template(content, options)(context); +} + +function diffHighlight(line) { + if (line[0] === '+') { + return chalk.green(line); + } else if (line[0] === '-') { + return chalk.red(line); + } else if (line.match(/^@@/)) { + return chalk.cyan(line); + } else { + return line; + } +} + +FileInfo.prototype.confirmOverwrite = function(path) { + var promptOptions = { + type: 'expand', + name: 'answer', + default: false, + message: chalk.red('Overwrite') + ' ' + path + '?', + choices: [ + { key: 'y', name: 'Yes, overwrite', value: 'overwrite' }, + { key: 'n', name: 'No, skip', value: 'skip' }, + { key: 'd', name: 'Diff', value: 'diff' } + ] + }; + + if (canEdit()) { + promptOptions.choices.push({ key: 'e', name: 'Edit', value: 'edit' }); + } + + return this.ui.prompt(promptOptions) + .then(function(response) { + return response.answer; + }); +}; + +FileInfo.prototype.displayDiff = function() { + var info = this, + jsdiff = require('diff'); + return Promise.hash({ + input: this.render(), + output: readFile(info.outputPath) + }).then(function(result) { + var diff = jsdiff.createPatch( + info.outputPath, result.output.toString(), result.input + ); + var lines = diff.split('\n'); + + for (var i = 0; i < lines.length; i++) { + info.ui.write( + diffHighlight(lines[i] + EOL) + ); + } + }); +}; + +function FileInfo(options) { + this.action = options.action; + this.outputPath = options.outputPath; + this.displayPath = options.displayPath; + this.inputPath = options.inputPath; + this.templateVariables = options.templateVariables; + this.ui = options.ui; +} + +FileInfo.prototype.render = function() { + var path = this.inputPath, + context = this.templateVariables; + if (!this.rendered) { + this.rendered = readFile(path).then(function(content) { + return lstat(path).then(function(fileStat) { + if (isBinaryFile(content, fileStat.size)) { + return content; + } else { + try { + return processTemplate(content.toString(), context); + } catch (err) { + err.message += ' (Error in blueprint template: ' + path + ')'; + throw err; + } + } + }); + }); + } + return this.rendered; +}; + +FileInfo.prototype.checkForConflict = function() { + return new Promise(function (resolve, reject) { + fs.exists(this.outputPath, function (doesExist, error) { + if (error) { + reject(error); + return; + } + + var result; + + if (doesExist) { + result = Promise.hash({ + input: this.render(), + output: readFile(this.outputPath) + }).then(function(result) { + var type; + if (result.input === result.output.toString()) { + type = 'identical'; + } else { + type = 'confirm'; + } + return type; + }.bind(this)); + } else { + result = 'none'; + } + + resolve(result); + }.bind(this)); + }.bind(this)); +}; + +FileInfo.prototype.confirmOverwriteTask = function() { + var info = this; + + return function() { + return new Promise(function(resolve, reject) { + function doConfirm() { + info.confirmOverwrite(info.displayPath).then(function(action) { + if (action === 'diff') { + info.displayDiff().then(doConfirm, reject); + } else if (action === 'edit') { + var editFileDiff = new EditFileDiff({info: info}); + editFileDiff.edit().then(function() { + info.action = action; + resolve(info); + }).catch(function() { + doConfirm() + .finally(function() { + resolve(info); + }); + }); + } else { + info.action = action; + resolve(info); + } + }, reject); + } + + doConfirm(); + }); + }.bind(this); +}; + +module.exports = FileInfo; diff --git a/packages/ember-cli/lib/models/installation-checker.js b/packages/ember-cli/lib/models/installation-checker.js new file mode 100644 index 000000000000..b9a0ed967a37 --- /dev/null +++ b/packages/ember-cli/lib/models/installation-checker.js @@ -0,0 +1,75 @@ +'use strict'; + +var debug = require('debug')('ember-cli:installation-checker'); +var fs = require('fs'); +var existsSync = require('exists-sync'); +var path = require('path'); +var SilentError = require('silent-error'); + +module.exports = InstallationChecker; + +function InstallationChecker(options) { + this.project = options.project; +} + +/** +* Check if npm and bower installation directories are present, +* and raise an error message with instructions on how to proceed. +* +* If some of these package managers aren't being used in the project +* we just ignore them. Their usage is considered by checking the +* presence of your manifest files: package.json for npm and bower.json for bower. +*/ +InstallationChecker.prototype.checkInstallations = function() { + var commands = []; + + if (this.usingNpm() && this.npmDependenciesNotPresent()) { + debug('npm dependencies not installed'); + commands.push('`npm install`'); + } + if (this.usingBower() && this.bowerDependenciesNotPresent()) { + debug('bower dependencies not installed'); + commands.push('`bower install`'); + } + if (commands.length) { + var commandText = commands.join(' and '); + throw new SilentError('No dependencies installed. Run ' + commandText + ' to install missing dependencies.'); + } +}; + +function hasDependencies(pkg) { + return (pkg.dependencies && pkg.dependencies.length) || + (pkg.devDependencies && pkg.devDependencies.length); +} + +function readJSON(path) { + try { + return JSON.parse(fs.readFileSync(path).toString()); + } catch (e) { + throw new SilentError('InstallationChecker: Unable to parse: ' + path); + } +} + +InstallationChecker.prototype.hasBowerDeps = function() { + return hasDependencies(readJSON(path.join(this.project.root, 'bower.json'))); +}; + +InstallationChecker.prototype.usingBower = function() { + return existsSync(path.join(this.project.root, 'bower.json')) && this.hasBowerDeps(); +}; + +InstallationChecker.prototype.bowerDependenciesNotPresent = function() { + return !existsSync(this.project.bowerDirectory); +}; + +InstallationChecker.prototype.hasNpmDeps = function() { + return hasDependencies(readJSON(path.join(this.project.root, 'package.json'))); +}; + +InstallationChecker.prototype.usingNpm = function() { + return existsSync(path.join(this.project.root, 'package.json')) && this.hasNpmDeps(); +}; + +InstallationChecker.prototype.npmDependenciesNotPresent = function() { + return !existsSync(this.project.nodeModulesPath); +}; diff --git a/packages/ember-cli/lib/models/project.js b/packages/ember-cli/lib/models/project.js new file mode 100644 index 000000000000..d0c4fa0232bb --- /dev/null +++ b/packages/ember-cli/lib/models/project.js @@ -0,0 +1,733 @@ +'use strict'; + +/** +@module ember-cli +*/ +var Promise = require('../ext/promise'); +var path = require('path'); +var findup = Promise.denodeify(require('findup')); +var resolve = Promise.denodeify(require('resolve')); +var fs = require('fs'); +var existsSync = require('exists-sync'); +var find = require('lodash/find'); +var assign = require('lodash/assign'); +var forOwn = require('lodash/forOwn'); +var merge = require('lodash/merge'); +var debug = require('debug')('ember-cli:project'); +var AddonDiscovery = require('../models/addon-discovery'); +var AddonsFactory = require('../models/addons-factory'); +var Command = require('../models/command'); +var UI = require('../ui'); +var nodeModulesPath = require('node-modules-path'); +var getPackageBaseName = require('../utilities/get-package-base-name'); +var versionUtils = require('../utilities/version-utils'); +var emberCLIVersion = versionUtils.emberCLIVersion; + +/** + The Project model is tied to your package.json. It is instiantiated + by giving Project.closest the path to your project. + + @class Project + @constructor + @param {String} root Root directory for the project + @param {Object} pkg Contents of package.json +*/ +function Project(root, pkg, ui, cli) { + debug('init root: %s', root); + this.root = root; + this.pkg = pkg; + this.ui = ui; + this.cli = cli; + this.addonPackages = {}; + this.addons = []; + this.liveReloadFilterPatterns = []; + this.setupBowerDirectory(); + this.setupNodeModulesPath(); + this.addonDiscovery = new AddonDiscovery(this.ui); + this.addonsFactory = new AddonsFactory(this, this); + this._watchmanInfo = { + enabled: false, + version: null, + canNestRoots: false + }; +} + +/** + Set when the `Watcher.detectWatchman` helper method finishes running, + so that other areas of the system can be aware that watchman is being used. + + For example, this information is used in the broccoli build pipeline to know + if we can watch additional directories (like bower_components) "cheaply". + + Contains `enabled` and `version`. + + @private + @property _watchmanInfo + @returns {Object} + @default false +*/ + +/** + Sets the name of the bower directory for this project + + @private + @method setupBowerDirectory + */ +Project.prototype.setupBowerDirectory = function() { + var bowerrcPath = path.join(this.root, '.bowerrc'); + + debug('bowerrc path: %s', bowerrcPath); + + if (existsSync(bowerrcPath)) { + var bowerrcContent = fs.readFileSync(bowerrcPath); + try { + this.bowerDirectory = JSON.parse(bowerrcContent).directory; + } catch (exception) { + debug('failed to parse bowerc: %s', exception); + this.bowerDirectory = null; + } + } + + this.bowerDirectory = this.bowerDirectory || 'bower_components'; + debug('bowerDirectory: %s', this.bowerDirectory); +}; + +Project.prototype.hasDependencies = function() { + return !!this.nodeModulesPath; +}; +/** + Sets the path to the node_modules directory for this + project. + + @private + @method setupNodeModulesPath + */ +Project.prototype.setupNodeModulesPath = function() { + this.nodeModulesPath = nodeModulesPath(this.root); + debug('nodeModulesPath: %s', this.nodeModulesPath); +}; + +var processCwd = process.cwd(); +// ensure NULL_PROJECT is a singleton +var NULL_PROJECT; + +Project.nullProject = function (ui, cli) { + if (NULL_PROJECT) { return NULL_PROJECT; } + + NULL_PROJECT = new Project(processCwd, {}, ui, cli); + + NULL_PROJECT.isEmberCLIProject = function() { + return false; + }; + + NULL_PROJECT.isEmberCLIAddon = function() { + return false; + }; + + NULL_PROJECT.name = function() { + return path.basename(process.cwd()); + }; + + NULL_PROJECT.initializeAddons(); + + return NULL_PROJECT; +}; + +/** + Returns the name from package.json. + + @private + @method name + @return {String} Package name + */ +Project.prototype.name = function() { + return getPackageBaseName(this.pkg.name); +}; + +/** + Returns whether or not this is an Ember CLI project. + This checks whether ember-cli is listed in devDependencies. + + @private + @method isEmberCLIProject + @return {Boolean} Whether this is an Ember CLI project + */ +Project.prototype.isEmberCLIProject = function() { + return (this.cli ? this.cli.npmPackage : 'ember-cli') in this.dependencies(); +}; + +/** + Returns whether or not this is an Ember CLI addon. + + @method isEmberCLIAddon + @return {Boolean} Whether or not this is an Ember CLI Addon. + */ +Project.prototype.isEmberCLIAddon = function() { + return !!this.pkg.keywords && this.pkg.keywords.indexOf('ember-addon') > -1; +}; + +/** + Returns the path to the configuration. + + @private + @method configPath + @return {String} Configuration path + */ +Project.prototype.configPath = function() { + var configPath = 'config'; + + if (this.pkg['ember-addon'] && this.pkg['ember-addon']['configPath']) { + configPath = this.pkg['ember-addon']['configPath']; + } + + return path.join(configPath, 'environment'); +}; + +/** + Loads the configuration for this project and its addons. + + @private + @method config + @param {String} env Environment name + @return {Object} Merged confiration object + */ +Project.prototype.config = function(env) { + var configPath = this.configPath(); + + if (existsSync(path.join(this.root, configPath + '.js'))) { + var appConfig = this.require('./' + configPath)(env); + var addonsConfig = this.getAddonsConfig(env, appConfig); + + return merge(addonsConfig, appConfig); + } else { + return this.getAddonsConfig(env, {}); + } +}; + +/** + Returns the addons configuration. + + @private + @method getAddonsConfig + @param {String} env Environment name + @param {Object} appConfig Application configuration + @return {Object} Merged configuration of all addons + */ +Project.prototype.getAddonsConfig = function(env, appConfig) { + this.initializeAddons(); + + var initialConfig = merge({}, appConfig); + + return this.addons.reduce(function(config, addon) { + if (addon.config) { + merge(config, addon.config(env, config)); + } + + return config; + }, initialConfig); +}; + +/** + Returns whether or not the given file name is present in this project. + + @private + @method has + @param {String} file File name + @return {Boolean} Whether or not the file is present + */ +Project.prototype.has = function(file) { + return existsSync(path.join(this.root, file)) || existsSync(path.join(this.root, file + '.js')); +}; + +/** + Resolves the absolute path to a file. + + @private + @method resolve + @param {String} file File to resolve + @return {String} Absolute path to file + */ +Project.prototype.resolve = function(file) { + return resolve(file, { + basedir: this.root + }); +}; + +/** + Resolves the absolute path to a file synchronously + + @private + @method resolveSync + @param {String} file File to resolve + @return {String} Absolute path to file + */ +Project.prototype.resolveSync = function(file) { + return resolve.sync(file, { + basedir: this.root + }); +}; + +/** + Calls `require` on a given module. + + @private + @method require + @param {String} file File path or module name + @return {Object} Imported module + */ +Project.prototype.require = function(file) { + if (/^\.\//.test(file)) { // Starts with ./ + return require(path.join(this.root, file)); + } else { + return require(path.join(this.nodeModulesPath, file)); + } +}; + + +Project.prototype.emberCLIVersion = emberCLIVersion; + +/** + Returns the dependencies from a package.json + + @private + @method dependencies + @param {Object} pkg Package object. If false, the current package is used. + @param {Boolean} excludeDevDeps Whether or not development dependencies should be excluded, defaults to false. + @return {Object} Dependencies + */ +Project.prototype.dependencies = function(pkg, excludeDevDeps) { + pkg = pkg || this.pkg || {}; + + var devDependencies = pkg['devDependencies']; + if (excludeDevDeps) { + devDependencies = {}; + } + + return assign({}, devDependencies, pkg['dependencies']); +}; + +/** + Returns the bower dependencies for this project. + + @private + @method bowerDependencies + @param {String} bower Path to bower.json + @return {Object} Bower dependencies + */ +Project.prototype.bowerDependencies = function(bower) { + if (!bower) { + var bowerPath = path.join(this.root, 'bower.json'); + bower = (existsSync(bowerPath)) ? require(bowerPath) : {}; + } + return assign({}, bower['devDependencies'], bower['dependencies']); +}; + +/** + Provides the list of paths to consult for addons that may be provided + internally to this project. Used for middleware addons with built-in support. + + @private + @method supportedInternalAddonPaths +*/ +Project.prototype.supportedInternalAddonPaths = function() { + if (!this.root) { return []; } + + var internalMiddlewarePath = path.join(__dirname, '../tasks/server/middleware'); + + return [ + path.join(internalMiddlewarePath, 'tests-server'), + path.join(internalMiddlewarePath, 'history-support'), + path.join(internalMiddlewarePath, 'serve-files'), + path.join(internalMiddlewarePath, 'proxy-server') + ]; +}; + +/** + Discovers all addons for this project and stores their names and + package.json contents in this.addonPackages as key-value pairs + + @private + @method discoverAddons + */ +Project.prototype.discoverAddons = function() { + var addonsList = this.addonDiscovery.discoverProjectAddons(this); + + this.addonPackages = this.addonDiscovery.addonPackages(addonsList); +}; + +/** + Loads and initializes all addons for this project. + + @private + @method initializeAddons + */ +Project.prototype.initializeAddons = function() { + if (this._addonsInitialized) { + return; + } + this._addonsInitialized = true; + + debug('initializeAddons for: %s', this.name()); + + this.discoverAddons(); + + this.addons = this.addonsFactory.initializeAddons(this.addonPackages); + + this.addons.forEach(function(addon) { + debug('addon: %s', addon.name); + }); +}; + +/** + Returns what commands are made available by addons by inspecting + `includedCommands` for every addon. + + @private + @method addonCommands + @return {Object} Addon names and command maps as key-value pairs + */ +Project.prototype.addonCommands = function() { + var commands = {}; + this.addons.forEach(function(addon) { + var includedCommands = (addon.includedCommands && addon.includedCommands()) || {}; + var addonCommands = {}; + + for (var key in includedCommands) { + if (typeof includedCommands[key] === 'function') { + addonCommands[key] = includedCommands[key]; + } else { + addonCommands[key] = Command.extend(includedCommands[key]); + } + } + if (Object.keys(addonCommands).length) { + commands[addon.name] = addonCommands; + } + }); + return commands; +}; + +/** + Execute a given callback for every addon command. + Example: + + ``` + project.eachAddonCommand(function(addonName, commands) { + console.log('Addon ' + addonName + ' exported the following commands:' + commands.keys().join(', ')); + }); + ``` + + @private + @method eachAddonCommand + @param {Function} callback [description] + */ +Project.prototype.eachAddonCommand = function(callback) { + if (this.initializeAddons && this.addonCommands) { + this.initializeAddons(); + var addonCommands = this.addonCommands(); + + forOwn(addonCommands, function(commands, addonName) { + return callback(addonName, commands); + }); + } +}; + +/** + Path to the blueprints for this project. + + @private + @method localBlueprintLookupPath + @return {String} Path to blueprints + */ +Project.prototype.localBlueprintLookupPath = function() { + return path.join(this.root, 'blueprints'); +}; + +/** + Returns a list of paths (including addon paths) where blueprints will be looked up. + + @private + @method blueprintLookupPaths + @return {Array} List of paths + */ +Project.prototype.blueprintLookupPaths = function() { + if (this.isEmberCLIProject()) { + var lookupPaths = [this.localBlueprintLookupPath()]; + var addonLookupPaths = this.addonBlueprintLookupPaths(); + + return lookupPaths.concat(addonLookupPaths); + } else { + return this.addonBlueprintLookupPaths(); + } +}; + +/** + Returns a list of addon paths where blueprints will be looked up. + + @private + @method addonBlueprintLookupPaths + @return {Array} List of paths + */ +Project.prototype.addonBlueprintLookupPaths = function() { + var addonPaths = this.addons.map(function(addon) { + if (addon.blueprintsPath) { + return addon.blueprintsPath(); + } + }, this); + + return addonPaths.filter(Boolean).reverse(); +}; + +/** + Reloads package.json + + @private + @method reloadPkg + @return {Object} Package content + */ +Project.prototype.reloadPkg = function() { + var pkgPath = path.join(this.root, 'package.json'); + + // We use readFileSync instead of require to avoid the require cache. + this.pkg = JSON.parse(fs.readFileSync(pkgPath, { encoding: 'utf-8' })); + + return this.pkg; +}; + +/** + Re-initializes addons. + + @private + @method reloadAddons + */ +Project.prototype.reloadAddons = function() { + this.reloadPkg(); + this._addonsInitialized = false; + return this.initializeAddons(); +}; + +/** + Find an addon by its name + + @private + @method findAddonByName + @param {String} name Addon name as specified in package.json + @return {Addon} Addon instance + */ +Project.prototype.findAddonByName = function(name) { + this.initializeAddons(); + + var exactMatch = find(this.addons, function(addon) { + return name === addon.name || (addon.pkg && name === addon.pkg.name); + }); + + if (exactMatch) { + return exactMatch; + } + + return find(this.addons, function(addon) { + return name.indexOf(addon.name) > -1 || (addon.pkg && name.indexOf(addon.pkg.name) > -1); + }); +}; + +/** + Generate test file contents. + + This method is supposed to be overwritten by test framework addons + like `ember-cli-qunit` and `ember-cli-mocha`. + + @public + @method generateTestFile + @param {String} moduleName Name of the test module (e.g. `JSHint`) + @param {Object[]} tests Array of tests with `name`, `passed` and `errorMessage` properties + @return {String} The test file content + */ +Project.prototype.generateTestFile = function(/* moduleName, tests */) { + var message = 'Please install an Ember.js test framework addon or update your dependencies.'; + + if (this.ui) { + this.ui.writeDeprecateLine(message) + } else { + console.warn(message); + } + + return ''; +}; + +/** + Returns a new project based on the first package.json that is found + in `pathName`. + + @private + @static + @method closest + @param {String} pathName Path to your project + @return {Promise} Promise which resolves to a {Project} + */ +Project.closest = function(pathName, _ui, _cli) { + var ui = ensureUI(_ui); + return closestPackageJSON(pathName) + .then(function(result) { + debug('closest %s -> %s', pathName, result); + if (result.pkg && result.pkg.name === 'ember-cli') { + return Project.nullProject(_ui, _cli); + } + + return new Project(result.directory, result.pkg, ui, _cli); + }) + .catch(function(reason) { + handleFindupError(pathName, reason); + }); +}; + +/** + Returns a new project based on the first package.json that is found + in `pathName`. + + @private + @static + @method closestSync + @param {String} pathName Path to your project + @param {UI} _ui The UI instance to provide to the created Project. + @return {Project} Project instance + */ +Project.closestSync = function(pathName, _ui, _cli) { + var ui = ensureUI(_ui); + var directory, pkg; + + if (_cli && _cli.testing) { + directory = existsSync(path.join(pathName, 'package.json')) && process.cwd(); + if (!directory) { + if (pathName.indexOf(path.sep + 'app') > -1) { + directory = findupPath(pathName); + } else { + pkg = {name: 'ember-cli'}; + } + } + } else { + directory = findupPath(pathName); + } + if (!pkg) { + pkg = JSON.parse(fs.readFileSync(path.join(directory, 'package.json'))); + } + + debug('dir' + directory); + debug('pkg: %s', pkg); + if (pkg && pkg.name === 'ember-cli') { + return Project.nullProject(_ui, _cli); + } + + debug('closestSync %s -> %s', pathName, directory); + return new Project(directory, pkg, ui, _cli); +}; + +/** + Returns a new project based on the first package.json that is found + in `pathName`, or the nullProject. + + The nullProject signifies no-project, but abides by the null object pattern + + @private + @static + @method projectOrnullProject + @param {UI} _ui The UI instance to provide to the created Project. + @return {Project} Project instance + */ +Project.projectOrnullProject = function(_ui, _cli) { + try { + return Project.closestSync(process.cwd(), _ui, _cli); + } catch (reason) { + if (reason instanceof Project.NotFoundError) { + return Project.nullProject(_ui, _cli); + } else { + throw reason; + } + } +}; + +/** + Returns the project root based on the first package.json that is found + + @return {String} The project root directory + */ +Project.getProjectRoot = function () { + try { + var directory = findup.sync(process.cwd(), 'package.json'); + var pkg = require(path.join(directory, 'package.json')); + + if (pkg && pkg.name === 'ember-cli') { + debug('getProjectRoot: named \'ember-cli\'. Will use cwd: %s', process.cwd()); + return process.cwd(); + } + + debug('getProjectRoot %s -> %s', process.cwd(), directory); + return directory; + } catch (reason) { + if (isFindupError(reason)) { + debug('getProjectRoot: not found. Will use cwd: %s', process.cwd()); + return process.cwd(); + } else { + throw reason; + } + } +}; + +function NotFoundError(message) { + this.name = 'NotFoundError'; + this.message = message; + this.stack = (new Error()).stack; +} + +NotFoundError.prototype = Object.create(Error.prototype); +NotFoundError.prototype.constructor = NotFoundError; + +Project.NotFoundError = NotFoundError; + +function ensureUI(_ui) { + var ui = _ui; + + if (!ui) { + // TODO: one UI (lib/cli/index.js also has one for now...) + ui = new UI({ + inputStream: process.stdin, + outputStream: process.stdout, + ci: process.env.CI || /^(dumb|emacs)$/.test(process.env.TERM), + writeLevel: ~process.argv.indexOf('--silent') ? 'ERROR' : undefined + }); + } + + return ui; +} + +function closestPackageJSON(pathName) { + return findup(pathName, 'package.json') + .then(function(directory) { + return Promise.hash({ + directory: directory, + pkg: require(path.join(directory, 'package.json')) + }); + }); +} + +function findupPath(pathName) { + try { + return findup.sync(pathName, 'package.json'); + } catch (reason) { + handleFindupError(pathName, reason); + } +} + +function isFindupError(reason) { + // Would be nice if findup threw error subclasses + return reason && /not found/i.test(reason.message); +} + +function handleFindupError(pathName, reason) { + if (isFindupError(reason)) { + throw new NotFoundError('No project found at or up from: `' + pathName + '`'); + } else { + throw reason; + } +} + +// Export +module.exports = Project; diff --git a/packages/ember-cli/lib/models/server-watcher.js b/packages/ember-cli/lib/models/server-watcher.js new file mode 100644 index 000000000000..129a0f100757 --- /dev/null +++ b/packages/ember-cli/lib/models/server-watcher.js @@ -0,0 +1,61 @@ +'use strict'; + +var Task = require('./task'); + +module.exports = Task.extend({ + verbose: true, + + init: function() { + this.watcher = this.watcher || new (require('sane'))(this.watchedDir, { + verbose: this.verbose, + poll: this.polling() + }); + + this.watcher.on('change', this.didChange.bind(this)); + this.watcher.on('add', this.didAdd.bind(this)); + this.watcher.on('delete', this.didDelete.bind(this)); + }, + + didChange: function (filepath) { + this.ui.writeLine('Server file changed: ' + filepath); + + this.analytics.track({ + name: 'server file change', + description: 'File changed: "' + filepath + '"' + }); + }, + + didAdd: function (filepath) { + this.ui.writeLine('Server file added: ' + filepath); + + this.analytics.track({ + name: 'server file addition', + description: 'File added: "' + filepath + '"' + }); + }, + + didDelete: function (filepath) { + this.ui.writeLine('Server file deleted: ' + filepath); + + this.analytics.track({ + name: 'server file deletion', + description: 'File deleted: "' + filepath + '"' + }); + }, + + then: function() { + return this.watcher.then.apply(this.watcher, arguments); + }, + + on: function() { + this.watcher.on.apply(this.watcher, arguments); + }, + + off: function() { + this.watcher.off.apply(this.watcher, arguments); + }, + + polling: function () { + return this.options && this.options.watcher === 'polling'; + } +}); diff --git a/packages/ember-cli/lib/models/task.js b/packages/ember-cli/lib/models/task.js new file mode 100644 index 000000000000..09754c95e17d --- /dev/null +++ b/packages/ember-cli/lib/models/task.js @@ -0,0 +1,15 @@ +'use strict'; + +var CoreObject = require('core-object'); + +function Task() { + CoreObject.apply(this, arguments); +} + +module.exports = Task; + +Task.__proto__ = CoreObject; + +Task.prototype.run = function(/*options*/) { + throw new Error('Task needs to have run() defined.'); +}; diff --git a/packages/ember-cli/lib/models/update-checker.js b/packages/ember-cli/lib/models/update-checker.js new file mode 100644 index 000000000000..2fa371c075b4 --- /dev/null +++ b/packages/ember-cli/lib/models/update-checker.js @@ -0,0 +1,104 @@ +'use strict'; + +var Promise = require('../ext/promise'); +var versionUtils = require('../utilities/version-utils'); +var chalk = require('chalk'); +var debug = require('debug')('ember-cli:update-checker'); +var emberCLIVersion = versionUtils.emberCLIVersion; + +module.exports = UpdateChecker; + +function UpdateChecker(ui, settings, localVersion) { + this.ui = ui; + this.settings = settings; + this.localVersion = localVersion || emberCLIVersion(); + this.versionConfig = null; + + debug('version: %s', this.localVersion); + debug('version: %o', this.settings); +} + +/** +* Checks local config or npm for most recent version of ember-cli +*/ +UpdateChecker.prototype.checkForUpdates = function() { + // if 'checkForUpdates' is true, check for an updated ember-cli version + debug('checkingcheckForUpdates: %o', this.settings.checkingcheckForUpdates); + if (this.settings.checkForUpdates) { + return this.doCheck().then(function(updateInfo) { + debug('updatedNeeded %o', updateInfo.updateNeeded); + if (updateInfo.updateNeeded) { + this.ui.writeLine(''); + this.ui.writeLine('A new version of ember-cli is available (' + + updateInfo.newestVersion + ').'); + } + return updateInfo; + }.bind(this)); + } else { + return Promise.resolve({ + updateNeeded: false + }); + } +}; + +UpdateChecker.prototype.doCheck = function() { + this.versionConfig = this.versionConfig || new (require('configstore'))('ember-cli-version'); + var lastVersionCheckAt = this.versionConfig.get('lastVersionCheckAt'); + var now = new Date().getTime(); + + return new Promise(function(resolve, reject) { + // if the last check was less than a day ago, don't remotely check version + if (lastVersionCheckAt && lastVersionCheckAt > (now - 86400000)) { + resolve(this.versionConfig.get('newestVersion')); + } + + reject(); + }.bind(this)).catch(function() { + return this.checkNPM(); + }.bind(this)).then(function(version) { + var isDevBuild = versionUtils.isDevelopment(this.localVersion); + var updateNeeded = false; + + if (!isDevBuild) { + updateNeeded = version && require('semver').lt(this.localVersion, version); + } + + return { + updateNeeded: updateNeeded, + newestVersion: version + }; + }.bind(this)); +}; + +UpdateChecker.prototype.checkNPM = function() { + // use npm to determine the currently availabe ember-cli version + var loadNPM = Promise.denodeify(require('npm').load); + var fetchEmberCliVersion = function(npm) { + return Promise.denodeify(npm.commands.view)(['ember-cli', 'version']); + }; + var extractVersion = function(data) { return Object.keys(data)[0]; }; + + return loadNPM({ + 'loglevel': 'silent', + 'fetch-retries': 1, + 'cache-min': 1, + 'cache-max': 0 + }) + .then(fetchEmberCliVersion) + .then(extractVersion) + .then(this.saveVersionInformation.bind(this)) + .catch(function() { + this.ui.writeLine(chalk.red('An error occurred while checking for Ember CLI updates. ' + + 'Please verify your internet connectivity and npm configurations.')); + return false; + }.bind(this)); +}; + +UpdateChecker.prototype.saveVersionInformation = function(version) { + var versionConfig = this.versionConfig; + var now = new Date().getTime(); + + // save version so we don't have to check again for another day + versionConfig.set('newestVersion', version); + versionConfig.set('lastVersionCheckAt', now); +}; diff --git a/packages/ember-cli/lib/models/watcher.js b/packages/ember-cli/lib/models/watcher.js new file mode 100644 index 000000000000..edee470d9a20 --- /dev/null +++ b/packages/ember-cli/lib/models/watcher.js @@ -0,0 +1,134 @@ +'use strict'; + +var chalk = require('chalk'); +var Task = require('./task'); +var debug = require('debug')('ember-cli:watcher'); +var Promise = require('../ext/promise'); +var exec = Promise.denodeify(require('child_process').exec); +var isWin = /^win/.test(process.platform); + +var Watcher = Task.extend({ + verbose: true, + + init: function() { + var options = this.buildOptions(); + + debug('initialize %o', options); + + this.watcher = this.watcher || new (require('broccoli-sane-watcher'))(this.builder, options); + + this.watcher.on('error', this.didError.bind(this)); + this.watcher.on('change', this.didChange.bind(this)); + }, + + didError: function(error) { + debug('didError %o', error); + this.ui.writeError(error); + this.analytics.trackError({ + description: error && error.message + }); + }, + + then: function() { + return this.watcher.then.apply(this.watcher, arguments); + }, + + didChange: function(results) { + debug('didChange %o', results); + var totalTime = results.totalTime / 1e6; + + this.ui.writeLine(''); + this.ui.writeLine(chalk.green('Build successful - ' + Math.round(totalTime) + 'ms.')); + + this.analytics.track({ + name: 'ember rebuild', + message: 'broccoli rebuild time: ' + totalTime + 'ms' + }); + + this.analytics.trackTiming({ + category: 'rebuild', + variable: 'rebuild time', + label: 'broccoli rebuild time', + value: parseInt(totalTime, 10) + }); + }, + + on: function() { + this.watcher.on.apply(this.watcher, arguments); + }, + + off: function() { + this.watcher.off.apply(this.watcher, arguments); + }, + buildOptions: function() { + var watcher = this.options && this.options.watcher; + + if (watcher && ['polling', 'watchman', 'node', 'events'].indexOf(watcher) === -1) { + throw new Error('Unknown watcher type --watcher=[polling|watchman|node] but was: ' + watcher); + } + + return { + verbose: this.verbose, + poll: watcher === 'polling', + watchman: watcher === 'watchman' || watcher === 'events', + node: watcher === 'node' + }; + } +}); + +Watcher.detectWatcher = function(ui, _options) { + var options = _options || {}; + var watchmanInfo = 'Visit http://ember-cli.com/user-guide/#watchman for more info.'; + + if (options.watcher === 'polling') { + debug('skip detecting watchman, poll instead'); + return Promise.resolve(options); + } else if (options.watcher === 'node') { + debug('skip detecting watchman, node instead'); + return Promise.resolve(options); + } else if (isWin) { + debug('watchman isn\'t supported on windows, node instead'); + options.watcher = 'node'; + return Promise.resolve(options); + } else { + debug('detecting watchman'); + return exec('watchman version').then(function(output) { + var version; + try { + version = JSON.parse(output).version; + } catch (e) { + options.watcher = 'node'; + ui.writeLine('Looks like you have a different program called watchman, falling back to NodeWatcher.'); + ui.writeLine(watchmanInfo); + return options; + } + debug('detected watchman: %s', version); + + var semver = require('semver'); + if (semver.satisfies(version, '>= 3.0.0')) { + debug('watchman %s does satisfy: %s', version, '>= 3.0.0'); + options.watcher = 'watchman'; + options._watchmanInfo = { + enabled: true, + version: version, + canNestRoots: semver.satisfies(version, '>= 3.7.0') + }; + } else { + debug('watchman %s does NOT satisfy: %s', version, '>= 3.0.0'); + ui.writeLine('Invalid watchman found, version: [' + version + '] did not satisfy [>= 3.0.0], falling back to NodeWatcher.'); + ui.writeLine(watchmanInfo); + options.watcher = 'node'; + } + + return options; + }, function(reason) { + debug('detecting watchman failed %o', reason); + ui.writeLine('Could not start watchman; falling back to NodeWatcher for file system events.'); + ui.writeLine(watchmanInfo); + options.watcher = 'node'; + return options; + }); + } +}; + +module.exports = Watcher; diff --git a/packages/ember-cli/lib/tasks/addon-install.js b/packages/ember-cli/lib/tasks/addon-install.js new file mode 100644 index 000000000000..caec02b3a1c7 --- /dev/null +++ b/packages/ember-cli/lib/tasks/addon-install.js @@ -0,0 +1,81 @@ +'use strict'; + +var Task = require('../models/task'); +var SilentError = require('silent-error'); +var merge = require('lodash/merge'); +var getPackageBaseName = require('../utilities/get-package-base-name'); +var Promise = require('../ext/promise'); + +module.exports = Task.extend({ + init: function() { + this.NpmInstallTask = this.NpmInstallTask || require('./npm-install'); + this.BlueprintTask = this.BlueprintTask || require('./generate-from-blueprint'); + }, + + run: function(options) { + var chalk = require('chalk'); + var ui = this.ui; + var packageNames = options['packages']; + var blueprintOptions = options.blueprintOptions || {}; + + var npmInstall = new this.NpmInstallTask({ + ui: this.ui, + analytics: this.analytics, + project: this.project + }); + + var blueprintInstall = new this.BlueprintTask({ + ui: this.ui, + analytics: this.analytics, + project: this.project, + testing: this.testing + }); + + ui.startProgress(chalk.green('Installing addon package'), chalk.green('.')); + + return npmInstall.run({ + packages: packageNames, + 'save-dev': true, + 'save-exact': true + }).then(function() { + return this.project.reloadAddons(); + }.bind(this)).then(function() { + return this.installBlueprint(blueprintInstall, packageNames, blueprintOptions); + }.bind(this)) + .finally(function() { ui.stopProgress(); }) + .then(function() { + ui.writeLine(chalk.green('Installed addon package.')); + }); + }, + + installBlueprint: function(install, packageNames, blueprintOptions) { + var blueprintName, taskOptions, addonInstall = this; + + return packageNames.reduce(function(promise, packageName) { + return promise.then(function() { + blueprintName = addonInstall.findDefaultBlueprintName(packageName); + taskOptions = merge({ + args: [blueprintName], + ignoreMissingMain: true + }, blueprintOptions || {}); + return install.run(taskOptions); + }); + }, Promise.resolve()); + }, + + findDefaultBlueprintName: function(givenName) { + var addon = this.project.findAddonByName(givenName); + + if (!addon) { + throw new SilentError('Install failed. Could not find addon with name: ' + givenName); + } + + var emberAddon = addon.pkg['ember-addon']; + + if (emberAddon && emberAddon.defaultBlueprint) { + return emberAddon.defaultBlueprint; + } + + return getPackageBaseName(addon.pkg.name); + } +}); diff --git a/packages/ember-cli/lib/tasks/bower-install.js b/packages/ember-cli/lib/tasks/bower-install.js new file mode 100644 index 000000000000..81fe4b582c13 --- /dev/null +++ b/packages/ember-cli/lib/tasks/bower-install.js @@ -0,0 +1,57 @@ +'use strict'; + +// Runs `bower install` in cwd + +var Promise = require('../ext/promise'); +var Task = require('../models/task'); + +module.exports = Task.extend({ + init: function() { + this.bower = this.bower || require('bower'); + this.bowerConfig = this.bowerConfig || require('bower-config'); + }, + // Options: Boolean verbose + run: function(options) { + var chalk = require('chalk'); + var bower = this.bower; + var bowerConfig = this.bowerConfig; + var ui = this.ui; + var packages = options.packages || []; + var installOptions = options.installOptions || { save: true }; + + ui.startProgress(chalk.green('Installing browser packages via Bower'), chalk.green('.')); + + var config = bowerConfig.read(); + config.interactive = true; + + return new Promise(function(resolve, reject) { + bower.commands.install(packages, installOptions, config) // Packages, options, config + .on('log', logBowerMessage) + .on('prompt', ui.prompt.bind(ui)) + .on('error', reject) + .on('end', resolve); + }) + .finally(function() { ui.stopProgress(); }) + .then(function() { + ui.writeLine(chalk.green('Installed browser packages via Bower.')); + }); + + function logBowerMessage(message) { + if (message.level === 'conflict') { + // e.g. + // conflict Unable to find suitable version for ember-data + // 1) ember-data 1.0.0-beta.6 + // 2) ember-data ~1.0.0-beta.7 + ui.writeLine(' ' + chalk.red('conflict') + ' ' + message.message); + message.data.picks.forEach(function(pick, index) { + ui.writeLine(' ' + chalk.green((index + 1) + ')') + ' ' + + message.data.name + ' ' + pick.endpoint.target); + }); + } else if (message.level === 'info' && options.verbose) { + // e.g. + // cached git://example.com/some-package.git#1.0.0 + ui.writeLine(' ' + chalk.green(message.id) + ' ' + message.message); + } + } + } +}); diff --git a/packages/ember-cli/lib/tasks/build-watch.js b/packages/ember-cli/lib/tasks/build-watch.js new file mode 100644 index 000000000000..92c7029fc65a --- /dev/null +++ b/packages/ember-cli/lib/tasks/build-watch.js @@ -0,0 +1,29 @@ +'use strict'; + +var chalk = require('chalk'); +var Task = require('../models/task'); +var Watcher = require('../models/watcher'); +var Builder = require('../models/builder'); +var Promise = require('../ext/promise'); + +module.exports = Task.extend({ + run: function(options) { + this.ui.startProgress( + chalk.green('Building'), chalk.green('.') + ); + + return new Watcher({ + ui: this.ui, + builder: new Builder({ + ui: this.ui, + outputPath: options.outputPath, + environment: options.environment, + project: this.project + }), + analytics: this.analytics, + options: options + }).then(function() { + return new Promise(function () {}); // Run until failure or signal to exit + }); + } +}); diff --git a/packages/ember-cli/lib/tasks/build.js b/packages/ember-cli/lib/tasks/build.js new file mode 100644 index 000000000000..ae03e57efd0c --- /dev/null +++ b/packages/ember-cli/lib/tasks/build.js @@ -0,0 +1,52 @@ +'use strict'; + +var chalk = require('chalk'); +var Task = require('../models/task'); +var Builder = require('../models/builder'); + +module.exports = Task.extend({ + // Options: String outputPath + run: function(options) { + var ui = this.ui; + var analytics = this.analytics; + + ui.startProgress(chalk.green('Building'), chalk.green('.')); + + var builder = new Builder({ + ui: ui, + outputPath: options.outputPath, + environment: options.environment, + project: this.project + }); + + return builder.build() + .then(function(results) { + var totalTime = results.totalTime / 1e6; + + analytics.track({ + name: 'ember build', + message: totalTime + 'ms' + }); + + analytics.trackTiming({ + category: 'rebuild', + variable: 'build time', + label: 'broccoli build time', + value: parseInt(totalTime, 10) + }); + }) + .finally(function() { + ui.stopProgress(); + return builder.cleanup(); + }) + .then(function() { + ui.writeLine(chalk.green('Built project successfully. Stored in "' + + options.outputPath + '".')); + }) + .catch(function(err) { + ui.writeLine(chalk.red('Build failed.')); + + throw err; + }); + } +}); diff --git a/packages/ember-cli/lib/tasks/create-and-step-into-directory.js b/packages/ember-cli/lib/tasks/create-and-step-into-directory.js new file mode 100644 index 000000000000..b4fea890fbb8 --- /dev/null +++ b/packages/ember-cli/lib/tasks/create-and-step-into-directory.js @@ -0,0 +1,46 @@ +'use strict'; + +// Creates a directory with the name directoryName in cwd and then sets cwd to +// this directory. + +var Promise = require('../ext/promise'); +var fs = require('fs'); +var existsSync = require('exists-sync'); +var mkdir = Promise.denodeify(fs.mkdir); +var Task = require('../models/task'); +var SilentError = require('silent-error'); + +module.exports = Task.extend({ + // Options: String directoryName, Boolean: dryRun + + warnDirectoryAlreadyExists: function warnDirectoryAlreadyExists() { + var message = 'Directory \'' + this.directoryName + '\' already exists.'; + return new SilentError(message); + }, + + run: function(options) { + var directoryName = this.directoryName = options.directoryName; + if (options.dryRun) { + return new Promise(function(resolve, reject) { + if (existsSync(directoryName)) { + return reject(this.warnDirectoryAlreadyExists()); + } + resolve(); + }.bind(this)); + } + + return mkdir(directoryName) + .catch(function(err) { + if (err.code === 'EEXIST') { + throw this.warnDirectoryAlreadyExists(); + } else { + throw err; + } + }.bind(this)) + .then(function() { + var cwd = process.cwd(); + process.chdir(directoryName); + return { initialDirectory: cwd }; + }); + } +}); diff --git a/packages/ember-cli/lib/tasks/destroy-from-blueprint.js b/packages/ember-cli/lib/tasks/destroy-from-blueprint.js new file mode 100644 index 000000000000..bc50961b25fa --- /dev/null +++ b/packages/ember-cli/lib/tasks/destroy-from-blueprint.js @@ -0,0 +1,9 @@ +/*jshint quotmark: false*/ + +'use strict'; + +var Generate = require('./generate-from-blueprint'); + +module.exports = Generate.extend({ + blueprintFunction: 'uninstall' +}); diff --git a/packages/ember-cli/lib/tasks/generate-from-blueprint.js b/packages/ember-cli/lib/tasks/generate-from-blueprint.js new file mode 100644 index 000000000000..ccdc7368da75 --- /dev/null +++ b/packages/ember-cli/lib/tasks/generate-from-blueprint.js @@ -0,0 +1,96 @@ +/*jshint quotmark: false*/ + +'use strict'; + +var Promise = require('../ext/promise'); +var Blueprint = require('../models/blueprint'); +var Task = require('../models/task'); +var parseOptions = require('../utilities/parse-options'); +var merge = require('lodash/merge'); + +module.exports = Task.extend({ + blueprintFunction: 'install', + + run: function(options) { + var self = this; + var name = options.args[0]; + var noAddonBlueprint = ['mixin', 'blueprint-test']; + + var mainBlueprint = this.lookupBlueprint(name, options.ignoreMissingMain); + var testBlueprint = this.lookupBlueprint(name + '-test', true); + // lookup custom addon blueprint + var addonBlueprint = this.lookupBlueprint(name + '-addon', true); + // otherwise, use default addon-import + + if (noAddonBlueprint.indexOf(name) < 0 && !addonBlueprint && (mainBlueprint && mainBlueprint.supportsAddon()) && options.args[1]) { + addonBlueprint = this.lookupBlueprint('addon-import', true); + } + + if (options.ignoreMissingMain && !mainBlueprint) { + return Promise.resolve(); + } + + if (options.dummy) { + // don't install test or addon reexport for dummy + if (this.project.isEmberCLIAddon()) { + testBlueprint = null; + addonBlueprint = null; + } + } + + var entity = { + name: options.args[1], + options: parseOptions(options.args.slice(2)) + }; + + var blueprintOptions = { + target: this.project.root, + entity: entity, + ui: this.ui, + analytics: this.analytics, + project: this.project, + settings: this.settings, + testing: this.testing, + taskOptions: options, + originBlueprintName: name + }; + + blueprintOptions = merge(blueprintOptions, options || {}); + + return mainBlueprint[this.blueprintFunction](blueprintOptions) + .then(function() { + if (!testBlueprint) { return; } + + if (testBlueprint.locals === Blueprint.prototype.locals) { + testBlueprint.locals = function(options) { + return mainBlueprint.locals(options); + }; + } + + var testBlueprintOptions = merge({} , blueprintOptions, { installingTest: true }); + + return testBlueprint[self.blueprintFunction](testBlueprintOptions); + }) + .then(function() { + if (!addonBlueprint || name.match(/-addon/)) { return; } + if (!this.project.isEmberCLIAddon() && blueprintOptions.inRepoAddon === null) { return; } + + if (addonBlueprint.locals === Blueprint.prototype.locals) { + addonBlueprint.locals = function(options) { + return mainBlueprint.locals(options); + }; + } + + var addonBlueprintOptions = merge({}, blueprintOptions, { installingAddon: true }); + + return addonBlueprint[self.blueprintFunction](addonBlueprintOptions); + }.bind(this)); + }, + + lookupBlueprint: function(name, ignoreMissing) { + return Blueprint.lookup(name, { + paths: this.project.blueprintLookupPaths(), + ignoreMissing: ignoreMissing + }); + } +}); diff --git a/packages/ember-cli/lib/tasks/git-init.js b/packages/ember-cli/lib/tasks/git-init.js new file mode 100644 index 000000000000..11fcf4e10e12 --- /dev/null +++ b/packages/ember-cli/lib/tasks/git-init.js @@ -0,0 +1,50 @@ +'use strict'; + +var Promise = require('../../lib/ext/promise'); +var Task = require('../models/task'); +var exec = Promise.denodeify(require('child_process').exec); +var path = require('path'); +var pkg = require('../../package.json'); +var fs = require('fs'); +var template = require('lodash/template'); + +var gitEnvironmentVariables = { + GIT_AUTHOR_NAME: 'Tomster', + GIT_AUTHOR_EMAIL: 'tomster@emberjs.com', + get GIT_COMMITTER_NAME() { return this.GIT_AUTHOR_NAME; }, + get GIT_COMMITTER_EMAIL() { return this.GIT_AUTHOR_EMAIL; } +}; + +module.exports = Task.extend({ + run: function(commandOptions) { + var chalk = require('chalk'); + var ui = this.ui; + + if (commandOptions.skipGit) { + return Promise.resolve(); + } + + return exec('git --version') + .then(function() { + return exec('git init') + .then(function() { + return exec('git add .'); + }) + .then(function() { + var commitTemplate = fs.readFileSync(path.join(__dirname, '../utilities/COMMIT_MESSAGE.txt')); + var commitMessage = template(commitTemplate)(pkg); + return exec('git commit -m "' + commitMessage + '"', {env: gitEnvironmentVariables}); + }) + .then(function() { + ui.writeLine(chalk.green('Successfully initialized git.')); + }); + }) + .catch(function(error) { + if (commandOptions.logErrors) { + ui.writeError(error); + } + // if git is not found or an error was thrown during the `git` + // init process just swallow any errors here + }); + } +}); diff --git a/packages/ember-cli/lib/tasks/install-blueprint.js b/packages/ember-cli/lib/tasks/install-blueprint.js new file mode 100644 index 000000000000..a9fc4d1f4134 --- /dev/null +++ b/packages/ember-cli/lib/tasks/install-blueprint.js @@ -0,0 +1,56 @@ +'use strict'; + +var Blueprint = require('../models/blueprint'); +var Task = require('../models/task'); +var Promise = require('../ext/promise'); +var isGitRepo = require('is-git-url'); +var temp = require('temp'); +var childProcess = require('child_process'); +var path = require('path'); +var merge = require('lodash/merge'); + +var mkdir = Promise.denodeify(temp.mkdir); +var exec = Promise.denodeify(childProcess.exec); + +module.exports = Task.extend({ + run: function(options) { + var cwd = process.cwd(); + var name = options.rawName; + var blueprintOption = options.blueprint; + // If we're in a dry run, pretend we changed directories. + // Pretending we cd'd avoids prompts in the actual current directory. + var fakeCwd = path.join(cwd, name); + var target = options.dryRun ? fakeCwd : cwd; + + var installOptions = { + target: target, + entity: { name: name }, + ui: this.ui, + analytics: this.analytics, + project: this.project, + dryRun: options.dryRun, + targetFiles: options.targetFiles, + rawArgs: options.rawArgs + }; + + installOptions = merge(installOptions, options || {}); + + if (isGitRepo(blueprintOption)) { + return mkdir('ember-cli').then(function(pathName) { + var execArgs = ['git', 'clone', blueprintOption, pathName].join(' '); + return exec(execArgs).then(function() { + return exec('npm install', {cwd: pathName}).then(function() { + var blueprint = Blueprint.load(pathName); + return blueprint.install(installOptions); + }); + }); + }); + } else { + var blueprintName = blueprintOption || 'app'; + var blueprint = Blueprint.lookup(blueprintName, { + paths: this.project.blueprintLookupPaths() + }); + return blueprint.install(installOptions); + } + } +}); diff --git a/packages/ember-cli/lib/tasks/npm-install.js b/packages/ember-cli/lib/tasks/npm-install.js new file mode 100644 index 000000000000..40fa58af9cbe --- /dev/null +++ b/packages/ember-cli/lib/tasks/npm-install.js @@ -0,0 +1,11 @@ +'use strict'; + +// Runs `npm install` in cwd + +var NpmTask = require('./npm-task'); + +module.exports = NpmTask.extend({ + command: 'install', + startProgressMessage: 'Installing packages for tooling via npm', + completionMessage: 'Installed packages for tooling via npm.' +}); diff --git a/packages/ember-cli/lib/tasks/npm-task.js b/packages/ember-cli/lib/tasks/npm-task.js new file mode 100644 index 000000000000..048e184983ce --- /dev/null +++ b/packages/ember-cli/lib/tasks/npm-task.js @@ -0,0 +1,64 @@ +'use strict'; + +// Runs `npm install` in cwd + +var chalk = require('chalk'); +var Task = require('../models/task'); +var Promise = require('../ext/promise'); + +var spawn = Promise.denodeify(require('child_process').spawn); + + +module.exports = Task.extend({ + // The command to run: can be 'install' or 'uninstall' + command: '', + // Message to send to ui.startProgress + startProgressMessage: '', + // Message to send to ui.writeLine on completion + completionMessage: '', + + init: function() { + }, + // Options: Boolean verbose + run: function(options) { + this.ui.startProgress(chalk.green(this.startProgressMessage), chalk.green('.')); + + var npmOptions = { + loglevel: options.verbose ? 'verbose' : 'error', + logstream: this.ui.outputStream, + color: 'always', + // by default, do install peoples optional deps + 'optional': 'optional' in options ? options.optional : true, + 'save-dev': !!options['save-dev'], + 'save-exact': !!options['save-exact'] + }; + + var packages = options.packages || []; + + // npm otherwise is otherwise noisy, already submitted PR for npm to fix + // misplaced console.log + this.disableLogger(); + return spawn('npm', [this.command].concat(packages, npmOptions)). + // return npm(this.command, packages, npmOptions, this.npm). + finally(this.finally.bind(this)). + then(this.announceCompletion.bind(this)); + }, + + announceCompletion: function() { + this.ui.writeLine(chalk.green(this.completionMessage)); + }, + + finally: function() { + this.ui.stopProgress(); + this.restoreLogger(); + }, + + disableLogger: function() { + this.oldLog = console.log; + console.log = function() {}; + }, + + restoreLogger: function() { + console.log = this.oldLog; // Hack, see above + } +}); diff --git a/packages/ember-cli/lib/tasks/npm-uninstall.js b/packages/ember-cli/lib/tasks/npm-uninstall.js new file mode 100644 index 000000000000..79db8f8a0ace --- /dev/null +++ b/packages/ember-cli/lib/tasks/npm-uninstall.js @@ -0,0 +1,11 @@ +'use strict'; + +// Runs `npm uninstall` in cwd + +var NpmTask = require('./npm-task'); + +module.exports = NpmTask.extend({ + command: 'uninstall', + startProgressMessage: 'Uninstalling packages for tooling via npm', + completionMessage: 'Uninstalled packages for tooling via npm.' +}); diff --git a/packages/ember-cli/lib/tasks/update.js b/packages/ember-cli/lib/tasks/update.js new file mode 100644 index 000000000000..df64550200ae --- /dev/null +++ b/packages/ember-cli/lib/tasks/update.js @@ -0,0 +1,118 @@ +'use strict'; + +var Promise = require('../ext/promise'); +var chalk = require('chalk'); +var Task = require('../models/task'); +var fs = require('fs'); +var path = require('path'); + +function npmInstall(npm) { + return Promise.denodeify(npm.commands.install)(['ember-cli']); +} + +module.exports = Task.extend({ + init: function() { + this.npm = this.npm || require('npm'); + }, + + run: function(options, updateInfo) { + var env = options.environment || 'development'; + + process.env.EMBER_ENV = process.env.EMBER_ENV || env; + + this.ui.writeLine(''); + this.ui.writeLine(chalk.yellow('A new version of ember-cli is available (' + + updateInfo.newestVersion + ').')); + + var updatePrompt = { + type: 'confirm', + name: 'answer', + message: 'Are you sure you want to update ember-cli?', + choices: [ + { key: 'y', name: 'Yes, update', value: 'yes' }, + { key: 'n', name: 'No, cancel', value: 'no' } + ] + }; + + return this.ui.prompt(updatePrompt).then(function(response) { + if (response.answer === true) { + return this.runNpmUpdate(updateInfo.newestVersion); + } + }.bind(this)); + }, + + runNpmUpdate: function(newestVersion) { + this.ui.startProgress(chalk.green('Updating ember-cli'), chalk.green('.')); + + // first, run `npm install -g ember-cli` + var npm = this.npm; + var loadNPM = Promise.denodeify(npm.load); + + var stopProgress = (function() { + this.ui.stopProgress(); + }.bind(this)); + + var reportFailure = (function(reason) { + this.ui.writeLine('There was an error – possibly a permissions issue. You ' + + 'may need to manually run ' + + chalk.green('npm install -g ember-cli') + '.'); + throw reason; + }.bind(this)); + + var updateDependencies = (function() { + var pkg = this.project.pkg; + var packagePath = path.join(this.project.root, 'package.json'); + + if (!pkg) { + this.ui.write('There was an error locating your package.json file.'); + return false; + } + + pkg.devDependencies['ember-cli'] = newestVersion; + fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2)); + this.ui.writeLine(''); + this.ui.writeLine(chalk.green('✓ ember-cli was successfully updated!')); + + return this.showEmberInitPrompt(); + }.bind(this)); + + return loadNPM({ + loglevel: 'silent', + global: true + }) + .then(npmInstall) + .then(updateDependencies) + .catch(reportFailure) + .finally(stopProgress); + }, + + showEmberInitPrompt: function() { + this.ui.writeLine('To complete the update, you need to run ' + + chalk.green('ember init') + ' in your project directory.'); + + var initPrompt = { + type: 'confirm', + name: 'answer', + message: 'Would you like to run ' + chalk.green('ember init') + ' now?', + choices: [ + { key: 'y', name: 'Yes', value: 'yes' }, + { key: 'n', name: 'No', value: 'no' } + ] + }; + + return this.ui.prompt(initPrompt).then(function(response) { + if (response.answer === true) { + var InitCommand = this.commands.Init; + + var initCommand = new InitCommand({ + ui: this.ui, + analytics: this.analytics, + tasks: this.tasks, + project: this.project + }); + + return initCommand.run({}, []); + } + }.bind(this)); + } +}); diff --git a/packages/ember-cli/lib/ui/index.js b/packages/ember-cli/lib/ui/index.js new file mode 100644 index 000000000000..0188c900a789 --- /dev/null +++ b/packages/ember-cli/lib/ui/index.js @@ -0,0 +1,231 @@ +'use strict'; + +var ora = require('ora'); +var Promise = require('../ext/promise'); +var EOL = require('os').EOL; +var chalk = require('chalk'); +var writeError = require('./write-error'); + +var DEFAULT_WRITE_LEVEL = 'INFO'; + +// Note: You should use `ui.outputStream`, `ui.inputStream` and `ui.write()` +// instead of `process.stdout` and `console.log`. +// Thus the pleasant progress indicator automatically gets +// interrupted and doesn't mess up the output! -> Convenience :P + +module.exports = UI; + +/* + @constructor + + The UI provides the CLI with a unified mechanism for providing output and + requesting input from the user. This becomes useful when wanting to adjust + logLevels, or mock input/output for tests. + + new UI({ + inputStream: process.stdin, + outputStream: process.stdout, + writeLevel: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR', + ci: true | false + }); + +**/ + +function UI(options) { + var spinner = this.spinner = ora({ color: 'green' }); + + this.through = require('through'); + this.readline = require('readline2'); + + // Output stream + this.actualOutputStream = options.outputStream; + this.outputStream = this.through(function(data) { + spinner.stop(); + this.emit('data', data); + }); + + this.outputStream.setMaxListeners(0); + this.outputStream.pipe(this.actualOutputStream); + + this.inputStream = options.inputStream; + this.errorStream = options.errorStream; + + this.errorLog = options.errorLog || []; + this.writeLevel = options.writeLevel || DEFAULT_WRITE_LEVEL; + this.ci = !!options.ci; +} + +/** + Unified mechanism to write a string to the console. + Optionally include a writeLevel, this is used to decide if the specific + logging mechanism should or should not be printed. + + @method write + @param {String} data + @param {Number} writeLevel +*/ +UI.prototype.write = function(data, writeLevel) { + if (writeLevel === 'ERROR') { + this.errorStream.write(data); + } else if (this.writeLevelVisible(writeLevel)) { + this.outputStream.write(data); + } +}; + +/** + Unified mechanism to write a string and new line to the console. + Optionally include a writeLevel, this is used to decide if the specific + logging mechanism should or should not be printed. + @method writeLine + @param {String} data + @param {Number} writeLevel +*/ +UI.prototype.writeLine = function(data, writeLevel) { + this.write(data + EOL, writeLevel); +}; + +/** + Helper method to write a string with the DEBUG writeLevel and gray chalk + @method writeDebugLine + @param {String} data +*/ +UI.prototype.writeDebugLine = function(data) { + this.writeLine(chalk.gray(data), 'DEBUG'); +}; + +/** + Helper method to write a string with the INFO writeLevel and cyan chalk + @method writeInfoLine + @param {String} data +*/ +UI.prototype.writeInfoLine = function(data) { + this.writeLine(chalk.cyan(data), 'INFO'); +}; + +/** + Helper method to write a string with the WARNING writeLevel and yellow chalk. + Optionally include a test. If falsy, the warning will be printed. By default, warnings + will be prepended with WARNING text when printed. + @method writeWarnLine + @param {String} data + @param {Boolean} test + @param {Boolean} prepend +*/ +UI.prototype.writeWarnLine = function(data, test, prepend) { + if (test) { return; } + + data = this.prependLine('WARNING', data, prepend); + this.writeLine(chalk.yellow(data), 'WARNING', test); +}; + +/** + Helper method to write a string with the WARNING writeLevel and yellow chalk. + Optionally include a test. If falsy, the deprecation will be printed. By default deprecations + will be prepended with DEPRECATION text when printed. + @method writeDeprecateLine + @param {String} data + @param {Boolean} test + @param {Boolean} prepend +*/ +UI.prototype.writeDeprecateLine = function(data, test, prepend) { + data = this.prependLine('DEPRECATION', data, prepend); + this.writeWarnLine(data, test, false); +}; + +/** + Utility method to prepend a line with a flag-like string (i.e., WARNING). + @method prependLine + @param {String} prependData + @param {String} data + @param {Boolean} prepend +*/ +UI.prototype.prependLine = function(prependData, data, prepend) { + if (typeof prepend === 'undefined' || prepend) { + data = prependData + ': ' + data; + } + + return data; +}; + +/** + Unified mechanism to an Error to the console. + This will occure at a writeLevel of ERROR + + @method writeError + @param {Error} error +*/ +UI.prototype.writeError = function(error) { + writeError(this, error); +}; + +/** + Sets the write level for the UI. Valid write levels are 'DEBUG', 'INFO', + 'WARNING', and 'ERROR'. + + @method setWriteLevel + @param {String} level +*/ +UI.prototype.setWriteLevel = function(level) { + if (Object.keys(this.WRITE_LEVELS).indexOf(level) === -1) { + throw new Error('Unknown write level. Valid values are \'DEBUG\', \'INFO\', \'WARNING\', and \'ERROR\'.'); + } + + this.writeLevel = level; +}; + +UI.prototype.startProgress = function(message/*, stepString*/) { + if (this.writeLevelVisible('INFO')) { + if (this.ci) { + this.writeLine(message); + } else { + this.spinner.text = message; + this.spinner.start(); + } + } +}; + +UI.prototype.stopProgress = function() { + if (this.writeLevelVisible('INFO') && !this.ci) { + this.spinner.stop(); + } +}; + +UI.prototype.prompt = function(questions, callback) { + var inquirer = require('inquirer'); + + // If no callback was provided, automatically return a promise + if (callback) { + inquirer.prompt(questions, callback); + } else { + return new Promise(function(resolve) { + inquirer.prompt(questions, resolve); + }); + } +}; + +/** + @property WRITE_LEVELS + @private + @type Object +*/ +UI.prototype.WRITE_LEVELS = { + 'DEBUG': 1, + 'INFO': 2, + 'WARNING': 3, + 'ERROR': 4 +}; + +/** + Whether or not the specified write level should be printed by this UI. + + @method writeLevelVisible + @private + @param {String} writeLevel + @return {Boolean} +*/ +UI.prototype.writeLevelVisible = function(writeLevel) { + var levels = this.WRITE_LEVELS; + writeLevel = writeLevel || DEFAULT_WRITE_LEVEL; + + return levels[writeLevel] >= levels[this.writeLevel]; +}; diff --git a/packages/ember-cli/lib/ui/write-error.js b/packages/ember-cli/lib/ui/write-error.js new file mode 100644 index 000000000000..5114f9da409e --- /dev/null +++ b/packages/ember-cli/lib/ui/write-error.js @@ -0,0 +1,25 @@ +'use strict'; +var chalk = require('chalk'); + +module.exports = function writeError(ui, error) { + if (!error) { return; } + + // Uglify errors have a filename instead + var fileName = error.file || error.filename; + if (fileName) { + if (error.line) { + fileName += error.col ? ' (' + error.line + ':' + error.col + ')' : ' (' + error.line + ')'; + } + ui.writeLine(chalk.red('File: ' + fileName), 'ERROR'); + } + + if (error.message) { + ui.writeLine(chalk.red(error.message), 'ERROR'); + } else { + ui.writeLine(chalk.red(error), 'ERROR'); + } + + if (error.stack) { + ui.writeLine(error.stack, 'ERROR'); + } +}; diff --git a/packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt b/packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt new file mode 100644 index 000000000000..e1c35a53b875 --- /dev/null +++ b/packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt @@ -0,0 +1,39 @@ +Initial Commit from Ember CLI v<%= version %> + + _..., + ,:^;,...; + -+===;. ,,--++====++-,,, .: /....., + :::::~+++++#:,+#++++++++++++++++++#*..: /,...... + (,,,,,,::=+++##++++++++++++++++++++++#. :....../ + ...,,,,,::++++++++++++++++++++++++++++++*..,...: + *..+...,#@@@@@@@@@++++++++++++++++++++++#*....* + @#,;##############@@@+*+#@@@@@@@@@@#*++#..< + *@##@@+,-*^^^*-+@####@@@######@@@#####@@,,,+ + @#@* @#@@@@#@@+--*^^*--#@@@@@@# + @#@. @# @##+++@#, .@@#@@ + #@# @@ +@@++++#@@ @@ :@@ + :@#* @#@++++++@#* #@ @@+ + :*+@@#;,.__.+@#@+,-^^.++@# @@++ + ;* :*@@@##@@@@;++r._j^.+@##@+,.__,,@@++. + /* ........+++++++++++++#@@@@@###@@#++++, + ,: ...,@@@#++===----==@@@####,,....+++++ + .: ......@@##@\ ; :@####@,,...... +++. + ; .........@###, ; ;xx#@;,,..... *;+, + | ........,*;xxxx--^--=xxx,........ :+#; + ; ......,,;xxxxxxxxxxxxx;,..... *+# + ; ......,::xxxx;. ...... +. . + *; ......... +### .... / ,. /:| ,. + .+: ... ;##++##, . ,#. (..v..;*./ + ** ## ###* .:*&&&+. \.,....<, + #&+**==-..,,__ ;## ### :,*+&&&&&&&v+#&,,.._/ + #&&&&*...,::,,. ##; ,##* .*****;:&&&&&&&&& + ,+*+;~*..*** *.* ### ###* ******* *+#&;* + ##,;## **** :, ** + ##### ## ### ###, ######## .##### ;## ## + ####### ;## #### ,###. ########## ######## ### #### + ### ### ### ########## #### #### ,## ### #######* + ### ,### ##############: ## ### #### ,## :#### ### ##; + ########## ########### ## .## ,### ####### ##### :###### + ###### .###### #### ## ### ### ######* :##### #### + ############# #### ################ ######## ### + #####* *#* #: :### *###* *#### #* diff --git a/packages/ember-cli/lib/utilities/DAG.js b/packages/ember-cli/lib/utilities/DAG.js new file mode 100644 index 000000000000..432783c93efd --- /dev/null +++ b/packages/ember-cli/lib/utilities/DAG.js @@ -0,0 +1,110 @@ +'use strict'; + +function visit(vertex, fn, visited, path) { + var name = vertex.name, + vertices = vertex.incoming, + names = vertex.incomingNames, + len = names.length, + i; + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); +} + +function DAG() { + this.names = []; + this.vertices = {}; +} + +DAG.prototype.add = function(name) { + if (!name) { return; } + if (this.vertices.hasOwnProperty(name)) { + return this.vertices[name]; + } + var vertex = { + name: name, + incoming: {}, + incomingNames: [], + hasOutgoing: false, + value: null + }; + + this.vertices[name] = vertex; + this.names.push(name); + return vertex; +}; + +DAG.prototype.map = function(name, value) { + this.add(name).value = value; +}; + +DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName), to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new Error('cycle detected: ' + toName + ' <- ' + path.join(' <- ')); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); +}; + +DAG.prototype.topsort = function(fn) { + var visited = {}, + vertices = this.vertices, + names = this.names, + len = names.length, + i, vertex; + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } +}; + +DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } +}; + +module.exports = DAG; diff --git a/packages/ember-cli/lib/utilities/attempt-never-index.js b/packages/ember-cli/lib/utilities/attempt-never-index.js new file mode 100644 index 000000000000..d2ec53254958 --- /dev/null +++ b/packages/ember-cli/lib/utilities/attempt-never-index.js @@ -0,0 +1,20 @@ +'use strict'; + +var isDarwin = /darwin/i.test(require('os').type()); +var debug = require('debug')('ember-cli:utilities/attempt-metadata-index-file'); + +module.exports = function(dir) { + var path = dir + '/.metadata_never_index'; + + if (!isDarwin) { + debug('not darwin, skipping %s (which hints to spotlight to prevent indexing)', path); + return; + } + + debug('creating: %s (to prevent spotlight indexing)', path); + + var fs = require('fs-extra'); + + fs.mkdirsSync(dir); + fs.writeFileSync(path); +}; diff --git a/packages/ember-cli/lib/utilities/deprecate.js b/packages/ember-cli/lib/utilities/deprecate.js new file mode 100644 index 000000000000..35be01d66568 --- /dev/null +++ b/packages/ember-cli/lib/utilities/deprecate.js @@ -0,0 +1,19 @@ +'use strict'; + +var chalk = require('chalk'); + +module.exports = function(message, test) { + if (test) { + console.log(chalk.yellow('DEPRECATION: ' + message)); + } +}; + +module.exports.deprecateUI = function(ui) { + return function(message, test) { + ui.writeDeprecateLine('The deprecateUI utility has been deprecated in favor of ui.writeDeprecateLine'); + + test = !test; + + ui.writeDeprecateLine(message, test); + }; +}; diff --git a/packages/ember-cli/lib/utilities/doc-generator.js b/packages/ember-cli/lib/utilities/doc-generator.js new file mode 100644 index 000000000000..b9cb89f56666 --- /dev/null +++ b/packages/ember-cli/lib/utilities/doc-generator.js @@ -0,0 +1,24 @@ +'use strict'; + +var versionUtils = require('./version-utils'); +var emberCLIVersion = versionUtils.emberCLIVersion; +var fs = require('fs'); + +function DocGenerator(options) { + options = options || {}; + this.exec = options.exec || require('child_process').exec; +} + +DocGenerator.prototype.generate = function() { + var command = 'cd docs && ' + fs.realpathSync('./node_modules/.bin/yuidoc') + + ' -q --project-version ' + emberCLIVersion(); // add '-p' flag to produce only JSON and not HTML + + console.log('Executing command: ' + command); + this.exec(command, function(error) { // stdout, stderr + if (error !== null) { + console.log('Error: ' + error); + } + }); +}; + +module.exports = DocGenerator; diff --git a/packages/ember-cli/lib/utilities/find-build-file.js b/packages/ember-cli/lib/utilities/find-build-file.js new file mode 100644 index 000000000000..44a55c7bb03d --- /dev/null +++ b/packages/ember-cli/lib/utilities/find-build-file.js @@ -0,0 +1,28 @@ +'use strict'; + +var findUp = require('findup-sync'); +var path = require('path'); + +module.exports = function(file) { + var buildFilePath = findUp(file); + + // Note + // In the future this should throw + if (buildFilePath === null) { + return null; + } + + var baseDir = path.dirname(buildFilePath); + + process.chdir(baseDir); + + var buildFile = null; + try { + buildFile = require(buildFilePath); + } catch (err) { + err.message = 'Could not require \'' + file + '\': ' + err.message; + throw err; + } + + return buildFile; +}; diff --git a/packages/ember-cli/lib/utilities/get-option-args.js b/packages/ember-cli/lib/utilities/get-option-args.js new file mode 100644 index 000000000000..3ce3bd7838c2 --- /dev/null +++ b/packages/ember-cli/lib/utilities/get-option-args.js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = function(option, commandArgs) { + var results = [], value, i; + var optionIndex = commandArgs.indexOf(option); + if (optionIndex === -1) { return results; } + + for (i = optionIndex + 1; i < commandArgs.length; i++) { + value = commandArgs[i]; + if (/^\-+/.test(value)) { break; } + results.push(value); + } + + return results; +}; diff --git a/packages/ember-cli/lib/utilities/get-package-base-name.js b/packages/ember-cli/lib/utilities/get-package-base-name.js new file mode 100644 index 000000000000..9690ce43bb30 --- /dev/null +++ b/packages/ember-cli/lib/utilities/get-package-base-name.js @@ -0,0 +1,12 @@ +'use strict'; + +module.exports = function (name) { + var packageParts; + + if (!name) { + return null; + } + + packageParts = name.split('/'); + return packageParts[(packageParts.length - 1)]; +}; diff --git a/packages/ember-cli/lib/utilities/json-generator.js b/packages/ember-cli/lib/utilities/json-generator.js new file mode 100644 index 000000000000..0307d3aaa442 --- /dev/null +++ b/packages/ember-cli/lib/utilities/json-generator.js @@ -0,0 +1,100 @@ +'use strict'; + +var lookupCommand = require('../cli/lookup-command'); +var stringUtils = require('ember-cli-string-utils'); +var assign = require('lodash/assign'); +var GenerateCommand = require('../commands/generate'); +var RootCommand = require('./root-command'); +var versionUtils = require('./version-utils'); +var emberCLIVersion = versionUtils.emberCLIVersion; + +function JsonGenerator(options) { + options = options || {}; + + this.ui = options.ui; + this.project = options.project; + this.commands = options.commands; + this.tasks = options.tasks; +} + +JsonGenerator.prototype.generate = function(commandOptions, rawArgs) { + var rootCommand = new RootCommand({ + ui: this.ui, + project: this.project, + commands: this.commands, + tasks: this.tasks + }); + + var json = rootCommand.getJson(commandOptions); + json.version = emberCLIVersion(); + json.commands = []; + json.addons = []; + + if (rawArgs.length === 0) { + Object.keys(this.commands).forEach(function(commandName) { + this._addCommandHelpToJson(commandName, false, commandOptions, json); + }, this); + + if (this.project.eachAddonCommand) { + this.project.eachAddonCommand(function(addonName, commands) { + this.commands = commands; + + var addonJson = { name: addonName }; + addonJson.commands = []; + json.addons.push(addonJson); + + Object.keys(this.commands).forEach(function(commandName) { + this._addCommandHelpToJson(commandName, false, commandOptions, addonJson); + }, this); + }.bind(this)); + } + } else { + // If args were passed to the help command, + // attempt to look up the command for each of them. + + if (this.project.eachAddonCommand) { + this.project.eachAddonCommand(function(addonName, commands) { + assign(this.commands, commands); + }.bind(this)); + } + + var multipleCommands = [GenerateCommand.prototype.name].concat(GenerateCommand.prototype.aliases); + if (multipleCommands.indexOf(rawArgs[0]) > -1) { + var command = rawArgs.shift(); + if (rawArgs.length > 0) { + commandOptions.rawArgs = rawArgs; + } + rawArgs = [command]; + } + + // Iterate through each arg beyond the initial 'help' command, + // and try to display usage instructions. + rawArgs.forEach(function(commandName) { + this._addCommandHelpToJson(commandName, true, commandOptions, json); + }, this); + } + + return json; +}; + + +JsonGenerator.prototype._addCommandHelpToJson = function(commandName, single, options, json) { + var command = this._lookupCommand(commandName); + if ((!command.skipHelp || single) && !command.unknown) { + json.commands.push(command.getJson(options)); + } +}; + +JsonGenerator.prototype._lookupCommand = function(commandName) { + var Command = this.commands[stringUtils.classify(commandName)] || + lookupCommand(this.commands, commandName); + + return new Command({ + ui: this.ui, + project: this.project, + commands: this.commands, + tasks: this.tasks + }); +}; + +module.exports = JsonGenerator; diff --git a/packages/ember-cli/lib/utilities/markdown-color.js b/packages/ember-cli/lib/utilities/markdown-color.js new file mode 100644 index 000000000000..6bf3c343a741 --- /dev/null +++ b/packages/ember-cli/lib/utilities/markdown-color.js @@ -0,0 +1,213 @@ +'use strict'; + +var fs = require('fs'); +var existsSync = require('exists-sync'); + +var chalk = require('chalk'); +var SilentError = require('silent-error'); +var isArray = require('lodash/isArray'); +var merge = require('lodash/merge'); + +var colors = ['red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'white', 'grey', 'gray']; +var backgroundColors = ['bgRed', 'bgGreen', 'bgBlue', 'bgCyan', 'bgMagenta', 'bgYellow', 'bgWhite', 'bgBlack']; + +module.exports = MarkdownColor; + +/* + Parses markdown and applies coloring to output by matching defined tokens and + applying styling. Default outputs chalk.js coloring for terminal output. + Options: + tokens: pass additional tokens in the following format: + { + name:{ + token: '(Reserved)', // example of token + pattern: /(Reserved)/g, // regexp pattern + render: function(string) { return string + '!'} // function that takes and returns a string + } + } + + markdownOptions: object containing options to pass (or override) to markdown-it-terminal upon + instantiation. See https://github.com/trabus/markdown-it-terminal/blob/master/index.js#L8 + + renderStyles: pass an object to render color styles, default is chalk.js + + @class MarkdownColor + @constructor + @param {Object} [options] +*/ +function MarkdownColor(options) { + var optionTokens = options && options.tokens || {}; + var renderStyles = options && options.renderStyles || chalk; + var tokens = this.generateTokens(renderStyles); + var markdownOptions = options && options.markdownOptions || {}; + var markdown = require('markdown-it'); + var terminal = require('markdown-it-terminal'); + this.options = options || {}; + this.markdown = markdown().use(terminal, markdownOptions); + this.tokens = merge(tokens, optionTokens); + + return this; +} + +/* + Lookup markdown file and render contents + @method renderFile + @param {String} [filePath] + @param {Object} [options] +*/ +MarkdownColor.prototype.renderFile = function (filePath, options) { + var file; + if (existsSync(filePath)) { + file = fs.readFileSync(filePath, 'utf-8'); + } else { + throw new SilentError('The file \'' + filePath + '\' doesn\'t exist.' + + ' Please check your filePath'); + } + + return this.render(file, options); +}; + +/* + Parse markdown and output as string + @method render + @param {String} [string] + @param {Object} [options] + @return {String} +*/ +MarkdownColor.prototype.render = function (string, options) { + var indent = options && options.indent || ''; + var input = this.markdown.render(string); + var styles = Object.keys(this.tokens); + input = input.replace(/^/mg, indent); + styles.reverse().map(function(style) { + input = input.replace(this.tokens[style].pattern, this.tokens[style].render); + }.bind(this)); + input = input.replace(/\~\^(.*)\~\^/g, escapeToken); + return input; +}; + +/* + Generate default style tokens + @method generateTokens + @return {Object} +*/ +MarkdownColor.prototype.generateTokens = function (renderer) { + var defaultTokens = { + // ember-cli styles + option: { + name: 'option', + token: '--option', + pattern: /((--\w*\b)|())/g, + render: renderStylesFactory(renderer, 'cyan') + }, + default: { + name: 'default', + token: '(Default: default)', + pattern: /(\(Default:\s.*\))/g, + render: renderStylesFactory(renderer, 'cyan') + }, + required: { + name: 'required', + token: '(Required)', + pattern: /(\(Required\))/g, + render: renderStylesFactory(renderer, 'cyan') + } + }; + + var colorTokens = unshiftValue(colors.concat(backgroundColors).map(getToken), {}).reduce(setToken); + return merge(colorTokens, defaultTokens); +}; + + +/* + Looks up multiple styles to apply to the rendered output + @method renderStylesFactory + @param {Object} [renderer] should match chalk.js format + @param {String, Array} [styleNames] + @return {Function} Function that will wrap the input string with styling +*/ +MarkdownColor.prototype.renderStylesFactory = renderStylesFactory; +function renderStylesFactory(renderer, styleNames) { + var styles; + if (isArray(styleNames)) { + styles = styleNames.map(checkStyleName.bind(null, renderer)); + } else { + styles = [checkStyleName(renderer, styleNames)]; + } + return function(match, pattern) { + return styles.reverse().reduce(function (previous, current) { + return renderer[current](previous); + }, pattern); + }; +} + +/* + Check to see if style exists on the renderer + @param {Object} [renderer] should match chalk.js format + @param {String} [name] +*/ +function checkStyleName(renderer, name) { + if (Object.keys(renderer.styles).indexOf(name) > -1) { + return name; + } else { + throw new SilentError('The style \'' + name + '\' is not supported by the markdown renderer.'); + } +} + +/* + @param {String} [name] + @param {Object} [options] + @return {RegExp} Returns lookup pattern +*/ +function getColorTokenRegex(name, options) { + options = options || {}; + var start = options.start || '(?:<'; + var end = options.end || '>)'; + var close = options.close || '(?:<\/'; + var middle = options.middle || '(.*?)'; + var tag = start + name + end; + var closeTag = close + name + end; + var pattern = tag + middle + closeTag; + return new RegExp(pattern, 'g'); +} + +/* + @param {String} [name] + @param {Object} [options] + @return {Object} Returns token object +*/ +function getToken(name, options) { + var renderer = options && options.renderer || chalk; + return { + name: name, + token: '<' + name + '>', + pattern: getColorTokenRegex(name), + render: renderStylesFactory(renderer, name) + }; +} + +function setToken(result, color) { + result[color.name] = color; + return result; +} + +function escapeToken(match, pattern) { + var output = pattern.replace(/\~/g,''); + return '<' + output + '>'; +} + +function unshiftValue(array, value) { + array.unshift(value); + return array; +} + +/* +Formatting colors for ember-cli help + +white: ember serve +yellow: +cyan: --port, --important-option +cyan: (Default: something), (Default: 4200) +white: Description 1, Description 2 +cyan: (Required) +*/ diff --git a/packages/ember-cli/lib/utilities/merge-blueprint-options.js b/packages/ember-cli/lib/utilities/merge-blueprint-options.js new file mode 100644 index 000000000000..0c5fc4f4c872 --- /dev/null +++ b/packages/ember-cli/lib/utilities/merge-blueprint-options.js @@ -0,0 +1,31 @@ +'use strict'; + +var SilentError = require('silent-error'); +var Blueprint = require('../models/blueprint'); + +/* + * Helper for commands that use a blueprint to merge the blueprint's options + * into the command's options so they can be passed in. Needs to be invoked + * with `this` pointing to the command object, e.g. + * + * var mergeBlueprintOptions = require('../utilities/merge-blueprint-options'); + * + * Command.extend({ + * beforeRun: mergeBlueprintOptions + * }) + */ +module.exports = function(rawArgs) { + if (rawArgs.length === 0) { + return; + } + // merge in blueprint availableOptions + var blueprint; + try { + blueprint = Blueprint.lookup(rawArgs[0], { + paths: this.project.blueprintLookupPaths() + }); + this.registerOptions(blueprint); + } catch (e) { + SilentError.debugOrThrow('ember-cli/commands/' + this.name, e); + } +}; diff --git a/packages/ember-cli/lib/utilities/mk-tmp-dir-in.js b/packages/ember-cli/lib/utilities/mk-tmp-dir-in.js new file mode 100644 index 000000000000..4c1ce06a30f1 --- /dev/null +++ b/packages/ember-cli/lib/utilities/mk-tmp-dir-in.js @@ -0,0 +1,25 @@ +'use strict'; + +var Promise = require('../ext/promise'); +var fs = require('fs-extra'); +var temp = require('temp'); +var mkdir = Promise.denodeify(fs.mkdir); +var mkdirTemp = Promise.denodeify(temp.mkdir); + +function exists(dir) { + return new Promise(function(resolve) { + fs.exists(dir, resolve); + }); +} + +function mkTmpDirIn(dir) { + return exists(dir).then(function(doesExist) { + if (!doesExist) { + return mkdir(dir); + } + }).then(function() { + return mkdirTemp({ dir: dir }); + }); +} + +module.exports = mkTmpDirIn; diff --git a/packages/ember-cli/lib/utilities/normalize-blueprint-option.js b/packages/ember-cli/lib/utilities/normalize-blueprint-option.js new file mode 100644 index 000000000000..1bedf9543c41 --- /dev/null +++ b/packages/ember-cli/lib/utilities/normalize-blueprint-option.js @@ -0,0 +1,7 @@ +'use strict'; + +var path = require('path'); + +module.exports = function normalizeBlueprintOption(blueprint) { + return blueprint[0] === '.' ? path.resolve(process.cwd(), blueprint) : blueprint; +}; diff --git a/packages/ember-cli/lib/utilities/npm.js b/packages/ember-cli/lib/utilities/npm.js new file mode 100644 index 000000000000..a5be7e82466b --- /dev/null +++ b/packages/ember-cli/lib/utilities/npm.js @@ -0,0 +1,38 @@ +'use strict'; + +var Promise = require('../ext/promise'); + +// + +/** + Runs the npm command `command` with the supplied args and load options. + + Please note that the loaded module appears to retain some state, so do not + expect multiple invocations within the same process to work without quirks. + This problem is likely fixable. + + @method npm + @param {String} command The npm command to run. + @param {Array} npmArgs The arguments passed to the npm command. + @param {Array} options The options passed when loading npm. + @param {Module} [npm] A reference to the npm module. +*/ +module.exports = function npm(command, npmArgs, options/*, npm*/) { + var lib; + if (arguments.length === 4) { + lib = arguments[3]; + } else { + lib = require('npm'); + } + + var load = Promise.denodeify(lib.load); + + return load(options) + .then(function() { + // if install is denodeified outside load.then(), + // it throws "Call npm.load(config, cb) before using this command." + var operation = Promise.denodeify(lib.commands[command]); + + return operation(npmArgs || []); + }); +}; diff --git a/packages/ember-cli/lib/utilities/open-editor.js b/packages/ember-cli/lib/utilities/open-editor.js new file mode 100644 index 000000000000..11696ed02d4e --- /dev/null +++ b/packages/ember-cli/lib/utilities/open-editor.js @@ -0,0 +1,42 @@ +'use strict'; + +var Promise = require('../ext/promise'); +var spawn = require('child_process').spawn; + +function openEditor(file) { + if (!openEditor.canEdit()) { + throw new Error('EDITOR environment variable is not set'); + } + + if (!file) { + throw new Error('No `file` option provided'); + } + + var editorArgs = openEditor._env().EDITOR.split(' '); + var editor = editorArgs.shift(); + var editProcess = openEditor._spawn(editor, [file].concat(editorArgs), {stdio: 'inherit'}); + + return new Promise(function(resolve, reject) { + editProcess.on('close', function (code) { + if (code === 0) { + resolve(); + } else { + reject(); + } + }); + }); +} + +openEditor.canEdit = function() { + return openEditor._env().EDITOR !== undefined; +}; + +openEditor._env = function() { + return process.env; +}; + +openEditor._spawn = function() { + return spawn.apply(this, arguments); +}; + +module.exports = openEditor; diff --git a/packages/ember-cli/lib/utilities/parse-options.js b/packages/ember-cli/lib/utilities/parse-options.js new file mode 100644 index 000000000000..d2d06f9b0efe --- /dev/null +++ b/packages/ember-cli/lib/utilities/parse-options.js @@ -0,0 +1,11 @@ +'use strict'; + +var reduce = require('lodash/reduce'); + +module.exports = function parseOptions(args) { + return reduce(args, function(result, arg) { + var parts = arg.split(':'); + result[parts[0]] = parts.slice(1).join(':'); + return result; + }, {}); +}; diff --git a/packages/ember-cli/lib/utilities/path.js b/packages/ember-cli/lib/utilities/path.js new file mode 100644 index 000000000000..39c686da4913 --- /dev/null +++ b/packages/ember-cli/lib/utilities/path.js @@ -0,0 +1,31 @@ +'use strict'; + +module.exports = { + /** + Returns a relative parent path string using the path provided + + @method getRelativeParentPath + @param {String} path The path to relatively get to. + @return {String} the relative path string. + */ + getRelativeParentPath: function getRelativeParentPath(path, offset, slash) { + var offsetValue = offset || 0; + var trailingSlash = typeof slash === 'undefined' ? true : slash; + var outputPath = new Array(path.split('/').length + 1 - offsetValue).join('../'); + + return trailingSlash ? outputPath : outputPath.substr(0, outputPath.length - 1); + }, + + /** + Returns a relative path string using the path provided + + @method getRelativePath + @param {String} path The path to relatively get to. + @return {String} the relative path string. + */ + getRelativePath: function getRelativePath(path, offset) { + var offsetValue = offset || 0; + var relativePath = new Array(path.split('/').length - offsetValue).join('../'); + return relativePath || './'; + } +}; diff --git a/packages/ember-cli/lib/utilities/platform-checker.js b/packages/ember-cli/lib/utilities/platform-checker.js new file mode 100644 index 000000000000..e0a3dabe1099 --- /dev/null +++ b/packages/ember-cli/lib/utilities/platform-checker.js @@ -0,0 +1,35 @@ +'use strict'; + +var semver = require('semver'); +var debug = require('debug')('ember-cli:platform-checker:'); + +var LOWER_RANGE = '0.12.0'; +var UPPER_RANGE = '6.0.0'; + +module.exports = PlatformChecker; +function PlatformChecker(version) { + this.version = version; + this.isValid = this.checkIsValid(); + this.isUntested = this.checkIsUntested(); + this.isDeprecated = this.checkIsDeprecated(); + + debug('%o', { + version: this.version, + isValid: this.isValid, + isUntested: this.isUntested, + isDeprecated: this.isDeprecated + }); +} + +PlatformChecker.prototype.checkIsValid = function() { + return semver.satisfies(this.version, '>=' + LOWER_RANGE + ' <' + UPPER_RANGE); +}; + +PlatformChecker.prototype.checkIsDeprecated = function() { + return semver.satisfies(this.version, '<' + LOWER_RANGE); +}; + +PlatformChecker.prototype.checkIsUntested = function() { + return semver.satisfies(this.version, '>=' + UPPER_RANGE); +}; + diff --git a/packages/ember-cli/lib/utilities/print-command.js b/packages/ember-cli/lib/utilities/print-command.js new file mode 100644 index 000000000000..087b5c2e6f16 --- /dev/null +++ b/packages/ember-cli/lib/utilities/print-command.js @@ -0,0 +1,92 @@ +'use strict'; + +var chalk = require('chalk'); +var EOL = require('os').EOL; + +module.exports = function(initialMargin, shouldDescriptionBeGrey) { + initialMargin = initialMargin || ''; + + var output = ''; + + var options = this.anonymousOptions; + + // ... + if (options.length) { + output += ' ' + chalk.yellow(options.map(function(option) { + // blueprints we insert brackets, commands already have them + if (option.indexOf('<') === 0) { + return option; + } else { + return '<' + option + '>'; + } + }).join(' ')); + } + + options = this.availableOptions; + + // + if (options.length) { + output += ' ' + chalk.cyan(''); + } + + // Description + var description = this.description; + if (description) { + if (shouldDescriptionBeGrey) { + description = chalk.grey(description); + } + output += EOL + initialMargin + ' ' + description; + } + + // aliases: a b c + if (this.aliases && this.aliases.length) { + output += EOL + initialMargin + ' ' + chalk.grey('aliases: ' + this.aliases.filter(function(a) { return a; }).join(', ')); + } + + // --available-option (Required) (Default: value) + // ... + options.forEach(function(option) { + output += EOL + initialMargin + ' ' + chalk.cyan('--' + option.name); + + if (option.values) { + output += chalk.cyan('=' + option.values.join('|')); + } + + if (option.type) { + var types = Array.isArray(option.type) ? + option.type.map(formatType).join(', ') : + formatType(option.type); + + output += ' ' + chalk.cyan('(' + types + ')'); + } + + if (option.required) { + output += ' ' + chalk.cyan('(Required)'); + } + + if (option.default !== undefined) { + output += ' ' + chalk.cyan('(Default: ' + option.default + ')'); + } + + if (option.description) { + output += ' ' + option.description; + } + + if (option.aliases && option.aliases.length) { + output += EOL + initialMargin + ' ' + chalk.grey('aliases: ' + option.aliases.map(function(a) { + if (typeof a === 'string') { + return (a.length > 4 ? '--' : '-') + a + (option.type === Boolean ? '' : ' '); + } else { + var key = Object.keys(a)[0]; + return (key.length > 4 ? '--' : '-') + key + ' (--' + option.name + '=' + a[key] + ')'; + } + }).join(', ')); + } + }); + + return output; +}; + +function formatType(type) { + return typeof type === 'string' ? type : type.name; +} diff --git a/packages/ember-cli/lib/utilities/printable-properties.js b/packages/ember-cli/lib/utilities/printable-properties.js new file mode 100644 index 000000000000..21b6b5b63f07 --- /dev/null +++ b/packages/ember-cli/lib/utilities/printable-properties.js @@ -0,0 +1,36 @@ +'use strict'; + +var commandProperties = [ + 'name', + 'description', + 'aliases', + 'works', + 'availableOptions', + 'anonymousOptions' +]; +var blueprintProperties = [ + 'name', + 'description', + 'availableOptions', + 'anonymousOptions', + 'overridden' +]; + +function forEachWithProperty(properties, forEach, context) { + return properties.filter(function(key) { + return this[key] !== undefined; + }, context).forEach(forEach, context); +} + +module.exports = { + command: { + forEachWithProperty: function(forEach, context) { + return forEachWithProperty(commandProperties, forEach, context); + } + }, + blueprint: { + forEachWithProperty: function(forEach, context) { + return forEachWithProperty(blueprintProperties, forEach, context); + } + } +}; diff --git a/packages/ember-cli/lib/utilities/require-as-hash.js b/packages/ember-cli/lib/utilities/require-as-hash.js new file mode 100644 index 000000000000..7affe9f2cda8 --- /dev/null +++ b/packages/ember-cli/lib/utilities/require-as-hash.js @@ -0,0 +1,33 @@ +'use strict'; +var stringUtils = require('ember-cli-string-utils'); + +// Gathers subclasses of a certain specified base class into a hash. +// +// e.g.: +// Files: +// - ./hamster.js which exports an class of Hamster subclass of Rodent +// - ./parrot.js which exports an instance of Parrot (not a Rodent!) +// +// requireAsHash('./*.js', Rodent): +// { +// Hamster: Hamster // Same as require('./hamster.js') +// } + + +var globSync = require('glob').sync; +var path = require('path'); +var getCallerFile = require('get-caller-file'); + +module.exports = requireAsHash; +function requireAsHash(pattern, type) { + var callerFileDir = path.dirname(getCallerFile()); + return globSync(pattern, { cwd: callerFileDir }) + .reduce(function(hash, file) { + + var klass = require(callerFileDir + '/' + file); + if (!type || (klass.prototype instanceof type)) { + hash[stringUtils.classify(path.basename(file, '.js'))] = klass; + } + return hash; + }, {}); +} diff --git a/packages/ember-cli/lib/utilities/require-local.js b/packages/ember-cli/lib/utilities/require-local.js new file mode 100644 index 000000000000..69ee177d4070 --- /dev/null +++ b/packages/ember-cli/lib/utilities/require-local.js @@ -0,0 +1,8 @@ +'use strict'; + +var path = require('path'); +var nodeModulesPath = require('node-modules-path'); + +module.exports = function requireLocal(lib) { + return require(path.join(nodeModulesPath(process.cwd()), lib)); +}; diff --git a/packages/ember-cli/lib/utilities/root-command.js b/packages/ember-cli/lib/utilities/root-command.js new file mode 100644 index 000000000000..785048094c6e --- /dev/null +++ b/packages/ember-cli/lib/utilities/root-command.js @@ -0,0 +1,12 @@ +'use strict'; + +var Command = require('../models/command'); + +module.exports = Command.extend({ + isRoot: true, + name: 'ember', + + anonymousOptions: [ + '' + ] +}); diff --git a/packages/ember-cli/lib/utilities/sequence.js b/packages/ember-cli/lib/utilities/sequence.js new file mode 100644 index 000000000000..ec9e6eb7e7e8 --- /dev/null +++ b/packages/ember-cli/lib/utilities/sequence.js @@ -0,0 +1,41 @@ +'use strict'; + +var Promise = require('../ext/promise'); +/* + * + * given an array of functions, that may or may not return promises sequence + * will invoke them sequentially. If a promise is encountered sequence will + * wait until it fulfills before moving to the next entry. + * + * ```js + * var tasks = [ + * function() { return Promise.resolve(1); }, + * 2, + * function() { return timeout(1000).then(function() { return 3; } }, + * ]; + * + * sequence(tasks).then(function(results) { + * results === [ + * 1, + * 2, + * 3 + * ] + * }); + * ``` + * + * @method sequence + * @param tasks + * @return Promise + * + */ +module.exports = function sequence(tasks) { + var length = tasks.length; + var current = Promise.resolve(); + var results = new Array(length); + + for (var i = 0; i < length; ++i) { + current = results[i] = current.then(tasks[i]); + } + + return Promise.all(results); +}; diff --git a/packages/ember-cli/lib/utilities/valid-project-name.js b/packages/ember-cli/lib/utilities/valid-project-name.js new file mode 100644 index 000000000000..8d6833177bfb --- /dev/null +++ b/packages/ember-cli/lib/utilities/valid-project-name.js @@ -0,0 +1,11 @@ +'use strict'; + +module.exports = function(name) { + name = name.toLowerCase(); + + if (['test', 'ember', 'ember-cli', 'vendor', 'app'].indexOf(name) > -1) { return false; } + if (name.indexOf('.') > -1) { return false; } + if (!isNaN(parseInt(name.charAt(0), 10))) { return false; } + + return true; +}; diff --git a/packages/ember-cli/lib/utilities/version-utils.js b/packages/ember-cli/lib/utilities/version-utils.js new file mode 100644 index 000000000000..7315cd7ce7e0 --- /dev/null +++ b/packages/ember-cli/lib/utilities/version-utils.js @@ -0,0 +1,26 @@ +'use strict'; + +var existsSync = require('exists-sync'); +var path = require('path'); +var getRepoInfo = require('git-repo-info'); + +module.exports = { + emberCLIVersion: function emberCLIVersion() { + var gitPath = path.join(__dirname, '..','..','.git'); + var output = [require('../../package.json').version]; + + if (existsSync(gitPath)) { + var repoInfo = getRepoInfo(gitPath); + + output.push(repoInfo.branch); + output.push(repoInfo.abbreviatedSha); + } + + return output.join('-'); + }, + + isDevelopment: function isDevelopment(version) { + // match postfix SHA in dev version + return !!version.match(/\b[0-9a-f]{5,40}\b/); + } +}; diff --git a/packages/ember-cli/lib/utilities/windows-admin.js b/packages/ember-cli/lib/utilities/windows-admin.js new file mode 100644 index 000000000000..f5a6d69e50c6 --- /dev/null +++ b/packages/ember-cli/lib/utilities/windows-admin.js @@ -0,0 +1,41 @@ +'use strict'; + +var Promise = require('../ext/promise'); +var chalk = require('chalk'); +var exec = require('child_process').exec; + +module.exports = { + /** + * Uses the eon-old command NET SESSION to determine whether or not the + * current user has elevated rights (think sudo, but Windows). + * + * @method checkWindowsElevation + * @param {Object} ui - ui object used to call writeLine(); + * @return {Object} Object describing whether we're on windows and if admin rights exist + */ + checkWindowsElevation: function (ui) { + return new Promise(function (resolve) { + if (/^win/.test(process.platform)) { + exec('NET SESSION', function (error, stdout, stderr) { + var elevated = (!stderr || stderr.length === 0); + + if (!elevated && ui && ui.writeLine) { + ui.writeLine(chalk.yellow('\nRunning without elevated rights. ' + + 'Running Ember CLI "as Administrator" increases performance significantly.')); + ui.writeLine('See ember-cli.com/user-guide/#windows for details.\n'); + } + + resolve({ + windows: true, + elevated: elevated + }); + }); + } else { + resolve({ + windows: false, + elevated: null + }); + } + }); + } +}; diff --git a/packages/ember-cli/package.json b/packages/ember-cli/package.json new file mode 100644 index 000000000000..1b3bf9cd4c3c --- /dev/null +++ b/packages/ember-cli/package.json @@ -0,0 +1,66 @@ +{ + "author": { + "name": "Stefan Penner, Robert Jackson and ember-cli contributors" + }, + "bugs": { + "url": "https://github.com/ember-cli/ember-cli/issues" + }, + "dependencies": { + "chalk": "^1.1.1", + "configstore": "^2.0.0", + "core-object": "0.0.2", + "debug": "^2.1.3", + "diff": "^2.2.2", + "ember-cli-normalize-entity-name": "^1.0.0", + "ember-cli-preprocess-registry": "^2.0.0", + "ember-cli-string-utils": "^1.0.0", + "exists-sync": "0.0.3", + "exit": "^0.1.2", + "findup": "0.1.5", + "findup-sync": "^0.2.1", + "fs-extra": "0.26.7", + "fs-monitor-stack": "^1.0.2", + "get-caller-file": "^1.0.0", + "git-repo-info": "^1.0.4", + "glob": "7.0.3", + "inflection": "^1.7.0", + "inquirer": "^0.12.0", + "is-git-url": "^0.2.0", + "isbinaryfile": "^2.0.3", + "leek": "0.0.21", + "lodash": "^4.11.1", + "markdown-it": "4.3.0", + "markdown-it-terminal": "0.0.3", + "minimatch": "^3.0.0", + "mkdirp": "^0.5.1", + "node-modules-path": "^1.0.0", + "node-uuid": "^1.4.3", + "nopt": "^3.0.1", + "ora": "^0.2.0", + "portfinder": "^1.0.7", + "quick-temp": "0.1.5", + "readline2": "0.1.1", + "resolve": "^1.1.6", + "rimraf": "^2.4.4", + "rsvp": "^3.0.17", + "sane": "^1.1.1", + "semver": "^5.1.0", + "silent-error": "^1.0.0", + "temp": "0.8.3", + "through": "^2.3.6", + "tree-sync": "^1.1.0", + "walk-sync": "^0.2.6", + "yam": "0.0.18" + }, + "description": "Command line tool for developing ambitious ember.js apps", + "directories": {}, + "homepage": "https://github.com/ember-cli/ember-cli#readme", + "license": "MIT", + "main": "lib/cli/index.js", + "name": "@angular-cli/ember-cli", + "repository": { + "type": "git", + "url": "git+https://github.com/ember-cli/ember-cli.git" + }, + "version": "2.5.0" +} diff --git a/packages/ember-cli/tsconfig.json b/packages/ember-cli/tsconfig.json new file mode 100644 index 000000000000..9623f183e150 --- /dev/null +++ b/packages/ember-cli/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "mapRoot": "", + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noImplicitAny": true, + "outDir": "../../dist/angular-cli", + "rootDir": ".", + "sourceMap": true, + "sourceRoot": "/", + "target": "es5", + "lib": ["es6"], + "skipLibCheck": true, + "typeRoots": [ + "../../node_modules/@types" + ], + "baseUrl": "", + "paths": { + "@angular-cli/ast-tools": [ "../../dist/ast-tools/src" ], + "@angular-cli/base-href-webpack": [ "../../dist/base-href-webpack/src" ], + "@ngtools/webpack": [ "../../dist/webpack/src" ] + } + }, + "include": [ + "**/*" + ], + "exclude": [ + "blueprints/*/files/**/*" + ] +} diff --git a/scripts/publish/build.js b/scripts/publish/build.js index 642a353f6a1a..c617c3efccdc 100755 --- a/scripts/publish/build.js +++ b/scripts/publish/build.js @@ -32,6 +32,12 @@ function copy(from, to) { } +function getDeps(pkg) { + const packageJson = require(pkg.packageJson); + return Object.assign({}, packageJson['dependencies'], packageJson['devDependencies']); +} + + // First delete the dist folder. Promise.resolve() .then(() => console.log('Deleting dist folder...')) @@ -42,11 +48,12 @@ Promise.resolve() return Object.keys(packages) // Order packages in order of dependency. .sort((a, b) => { - const aPackageJson = require(packages[a].packageJson); - const bPackageJson = require(packages[b].packageJson); - if (Object.keys(aPackageJson['dependencies'] || {}).indexOf(b) == -1) { + const aDependsOnB = Object.keys(getDeps(packages[a])).indexOf(b) != -1; + const bDependsOnA = Object.keys(getDeps(packages[b])).indexOf(a) != -1; + + if (!aDependsOnB && !bDependsOnA) { return 0; - } else if (Object.keys(bPackageJson['dependencies'] || {}).indexOf(a) == -1) { + } else if (aDependsOnB) { return 1; } else { return -1; diff --git a/tests/acceptance/destroy.spec.js b/tests/acceptance/destroy.spec.js index 90230e8ee309..fac5327d4533 100644 --- a/tests/acceptance/destroy.spec.js +++ b/tests/acceptance/destroy.spec.js @@ -2,15 +2,10 @@ const ng = require('../helpers/ng'); const tmp = require('../helpers/tmp'); -const conf = require('ember-cli/tests/helpers/conf'); const SilentError = require('silent-error'); const expect = require('chai').expect; describe('Acceptance: ng destroy', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { this.timeout(10000); return tmp.setup('./tmp').then(function () { diff --git a/tests/acceptance/generate-class.spec.js b/tests/acceptance/generate-class.spec.js index 0c2e68e18700..0c173d90127d 100644 --- a/tests/acceptance/generate-class.spec.js +++ b/tests/acceptance/generate-class.spec.js @@ -3,7 +3,6 @@ const ng = require('../helpers/ng'); const tmp = require('../helpers/tmp'); -const conf = require('ember-cli/tests/helpers/conf'); const existsSync = require('exists-sync'); const expect = require('chai').expect; const path = require('path'); @@ -12,10 +11,6 @@ const root = process.cwd(); const testPath = path.join(root, 'tmp', 'foo', 'src', 'app'); describe('Acceptance: ng generate class', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { this.timeout(10000); return tmp.setup('./tmp').then(function () { diff --git a/tests/acceptance/generate-component.spec.js b/tests/acceptance/generate-component.spec.js index 6416ef2fff76..e0010c9ac8c6 100644 --- a/tests/acceptance/generate-component.spec.js +++ b/tests/acceptance/generate-component.spec.js @@ -7,8 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var conf = require('ember-cli/tests/helpers/conf'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); @@ -16,10 +15,6 @@ const readFile = denodeify(fs.readFile); describe('Acceptance: ng generate component', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { this.timeout(10000); return tmp.setup('./tmp').then(function () { diff --git a/tests/acceptance/generate-directive.spec.js b/tests/acceptance/generate-directive.spec.js index 9f013a69ee52..116e12b0636f 100644 --- a/tests/acceptance/generate-directive.spec.js +++ b/tests/acceptance/generate-directive.spec.js @@ -7,8 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var conf = require('ember-cli/tests/helpers/conf'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); @@ -16,10 +15,6 @@ const readFile = denodeify(fs.readFile); describe('Acceptance: ng generate directive', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); diff --git a/tests/acceptance/generate-module.spec.js b/tests/acceptance/generate-module.spec.js index 2be0d23e7ae9..c961e17bc7af 100644 --- a/tests/acceptance/generate-module.spec.js +++ b/tests/acceptance/generate-module.spec.js @@ -3,7 +3,6 @@ const ng = require('../helpers/ng'); const tmp = require('../helpers/tmp'); -const conf = require('ember-cli/tests/helpers/conf'); const existsSync = require('exists-sync'); const expect = require('chai').expect; const path = require('path'); @@ -12,10 +11,6 @@ const root = process.cwd(); const testPath = path.join(root, 'tmp', 'foo', 'src', 'app'); describe('Acceptance: ng generate module', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); diff --git a/tests/acceptance/generate-pipe.spec.js b/tests/acceptance/generate-pipe.spec.js index eedb299ac84d..1ddca3d98948 100644 --- a/tests/acceptance/generate-pipe.spec.js +++ b/tests/acceptance/generate-pipe.spec.js @@ -8,8 +8,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var conf = require('ember-cli/tests/helpers/conf'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); @@ -17,10 +16,6 @@ const readFile = denodeify(fs.readFile); describe('Acceptance: ng generate pipe', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); diff --git a/tests/acceptance/generate-route.spec.js b/tests/acceptance/generate-route.spec.js index 79ec44ac5b99..afe616bf5d26 100644 --- a/tests/acceptance/generate-route.spec.js +++ b/tests/acceptance/generate-route.spec.js @@ -3,7 +3,6 @@ const ng = require('../helpers/ng'); const tmp = require('../helpers/tmp'); -const conf = require('ember-cli/tests/helpers/conf'); const existsSync = require('exists-sync'); const expect = require('chai').expect; const fs = require('fs'); @@ -18,10 +17,6 @@ function fileExpectations(expectation) { } xdescribe('Acceptance: ng generate route', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); diff --git a/tests/acceptance/generate-service.spec.js b/tests/acceptance/generate-service.spec.js index f91584cba73f..f2c5c3aee5ca 100644 --- a/tests/acceptance/generate-service.spec.js +++ b/tests/acceptance/generate-service.spec.js @@ -7,8 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var conf = require('ember-cli/tests/helpers/conf'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); @@ -16,10 +15,6 @@ const readFile = denodeify(fs.readFile); describe('Acceptance: ng generate service', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); diff --git a/tests/acceptance/github-pages-deploy.spec.js b/tests/acceptance/github-pages-deploy.spec.js index 28358cc40a3a..7c12c290c23b 100644 --- a/tests/acceptance/github-pages-deploy.spec.js +++ b/tests/acceptance/github-pages-deploy.spec.js @@ -3,8 +3,7 @@ var ng = require('../helpers/ng'); var tmp = require('../helpers/tmp'); -var conf = require('ember-cli/tests/helpers/conf'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var fs = require('fs'); var path = require('path'); var chai = require('chai'); @@ -34,10 +33,6 @@ describe('Acceptance: ng github-pages:deploy', function() { }); } - before(conf.setup); - - after(conf.restore); - beforeEach(function() { this.timeout(10000); return tmp.setup('./tmp') diff --git a/tests/acceptance/init.spec.js b/tests/acceptance/init.spec.js index 457e7882d6dc..b299972f23cf 100644 --- a/tests/acceptance/init.spec.js +++ b/tests/acceptance/init.spec.js @@ -4,12 +4,11 @@ var ng = require('../helpers/ng'); var expect = require('chai').expect; var walkSync = require('walk-sync'); var glob = require('glob'); -var Blueprint = require('ember-cli/lib/models/blueprint'); +var Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); var path = require('path'); var tmp = require('../helpers/tmp'); var root = path.join(__dirname, '../../packages/angular-cli'); var util = require('util'); -var conf = require('ember-cli/tests/helpers/conf'); var minimatch = require('minimatch'); var intersect = require('lodash/intersection'); var remove = require('lodash/remove'); @@ -24,14 +23,6 @@ var defaultIgnoredFiles = Blueprint.ignoredFiles; describe('Acceptance: ng init', function () { this.timeout(20000); - before(function () { - conf.setup(); - }); - - after(function () { - conf.restore(); - }); - beforeEach(function () { // Make a copy of defaultIgnoredFiles. Blueprint.ignoredFiles = defaultIgnoredFiles.splice(0); diff --git a/tests/acceptance/new.spec.js b/tests/acceptance/new.spec.js index 1cdcc640b214..505b364fccd0 100644 --- a/tests/acceptance/new.spec.js +++ b/tests/acceptance/new.spec.js @@ -6,20 +6,15 @@ var existsSync = require('exists-sync'); var expect = require('chai').expect; var forEach = require('lodash/forEach'); var walkSync = require('walk-sync'); -var Blueprint = require('ember-cli/lib/models/blueprint'); +var Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); var util = require('util'); -var conf = require('ember-cli/tests/helpers/conf'); var EOL = require('os').EOL; var SilentError = require('silent-error'); describe('Acceptance: ng new', function () { - before(conf.setup); - - after(conf.restore); - beforeEach(function () { return tmp.setup('./tmp').then(function () { process.chdir('./tmp'); @@ -91,7 +86,7 @@ describe('Acceptance: ng new', function () { }); }); - it('Cannot run ng new, inside of ember-cli project', function () { + it('Cannot run ng new, inside of angular-cli project', function () { return ng(['new', 'foo', '--skip-npm', '--skip-bower', '--skip-git']) .then(function () { return ng(['new', 'foo', '--skip-npm', '--skip-bower', '--skip-git']).then(() => { diff --git a/tests/e2e/setup/010-build.ts b/tests/e2e/setup/010-build.ts index 7dc8b0826fb7..230a2cb41ab8 100644 --- a/tests/e2e/setup/010-build.ts +++ b/tests/e2e/setup/010-build.ts @@ -1,6 +1,21 @@ import {npm} from '../utils/process'; +import {updateJsonFile} from '../utils/project'; +import {join} from 'path'; +const packages = require('../../../lib/packages'); export default function() { - return npm('run', 'build'); + return npm('run', 'build') + .then(() => console.log('Updating package.json from dist...')) + .then(() => Promise.all(Object.keys(packages).map(pkgName => { + return updateJsonFile(join(packages[pkgName].dist, 'package.json'), json => { + Object.keys(packages).forEach(pkgName => { + if (json['dependencies'] && pkgName in json['dependencies']) { + json['dependencies'][pkgName] = packages[pkgName].dist; + } else if (json['devDependencies'] && pkgName in json['devDependencies']) { + json['devDependencies'][pkgName] = packages[pkgName].dist; + } + }); + }); + }))); } diff --git a/tests/e2e/setup/500-create-project.ts b/tests/e2e/setup/500-create-project.ts index e2ff78992b76..2e39507af4f4 100644 --- a/tests/e2e/setup/500-create-project.ts +++ b/tests/e2e/setup/500-create-project.ts @@ -6,6 +6,9 @@ import {updateTsConfig, updateJsonFile} from '../utils/project'; import {gitClean, gitCommit} from '../utils/git'; +let packages = require('../../../lib/packages'); + + export default function(argv: any) { let createProject = null; @@ -28,11 +31,9 @@ export default function(argv: any) { return Promise.resolve() .then(() => createProject) .then(() => updateJsonFile('package.json', json => { - const dist = join(__dirname, '../../../dist/'); - json['devDependencies']['angular-cli'] = join(dist, 'angular-cli'); - json['devDependencies']['@angular-cli/ast-tools'] = join(dist, 'ast-tools'); - json['devDependencies']['@angular-cli/base-href-webpack'] = join(dist, 'base-href-webpack'); - json['devDependencies']['@ngtools/webpack'] = join(dist, 'webpack'); + Object.keys(packages).forEach(pkgName => { + json['dependencies'][pkgName] = packages[pkgName].dist; + }); })) .then(() => { if (argv.nightly) { diff --git a/tests/helpers/mock-ui.js b/tests/helpers/mock-ui.js index fbfd941cb9fb..66785bc998e2 100644 --- a/tests/helpers/mock-ui.js +++ b/tests/helpers/mock-ui.js @@ -1,8 +1,8 @@ 'use strict'; -var UI = require('ember-cli/lib/ui'); +var UI = require('@angular-cli/ember-cli/lib/ui'); var through = require('through'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); module.exports = MockUI; function MockUI() { diff --git a/tests/helpers/tmp.js b/tests/helpers/tmp.js index f9ae335b22c3..6b58cd556e9b 100644 --- a/tests/helpers/tmp.js +++ b/tests/helpers/tmp.js @@ -2,7 +2,7 @@ var fs = require('fs-extra'); var existsSync = require('exists-sync'); -var Promise = require('ember-cli/lib/ext/promise'); +var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); var remove = Promise.denodeify(fs.remove); var root = process.cwd(); From 4d7409d9e03645dbe548417d26f6e090373ef5a8 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 9 Nov 2016 15:44:53 -0800 Subject: [PATCH 2/3] chore(install): move ember-cli to a directory in angular-cli --- .eslintignore | 2 +- package.json | 35 +++++++++- .../angular-cli/blueprints/class/index.js | 2 +- .../angular-cli/blueprints/component/index.js | 2 +- .../angular-cli/blueprints/directive/index.js | 2 +- .../angular-cli/blueprints/module/index.js | 2 +- packages/angular-cli/blueprints/ng2/index.js | 2 +- packages/angular-cli/blueprints/pipe/index.js | 2 +- .../angular-cli/blueprints/service/index.js | 2 +- packages/angular-cli/commands/build.ts | 2 +- packages/angular-cli/commands/completion.ts | 2 +- packages/angular-cli/commands/destroy.ts | 2 +- packages/angular-cli/commands/doc.ts | 2 +- packages/angular-cli/commands/e2e.ts | 2 +- packages/angular-cli/commands/easter-egg.ts | 2 +- packages/angular-cli/commands/generate.ts | 4 +- packages/angular-cli/commands/get.ts | 2 +- .../commands/github-pages-deploy.ts | 2 +- packages/angular-cli/commands/help.ts | 4 +- packages/angular-cli/commands/init.ts | 9 ++- packages/angular-cli/commands/lint.ts | 2 +- packages/angular-cli/commands/new.ts | 6 +- packages/angular-cli/commands/serve.ts | 2 +- packages/angular-cli/commands/set.ts | 2 +- packages/angular-cli/commands/test.ts | 2 +- packages/angular-cli/commands/version.ts | 2 +- .../{ => angular-cli}/ember-cli/LICENSE.md | 0 .../{ => angular-cli}/ember-cli/bin/ember | 0 .../ember-cli/lib/cli/cli.js | 0 .../ember-cli/lib/cli/index.js | 0 .../ember-cli/lib/cli/lookup-command.js | 0 .../ember-cli/lib/commands/addon.js | 0 .../ember-cli/lib/commands/asset-sizes.js | 0 .../ember-cli/lib/commands/build.js | 0 .../ember-cli/lib/commands/destroy.js | 0 .../ember-cli/lib/commands/generate.js | 0 .../ember-cli/lib/commands/help.js | 0 .../ember-cli/lib/commands/init.js | 0 .../ember-cli/lib/commands/install-addon.js | 0 .../ember-cli/lib/commands/install-bower.js | 0 .../ember-cli/lib/commands/install-npm.js | 0 .../ember-cli/lib/commands/install.js | 0 .../ember-cli/lib/commands/new.js | 0 .../ember-cli/lib/commands/test.js | 0 .../ember-cli/lib/commands/uninstall-npm.js | 0 .../ember-cli/lib/commands/unknown.js | 0 .../ember-cli/lib/commands/version.js | 0 .../ember-cli/lib/errors/silent.js | 0 .../ember-cli/lib/ext/promise.js | 0 .../ember-cli/lib/models/addon-discovery.js | 0 .../ember-cli/lib/models/addon.js | 0 .../ember-cli/lib/models/addons-factory.js | 0 .../ember-cli/lib/models/blueprint.js | 0 .../ember-cli/lib/models/builder.js | 0 .../ember-cli/lib/models/command.js | 2 +- .../ember-cli/lib/models/edit-file-diff.js | 0 .../ember-cli/lib/models/file-info.js | 0 .../lib/models/installation-checker.js | 0 .../ember-cli/lib/models/project.js | 0 .../ember-cli/lib/models/server-watcher.js | 0 .../ember-cli/lib/models/task.js | 0 .../ember-cli/lib/models/update-checker.js | 0 .../ember-cli/lib/models/watcher.js | 0 .../ember-cli/lib/tasks/addon-install.js | 0 .../ember-cli/lib/tasks/bower-install.js | 0 .../ember-cli/lib/tasks/build-watch.js | 0 .../ember-cli/lib/tasks/build.js | 0 .../tasks/create-and-step-into-directory.js | 0 .../lib/tasks/destroy-from-blueprint.js | 0 .../lib/tasks/generate-from-blueprint.js | 0 .../ember-cli/lib/tasks/git-init.js | 0 .../ember-cli/lib/tasks/install-blueprint.js | 0 .../ember-cli/lib/tasks/npm-install.js | 0 .../ember-cli/lib/tasks/npm-task.js | 0 .../ember-cli/lib/tasks/npm-uninstall.js | 0 .../ember-cli/lib/tasks/update.js | 0 .../ember-cli/lib/ui/index.js | 0 .../ember-cli/lib/ui/write-error.js | 0 .../lib/utilities/COMMIT_MESSAGE.txt | 0 .../ember-cli/lib/utilities/DAG.js | 0 .../lib/utilities/attempt-never-index.js | 0 .../ember-cli/lib/utilities/deprecate.js | 0 .../ember-cli/lib/utilities/doc-generator.js | 0 .../lib/utilities/find-build-file.js | 0 .../lib/utilities/get-option-args.js | 0 .../lib/utilities/get-package-base-name.js | 0 .../ember-cli/lib/utilities/json-generator.js | 0 .../ember-cli/lib/utilities/markdown-color.js | 0 .../lib/utilities/merge-blueprint-options.js | 0 .../ember-cli/lib/utilities/mk-tmp-dir-in.js | 0 .../utilities/normalize-blueprint-option.js | 0 .../ember-cli/lib/utilities/npm.js | 0 .../ember-cli/lib/utilities/open-editor.js | 0 .../ember-cli/lib/utilities/parse-options.js | 0 .../ember-cli/lib/utilities/path.js | 0 .../lib/utilities/platform-checker.js | 0 .../ember-cli/lib/utilities/print-command.js | 0 .../lib/utilities/printable-properties.js | 0 .../lib/utilities/require-as-hash.js | 0 .../ember-cli/lib/utilities/require-local.js | 0 .../ember-cli/lib/utilities/root-command.js | 0 .../ember-cli/lib/utilities/sequence.js | 0 .../lib/utilities/valid-project-name.js | 0 .../ember-cli/lib/utilities/version-utils.js | 0 .../ember-cli/lib/utilities/windows-admin.js | 0 packages/angular-cli/ember-cli/package.json | 21 ++++++ .../{ => angular-cli}/ember-cli/tsconfig.json | 0 packages/angular-cli/lib/cli/index.js | 6 +- packages/angular-cli/package.json | 35 +++++++++- .../angular-cli/tasks/build-webpack-watch.ts | 2 +- packages/angular-cli/tasks/build-webpack.ts | 2 +- .../angular-cli/tasks/create-github-repo.ts | 2 +- packages/angular-cli/tasks/doc.ts | 2 +- packages/angular-cli/tasks/e2e.ts | 2 +- packages/angular-cli/tasks/git-init.js | 4 +- packages/angular-cli/tasks/link-cli.ts | 2 +- packages/angular-cli/tasks/lint.ts | 2 +- packages/angular-cli/tasks/npm-install.ts | 2 +- packages/angular-cli/tasks/serve-webpack.ts | 2 +- packages/angular-cli/tasks/test.ts | 2 +- packages/ast-tools/src/change.spec.ts | 2 +- packages/ember-cli/package.json | 66 ------------------- tests/acceptance/generate-component.spec.js | 2 +- tests/acceptance/generate-directive.spec.js | 2 +- tests/acceptance/generate-pipe.spec.js | 2 +- tests/acceptance/generate-service.spec.js | 2 +- tests/acceptance/github-pages-deploy.spec.js | 2 +- tests/acceptance/init.spec.js | 2 +- tests/acceptance/new.spec.js | 2 +- tests/helpers/mock-ui.js | 4 +- tests/helpers/tmp.js | 2 +- 131 files changed, 148 insertions(+), 128 deletions(-) rename packages/{ => angular-cli}/ember-cli/LICENSE.md (100%) rename packages/{ => angular-cli}/ember-cli/bin/ember (100%) rename packages/{ => angular-cli}/ember-cli/lib/cli/cli.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/cli/index.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/cli/lookup-command.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/addon.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/asset-sizes.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/build.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/destroy.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/generate.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/help.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/init.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/install-addon.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/install-bower.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/install-npm.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/install.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/new.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/test.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/uninstall-npm.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/unknown.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/commands/version.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/errors/silent.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/ext/promise.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/addon-discovery.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/addon.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/addons-factory.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/blueprint.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/builder.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/command.js (99%) rename packages/{ => angular-cli}/ember-cli/lib/models/edit-file-diff.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/file-info.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/installation-checker.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/project.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/server-watcher.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/task.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/update-checker.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/models/watcher.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/addon-install.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/bower-install.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/build-watch.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/build.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/create-and-step-into-directory.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/destroy-from-blueprint.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/generate-from-blueprint.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/git-init.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/install-blueprint.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/npm-install.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/npm-task.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/npm-uninstall.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/tasks/update.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/ui/index.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/ui/write-error.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/COMMIT_MESSAGE.txt (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/DAG.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/attempt-never-index.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/deprecate.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/doc-generator.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/find-build-file.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/get-option-args.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/get-package-base-name.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/json-generator.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/markdown-color.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/merge-blueprint-options.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/mk-tmp-dir-in.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/normalize-blueprint-option.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/npm.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/open-editor.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/parse-options.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/path.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/platform-checker.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/print-command.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/printable-properties.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/require-as-hash.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/require-local.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/root-command.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/sequence.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/valid-project-name.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/version-utils.js (100%) rename packages/{ => angular-cli}/ember-cli/lib/utilities/windows-admin.js (100%) create mode 100644 packages/angular-cli/ember-cli/package.json rename packages/{ => angular-cli}/ember-cli/tsconfig.json (100%) delete mode 100644 packages/ember-cli/package.json diff --git a/.eslintignore b/.eslintignore index f220aa998f21..f07735d14909 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,4 +8,4 @@ typings/ packages/angular-cli/blueprints/*/files/ # Ignore ember cli. -packages/ember-cli/ \ No newline at end of file +packages/angular-cli/ember-cli/ \ No newline at end of file diff --git a/package.json b/package.json index ea1dcfc80eeb..3dd81570ca55 100644 --- a/package.json +++ b/package.json @@ -57,21 +57,36 @@ "chalk": "^1.1.3", "common-tags": "^1.3.1", "compression-webpack-plugin": "^0.3.2", + "configstore": "^2.0.0", "core-js": "^2.4.0", + "core-object": "0.0.2", "css-loader": "^0.23.1", + "debug": "^2.1.3", "denodeify": "^1.2.1", - "ember-cli": "2.5.0", + "diff": "^2.2.2", + "ember-cli-normalize-entity-name": "^1.0.0", + "ember-cli-preprocess-registry": "^2.0.0", "ember-cli-string-utils": "^1.0.0", "enhanced-resolve": "^2.2.2", + "exists-sync": "0.0.3", "exit": "^0.1.2", "exports-loader": "^0.6.3", "expose-loader": "^0.7.1", "extract-text-webpack-plugin": "^2.0.0-beta.4", "file-loader": "^0.8.5", + "findup": "0.1.5", + "findup-sync": "^0.2.1", "fs-extra": "^0.30.0", + "fs-monitor-stack": "^1.0.2", "fs.realpath": "^1.0.0", + "get-caller-file": "^1.0.0", + "git-repo-info": "^1.0.4", "glob": "^7.0.3", "html-webpack-plugin": "^2.19.0", + "inflection": "^1.7.0", + "inquirer": "^0.12.0", + "is-git-url": "^0.2.0", + "isbinaryfile": "^2.0.3", "istanbul-instrumenter-loader": "^0.2.0", "json-loader": "^0.5.4", "karma-sourcemap-loader": "^0.3.7", @@ -80,22 +95,35 @@ "less": "^2.7.1", "less-loader": "^2.2.3", "lodash": "^4.11.1", + "markdown-it": "4.3.0", + "markdown-it-terminal": "0.0.3", + "minimatch": "^3.0.0", + "mkdirp": "^0.5.1", + "node-modules-path": "^1.0.0", "node-sass": "^3.10.1", + "node-uuid": "^1.4.3", + "nopt": "^3.0.1", "npm-run-all": "^3.0.0", "offline-plugin": "^3.4.1", "opn": "4.0.1", + "ora": "^0.2.0", "parse5": "^2.1.5", "portfinder": "1.0.9", "postcss-discard-comments": "^2.0.4", "postcss-loader": "^0.9.1", "protractor": "^3.3.0", + "quick-temp": "0.1.5", "raw-loader": "^0.5.1", + "readline2": "0.1.1", "remap-istanbul": "^0.6.4", "resolve": "^1.1.7", "rimraf": "^2.5.3", + "rsvp": "^3.0.17", "rxjs": "5.0.0-beta.12", + "sane": "^1.1.1", "sass-loader": "^3.2.0", "script-loader": "^0.7.0", + "semver": "^5.1.0", "shelljs": "^0.7.0", "silent-error": "^1.0.0", "source-map-loader": "^0.1.5", @@ -104,15 +132,20 @@ "style-loader": "^0.13.1", "stylus": "^0.54.5", "stylus-loader": "^2.1.0", + "temp": "0.8.3", + "through": "^2.3.6", + "tree-sync": "^1.1.0", "ts-loader": "^0.8.2", "tslint": "^3.15.1", "tslint-loader": "^2.1.4", "typescript": "~2.0.3", "url-loader": "^0.5.7", + "walk-sync": "^0.2.6", "webpack": "2.1.0-beta.25", "webpack-dev-server": "2.1.0-beta.9", "webpack-md5-hash": "0.0.5", "webpack-merge": "^0.14.0", + "yam": "0.0.18", "zone.js": "^0.6.23" }, "ember-addon": { diff --git a/packages/angular-cli/blueprints/class/index.js b/packages/angular-cli/blueprints/class/index.js index 47b2a75a21e2..d76dac94653e 100644 --- a/packages/angular-cli/blueprints/class/index.js +++ b/packages/angular-cli/blueprints/class/index.js @@ -1,6 +1,6 @@ const stringUtils = require('ember-cli-string-utils'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/component/index.js b/packages/angular-cli/blueprints/component/index.js index 10d8fd93d55e..523427fc2226 100644 --- a/packages/angular-cli/blueprints/component/index.js +++ b/packages/angular-cli/blueprints/component/index.js @@ -1,6 +1,6 @@ const path = require('path'); const chalk = require('chalk'); -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); const findParentModule = require('../../utilities/find-parent-module').default; const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/directive/index.js b/packages/angular-cli/blueprints/directive/index.js index 27832830555a..edf0af1548c3 100644 --- a/packages/angular-cli/blueprints/directive/index.js +++ b/packages/angular-cli/blueprints/directive/index.js @@ -4,7 +4,7 @@ const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; const NodeHost = require('@angular-cli/ast-tools').NodeHost; -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/module/index.js b/packages/angular-cli/blueprints/module/index.js index 7c5b7cfed069..cc3030c594cb 100644 --- a/packages/angular-cli/blueprints/module/index.js +++ b/packages/angular-cli/blueprints/module/index.js @@ -1,5 +1,5 @@ const path = require('path'); -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/ng2/index.js b/packages/angular-cli/blueprints/ng2/index.js index 35680dfe6555..3ab5dd53ea42 100644 --- a/packages/angular-cli/blueprints/ng2/index.js +++ b/packages/angular-cli/blueprints/ng2/index.js @@ -1,4 +1,4 @@ -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const path = require('path'); const stringUtils = require('ember-cli-string-utils'); const getFiles = Blueprint.prototype.files; diff --git a/packages/angular-cli/blueprints/pipe/index.js b/packages/angular-cli/blueprints/pipe/index.js index 6c163daf985b..2fa51ddad727 100644 --- a/packages/angular-cli/blueprints/pipe/index.js +++ b/packages/angular-cli/blueprints/pipe/index.js @@ -4,7 +4,7 @@ const stringUtils = require('ember-cli-string-utils'); const astUtils = require('../../utilities/ast-utils'); const findParentModule = require('../../utilities/find-parent-module').default; const NodeHost = require('@angular-cli/ast-tools').NodeHost; -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/blueprints/service/index.js b/packages/angular-cli/blueprints/service/index.js index 834f2805300c..bcdf691a6372 100644 --- a/packages/angular-cli/blueprints/service/index.js +++ b/packages/angular-cli/blueprints/service/index.js @@ -1,7 +1,7 @@ const path = require('path'); const chalk = require('chalk'); const dynamicPathParser = require('../../utilities/dynamic-path-parser'); -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); const getFiles = Blueprint.prototype.files; module.exports = { diff --git a/packages/angular-cli/commands/build.ts b/packages/angular-cli/commands/build.ts index 36674a0d5831..a9ed8c3ee9cf 100644 --- a/packages/angular-cli/commands/build.ts +++ b/packages/angular-cli/commands/build.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import WebpackBuild from '../tasks/build-webpack'; import WebpackBuildWatch from '../tasks/build-webpack-watch'; diff --git a/packages/angular-cli/commands/completion.ts b/packages/angular-cli/commands/completion.ts index 27cc430adea6..0a272ad996b0 100644 --- a/packages/angular-cli/commands/completion.ts +++ b/packages/angular-cli/commands/completion.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const CompletionCommand = Command.extend({ name: 'completion', diff --git a/packages/angular-cli/commands/destroy.ts b/packages/angular-cli/commands/destroy.ts index 198f38d56260..57745599d2fe 100644 --- a/packages/angular-cli/commands/destroy.ts +++ b/packages/angular-cli/commands/destroy.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const SilentError = require('silent-error'); diff --git a/packages/angular-cli/commands/doc.ts b/packages/angular-cli/commands/doc.ts index 06fdae1b1f95..f3fe1ea6165f 100644 --- a/packages/angular-cli/commands/doc.ts +++ b/packages/angular-cli/commands/doc.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import { DocTask } from '../tasks/doc'; const DocCommand = Command.extend({ diff --git a/packages/angular-cli/commands/e2e.ts b/packages/angular-cli/commands/e2e.ts index d4d5fec7a2ee..c3074afb649d 100644 --- a/packages/angular-cli/commands/e2e.ts +++ b/packages/angular-cli/commands/e2e.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import {E2eTask} from '../tasks/e2e'; import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/easter-egg.ts b/packages/angular-cli/commands/easter-egg.ts index 7d5921da3070..7cae2cfecb6c 100644 --- a/packages/angular-cli/commands/easter-egg.ts +++ b/packages/angular-cli/commands/easter-egg.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const stringUtils = require('ember-cli-string-utils'); import * as chalk from 'chalk'; diff --git a/packages/angular-cli/commands/generate.ts b/packages/angular-cli/commands/generate.ts index 7dd55cc40432..94adafed29c8 100644 --- a/packages/angular-cli/commands/generate.ts +++ b/packages/angular-cli/commands/generate.ts @@ -3,8 +3,8 @@ import * as path from 'path'; import * as os from 'os'; const chalk = require('chalk'); -const EmberGenerateCommand = require('@angular-cli/ember-cli/lib/commands/generate'); -const Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +const EmberGenerateCommand = require('../ember-cli/lib/commands/generate'); +const Blueprint = require('../ember-cli/lib/models/blueprint'); const SilentError = require('silent-error'); diff --git a/packages/angular-cli/commands/get.ts b/packages/angular-cli/commands/get.ts index 0626913f7925..f567f76809e8 100644 --- a/packages/angular-cli/commands/get.ts +++ b/packages/angular-cli/commands/get.ts @@ -1,7 +1,7 @@ import * as chalk from 'chalk'; import {CliConfig} from '../models/config'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const GetCommand = Command.extend({ name: 'get', diff --git a/packages/angular-cli/commands/github-pages-deploy.ts b/packages/angular-cli/commands/github-pages-deploy.ts index d50f3f2c238c..6eb35fc73e37 100644 --- a/packages/angular-cli/commands/github-pages-deploy.ts +++ b/packages/angular-cli/commands/github-pages-deploy.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const SilentError = require('silent-error'); import denodeify = require('denodeify'); diff --git a/packages/angular-cli/commands/help.ts b/packages/angular-cli/commands/help.ts index 134a576c0e04..90f8da58cd5e 100644 --- a/packages/angular-cli/commands/help.ts +++ b/packages/angular-cli/commands/help.ts @@ -1,9 +1,9 @@ import * as fs from 'fs'; import * as path from 'path'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const stringUtils = require('ember-cli-string-utils'); -const lookupCommand = require('@angular-cli/ember-cli/lib/cli/lookup-command'); +const lookupCommand = require('../ember-cli/lib/cli/lookup-command'); const commandsToIgnore = [ 'easter-egg', diff --git a/packages/angular-cli/commands/init.ts b/packages/angular-cli/commands/init.ts index c520fdbba461..cf7bd381b1ad 100644 --- a/packages/angular-cli/commands/init.ts +++ b/packages/angular-cli/commands/init.ts @@ -1,12 +1,11 @@ import LinkCli from '../tasks/link-cli'; import NpmInstall from '../tasks/npm-install'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); -const Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +const Command = require('../ember-cli/lib/models/command'); +const Promise = require('../ember-cli/lib/ext/promise'); const SilentError = require('silent-error'); -const validProjectName = require('@angular-cli/ember-cli/lib/utilities/valid-project-name'); -const normalizeBlueprint = require( - '@angular-cli/ember-cli/lib/utilities/normalize-blueprint-option'); +const validProjectName = require('../ember-cli/lib/utilities/valid-project-name'); +const normalizeBlueprint = require('../ember-cli/lib/utilities/normalize-blueprint-option'); const GitInit = require('../tasks/git-init'); diff --git a/packages/angular-cli/commands/lint.ts b/packages/angular-cli/commands/lint.ts index ff8cc3fd323e..c90d02cecc95 100644 --- a/packages/angular-cli/commands/lint.ts +++ b/packages/angular-cli/commands/lint.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import LintTask from '../tasks/lint'; export default Command.extend({ diff --git a/packages/angular-cli/commands/new.ts b/packages/angular-cli/commands/new.ts index ce1cd844c806..81ee12b2cdca 100644 --- a/packages/angular-cli/commands/new.ts +++ b/packages/angular-cli/commands/new.ts @@ -1,10 +1,10 @@ import * as chalk from 'chalk'; import InitCommand from './init'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); -const Project = require('@angular-cli/ember-cli/lib/models/project'); +const Command = require('../ember-cli/lib/models/command'); +const Project = require('../ember-cli/lib/models/project'); const SilentError = require('silent-error'); -const validProjectName = require('@angular-cli/ember-cli/lib/utilities/valid-project-name'); +const validProjectName = require('../ember-cli/lib/utilities/valid-project-name'); const NewCommand = Command.extend({ diff --git a/packages/angular-cli/commands/serve.ts b/packages/angular-cli/commands/serve.ts index 9ab7853d0806..fc7d6ded01ff 100644 --- a/packages/angular-cli/commands/serve.ts +++ b/packages/angular-cli/commands/serve.ts @@ -1,6 +1,6 @@ import * as assign from 'lodash/assign'; import * as denodeify from 'denodeify'; -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); const SilentError = require('silent-error'); const PortFinder = require('portfinder'); import ServeWebpackTask from '../tasks/serve-webpack'; diff --git a/packages/angular-cli/commands/set.ts b/packages/angular-cli/commands/set.ts index 7bca42730592..6530f7ee5908 100644 --- a/packages/angular-cli/commands/set.ts +++ b/packages/angular-cli/commands/set.ts @@ -1,5 +1,5 @@ const SilentError = require('silent-error'); -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/test.ts b/packages/angular-cli/commands/test.ts index ba82276b5908..957618d48058 100644 --- a/packages/angular-cli/commands/test.ts +++ b/packages/angular-cli/commands/test.ts @@ -1,4 +1,4 @@ -const TestCommand = require('@angular-cli/ember-cli/lib/commands/test'); +const TestCommand = require('../ember-cli/lib/commands/test'); import TestTask from '../tasks/test'; import {CliConfig} from '../models/config'; diff --git a/packages/angular-cli/commands/version.ts b/packages/angular-cli/commands/version.ts index 29c8fd8d1bec..b455d22f821a 100644 --- a/packages/angular-cli/commands/version.ts +++ b/packages/angular-cli/commands/version.ts @@ -1,4 +1,4 @@ -const Command = require('@angular-cli/ember-cli/lib/models/command'); +const Command = require('../ember-cli/lib/models/command'); import * as path from 'path'; import * as child_process from 'child_process'; diff --git a/packages/ember-cli/LICENSE.md b/packages/angular-cli/ember-cli/LICENSE.md similarity index 100% rename from packages/ember-cli/LICENSE.md rename to packages/angular-cli/ember-cli/LICENSE.md diff --git a/packages/ember-cli/bin/ember b/packages/angular-cli/ember-cli/bin/ember similarity index 100% rename from packages/ember-cli/bin/ember rename to packages/angular-cli/ember-cli/bin/ember diff --git a/packages/ember-cli/lib/cli/cli.js b/packages/angular-cli/ember-cli/lib/cli/cli.js similarity index 100% rename from packages/ember-cli/lib/cli/cli.js rename to packages/angular-cli/ember-cli/lib/cli/cli.js diff --git a/packages/ember-cli/lib/cli/index.js b/packages/angular-cli/ember-cli/lib/cli/index.js similarity index 100% rename from packages/ember-cli/lib/cli/index.js rename to packages/angular-cli/ember-cli/lib/cli/index.js diff --git a/packages/ember-cli/lib/cli/lookup-command.js b/packages/angular-cli/ember-cli/lib/cli/lookup-command.js similarity index 100% rename from packages/ember-cli/lib/cli/lookup-command.js rename to packages/angular-cli/ember-cli/lib/cli/lookup-command.js diff --git a/packages/ember-cli/lib/commands/addon.js b/packages/angular-cli/ember-cli/lib/commands/addon.js similarity index 100% rename from packages/ember-cli/lib/commands/addon.js rename to packages/angular-cli/ember-cli/lib/commands/addon.js diff --git a/packages/ember-cli/lib/commands/asset-sizes.js b/packages/angular-cli/ember-cli/lib/commands/asset-sizes.js similarity index 100% rename from packages/ember-cli/lib/commands/asset-sizes.js rename to packages/angular-cli/ember-cli/lib/commands/asset-sizes.js diff --git a/packages/ember-cli/lib/commands/build.js b/packages/angular-cli/ember-cli/lib/commands/build.js similarity index 100% rename from packages/ember-cli/lib/commands/build.js rename to packages/angular-cli/ember-cli/lib/commands/build.js diff --git a/packages/ember-cli/lib/commands/destroy.js b/packages/angular-cli/ember-cli/lib/commands/destroy.js similarity index 100% rename from packages/ember-cli/lib/commands/destroy.js rename to packages/angular-cli/ember-cli/lib/commands/destroy.js diff --git a/packages/ember-cli/lib/commands/generate.js b/packages/angular-cli/ember-cli/lib/commands/generate.js similarity index 100% rename from packages/ember-cli/lib/commands/generate.js rename to packages/angular-cli/ember-cli/lib/commands/generate.js diff --git a/packages/ember-cli/lib/commands/help.js b/packages/angular-cli/ember-cli/lib/commands/help.js similarity index 100% rename from packages/ember-cli/lib/commands/help.js rename to packages/angular-cli/ember-cli/lib/commands/help.js diff --git a/packages/ember-cli/lib/commands/init.js b/packages/angular-cli/ember-cli/lib/commands/init.js similarity index 100% rename from packages/ember-cli/lib/commands/init.js rename to packages/angular-cli/ember-cli/lib/commands/init.js diff --git a/packages/ember-cli/lib/commands/install-addon.js b/packages/angular-cli/ember-cli/lib/commands/install-addon.js similarity index 100% rename from packages/ember-cli/lib/commands/install-addon.js rename to packages/angular-cli/ember-cli/lib/commands/install-addon.js diff --git a/packages/ember-cli/lib/commands/install-bower.js b/packages/angular-cli/ember-cli/lib/commands/install-bower.js similarity index 100% rename from packages/ember-cli/lib/commands/install-bower.js rename to packages/angular-cli/ember-cli/lib/commands/install-bower.js diff --git a/packages/ember-cli/lib/commands/install-npm.js b/packages/angular-cli/ember-cli/lib/commands/install-npm.js similarity index 100% rename from packages/ember-cli/lib/commands/install-npm.js rename to packages/angular-cli/ember-cli/lib/commands/install-npm.js diff --git a/packages/ember-cli/lib/commands/install.js b/packages/angular-cli/ember-cli/lib/commands/install.js similarity index 100% rename from packages/ember-cli/lib/commands/install.js rename to packages/angular-cli/ember-cli/lib/commands/install.js diff --git a/packages/ember-cli/lib/commands/new.js b/packages/angular-cli/ember-cli/lib/commands/new.js similarity index 100% rename from packages/ember-cli/lib/commands/new.js rename to packages/angular-cli/ember-cli/lib/commands/new.js diff --git a/packages/ember-cli/lib/commands/test.js b/packages/angular-cli/ember-cli/lib/commands/test.js similarity index 100% rename from packages/ember-cli/lib/commands/test.js rename to packages/angular-cli/ember-cli/lib/commands/test.js diff --git a/packages/ember-cli/lib/commands/uninstall-npm.js b/packages/angular-cli/ember-cli/lib/commands/uninstall-npm.js similarity index 100% rename from packages/ember-cli/lib/commands/uninstall-npm.js rename to packages/angular-cli/ember-cli/lib/commands/uninstall-npm.js diff --git a/packages/ember-cli/lib/commands/unknown.js b/packages/angular-cli/ember-cli/lib/commands/unknown.js similarity index 100% rename from packages/ember-cli/lib/commands/unknown.js rename to packages/angular-cli/ember-cli/lib/commands/unknown.js diff --git a/packages/ember-cli/lib/commands/version.js b/packages/angular-cli/ember-cli/lib/commands/version.js similarity index 100% rename from packages/ember-cli/lib/commands/version.js rename to packages/angular-cli/ember-cli/lib/commands/version.js diff --git a/packages/ember-cli/lib/errors/silent.js b/packages/angular-cli/ember-cli/lib/errors/silent.js similarity index 100% rename from packages/ember-cli/lib/errors/silent.js rename to packages/angular-cli/ember-cli/lib/errors/silent.js diff --git a/packages/ember-cli/lib/ext/promise.js b/packages/angular-cli/ember-cli/lib/ext/promise.js similarity index 100% rename from packages/ember-cli/lib/ext/promise.js rename to packages/angular-cli/ember-cli/lib/ext/promise.js diff --git a/packages/ember-cli/lib/models/addon-discovery.js b/packages/angular-cli/ember-cli/lib/models/addon-discovery.js similarity index 100% rename from packages/ember-cli/lib/models/addon-discovery.js rename to packages/angular-cli/ember-cli/lib/models/addon-discovery.js diff --git a/packages/ember-cli/lib/models/addon.js b/packages/angular-cli/ember-cli/lib/models/addon.js similarity index 100% rename from packages/ember-cli/lib/models/addon.js rename to packages/angular-cli/ember-cli/lib/models/addon.js diff --git a/packages/ember-cli/lib/models/addons-factory.js b/packages/angular-cli/ember-cli/lib/models/addons-factory.js similarity index 100% rename from packages/ember-cli/lib/models/addons-factory.js rename to packages/angular-cli/ember-cli/lib/models/addons-factory.js diff --git a/packages/ember-cli/lib/models/blueprint.js b/packages/angular-cli/ember-cli/lib/models/blueprint.js similarity index 100% rename from packages/ember-cli/lib/models/blueprint.js rename to packages/angular-cli/ember-cli/lib/models/blueprint.js diff --git a/packages/ember-cli/lib/models/builder.js b/packages/angular-cli/ember-cli/lib/models/builder.js similarity index 100% rename from packages/ember-cli/lib/models/builder.js rename to packages/angular-cli/ember-cli/lib/models/builder.js diff --git a/packages/ember-cli/lib/models/command.js b/packages/angular-cli/ember-cli/lib/models/command.js similarity index 99% rename from packages/ember-cli/lib/models/command.js rename to packages/angular-cli/ember-cli/lib/models/command.js index d5f43cc3d0b3..81dd9e353b9c 100644 --- a/packages/ember-cli/lib/models/command.js +++ b/packages/angular-cli/ember-cli/lib/models/command.js @@ -293,7 +293,7 @@ Command.prototype.parseAlias = function(option, alias) { try { aliasValue = JSON.parse(alias); } catch (e) { - var debug = require('debug')('@angular-cli/ember-cli/models/command'); + var debug = require('debug')('angular-cli/ember-cli/models/command'); debug(e); } } diff --git a/packages/ember-cli/lib/models/edit-file-diff.js b/packages/angular-cli/ember-cli/lib/models/edit-file-diff.js similarity index 100% rename from packages/ember-cli/lib/models/edit-file-diff.js rename to packages/angular-cli/ember-cli/lib/models/edit-file-diff.js diff --git a/packages/ember-cli/lib/models/file-info.js b/packages/angular-cli/ember-cli/lib/models/file-info.js similarity index 100% rename from packages/ember-cli/lib/models/file-info.js rename to packages/angular-cli/ember-cli/lib/models/file-info.js diff --git a/packages/ember-cli/lib/models/installation-checker.js b/packages/angular-cli/ember-cli/lib/models/installation-checker.js similarity index 100% rename from packages/ember-cli/lib/models/installation-checker.js rename to packages/angular-cli/ember-cli/lib/models/installation-checker.js diff --git a/packages/ember-cli/lib/models/project.js b/packages/angular-cli/ember-cli/lib/models/project.js similarity index 100% rename from packages/ember-cli/lib/models/project.js rename to packages/angular-cli/ember-cli/lib/models/project.js diff --git a/packages/ember-cli/lib/models/server-watcher.js b/packages/angular-cli/ember-cli/lib/models/server-watcher.js similarity index 100% rename from packages/ember-cli/lib/models/server-watcher.js rename to packages/angular-cli/ember-cli/lib/models/server-watcher.js diff --git a/packages/ember-cli/lib/models/task.js b/packages/angular-cli/ember-cli/lib/models/task.js similarity index 100% rename from packages/ember-cli/lib/models/task.js rename to packages/angular-cli/ember-cli/lib/models/task.js diff --git a/packages/ember-cli/lib/models/update-checker.js b/packages/angular-cli/ember-cli/lib/models/update-checker.js similarity index 100% rename from packages/ember-cli/lib/models/update-checker.js rename to packages/angular-cli/ember-cli/lib/models/update-checker.js diff --git a/packages/ember-cli/lib/models/watcher.js b/packages/angular-cli/ember-cli/lib/models/watcher.js similarity index 100% rename from packages/ember-cli/lib/models/watcher.js rename to packages/angular-cli/ember-cli/lib/models/watcher.js diff --git a/packages/ember-cli/lib/tasks/addon-install.js b/packages/angular-cli/ember-cli/lib/tasks/addon-install.js similarity index 100% rename from packages/ember-cli/lib/tasks/addon-install.js rename to packages/angular-cli/ember-cli/lib/tasks/addon-install.js diff --git a/packages/ember-cli/lib/tasks/bower-install.js b/packages/angular-cli/ember-cli/lib/tasks/bower-install.js similarity index 100% rename from packages/ember-cli/lib/tasks/bower-install.js rename to packages/angular-cli/ember-cli/lib/tasks/bower-install.js diff --git a/packages/ember-cli/lib/tasks/build-watch.js b/packages/angular-cli/ember-cli/lib/tasks/build-watch.js similarity index 100% rename from packages/ember-cli/lib/tasks/build-watch.js rename to packages/angular-cli/ember-cli/lib/tasks/build-watch.js diff --git a/packages/ember-cli/lib/tasks/build.js b/packages/angular-cli/ember-cli/lib/tasks/build.js similarity index 100% rename from packages/ember-cli/lib/tasks/build.js rename to packages/angular-cli/ember-cli/lib/tasks/build.js diff --git a/packages/ember-cli/lib/tasks/create-and-step-into-directory.js b/packages/angular-cli/ember-cli/lib/tasks/create-and-step-into-directory.js similarity index 100% rename from packages/ember-cli/lib/tasks/create-and-step-into-directory.js rename to packages/angular-cli/ember-cli/lib/tasks/create-and-step-into-directory.js diff --git a/packages/ember-cli/lib/tasks/destroy-from-blueprint.js b/packages/angular-cli/ember-cli/lib/tasks/destroy-from-blueprint.js similarity index 100% rename from packages/ember-cli/lib/tasks/destroy-from-blueprint.js rename to packages/angular-cli/ember-cli/lib/tasks/destroy-from-blueprint.js diff --git a/packages/ember-cli/lib/tasks/generate-from-blueprint.js b/packages/angular-cli/ember-cli/lib/tasks/generate-from-blueprint.js similarity index 100% rename from packages/ember-cli/lib/tasks/generate-from-blueprint.js rename to packages/angular-cli/ember-cli/lib/tasks/generate-from-blueprint.js diff --git a/packages/ember-cli/lib/tasks/git-init.js b/packages/angular-cli/ember-cli/lib/tasks/git-init.js similarity index 100% rename from packages/ember-cli/lib/tasks/git-init.js rename to packages/angular-cli/ember-cli/lib/tasks/git-init.js diff --git a/packages/ember-cli/lib/tasks/install-blueprint.js b/packages/angular-cli/ember-cli/lib/tasks/install-blueprint.js similarity index 100% rename from packages/ember-cli/lib/tasks/install-blueprint.js rename to packages/angular-cli/ember-cli/lib/tasks/install-blueprint.js diff --git a/packages/ember-cli/lib/tasks/npm-install.js b/packages/angular-cli/ember-cli/lib/tasks/npm-install.js similarity index 100% rename from packages/ember-cli/lib/tasks/npm-install.js rename to packages/angular-cli/ember-cli/lib/tasks/npm-install.js diff --git a/packages/ember-cli/lib/tasks/npm-task.js b/packages/angular-cli/ember-cli/lib/tasks/npm-task.js similarity index 100% rename from packages/ember-cli/lib/tasks/npm-task.js rename to packages/angular-cli/ember-cli/lib/tasks/npm-task.js diff --git a/packages/ember-cli/lib/tasks/npm-uninstall.js b/packages/angular-cli/ember-cli/lib/tasks/npm-uninstall.js similarity index 100% rename from packages/ember-cli/lib/tasks/npm-uninstall.js rename to packages/angular-cli/ember-cli/lib/tasks/npm-uninstall.js diff --git a/packages/ember-cli/lib/tasks/update.js b/packages/angular-cli/ember-cli/lib/tasks/update.js similarity index 100% rename from packages/ember-cli/lib/tasks/update.js rename to packages/angular-cli/ember-cli/lib/tasks/update.js diff --git a/packages/ember-cli/lib/ui/index.js b/packages/angular-cli/ember-cli/lib/ui/index.js similarity index 100% rename from packages/ember-cli/lib/ui/index.js rename to packages/angular-cli/ember-cli/lib/ui/index.js diff --git a/packages/ember-cli/lib/ui/write-error.js b/packages/angular-cli/ember-cli/lib/ui/write-error.js similarity index 100% rename from packages/ember-cli/lib/ui/write-error.js rename to packages/angular-cli/ember-cli/lib/ui/write-error.js diff --git a/packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt b/packages/angular-cli/ember-cli/lib/utilities/COMMIT_MESSAGE.txt similarity index 100% rename from packages/ember-cli/lib/utilities/COMMIT_MESSAGE.txt rename to packages/angular-cli/ember-cli/lib/utilities/COMMIT_MESSAGE.txt diff --git a/packages/ember-cli/lib/utilities/DAG.js b/packages/angular-cli/ember-cli/lib/utilities/DAG.js similarity index 100% rename from packages/ember-cli/lib/utilities/DAG.js rename to packages/angular-cli/ember-cli/lib/utilities/DAG.js diff --git a/packages/ember-cli/lib/utilities/attempt-never-index.js b/packages/angular-cli/ember-cli/lib/utilities/attempt-never-index.js similarity index 100% rename from packages/ember-cli/lib/utilities/attempt-never-index.js rename to packages/angular-cli/ember-cli/lib/utilities/attempt-never-index.js diff --git a/packages/ember-cli/lib/utilities/deprecate.js b/packages/angular-cli/ember-cli/lib/utilities/deprecate.js similarity index 100% rename from packages/ember-cli/lib/utilities/deprecate.js rename to packages/angular-cli/ember-cli/lib/utilities/deprecate.js diff --git a/packages/ember-cli/lib/utilities/doc-generator.js b/packages/angular-cli/ember-cli/lib/utilities/doc-generator.js similarity index 100% rename from packages/ember-cli/lib/utilities/doc-generator.js rename to packages/angular-cli/ember-cli/lib/utilities/doc-generator.js diff --git a/packages/ember-cli/lib/utilities/find-build-file.js b/packages/angular-cli/ember-cli/lib/utilities/find-build-file.js similarity index 100% rename from packages/ember-cli/lib/utilities/find-build-file.js rename to packages/angular-cli/ember-cli/lib/utilities/find-build-file.js diff --git a/packages/ember-cli/lib/utilities/get-option-args.js b/packages/angular-cli/ember-cli/lib/utilities/get-option-args.js similarity index 100% rename from packages/ember-cli/lib/utilities/get-option-args.js rename to packages/angular-cli/ember-cli/lib/utilities/get-option-args.js diff --git a/packages/ember-cli/lib/utilities/get-package-base-name.js b/packages/angular-cli/ember-cli/lib/utilities/get-package-base-name.js similarity index 100% rename from packages/ember-cli/lib/utilities/get-package-base-name.js rename to packages/angular-cli/ember-cli/lib/utilities/get-package-base-name.js diff --git a/packages/ember-cli/lib/utilities/json-generator.js b/packages/angular-cli/ember-cli/lib/utilities/json-generator.js similarity index 100% rename from packages/ember-cli/lib/utilities/json-generator.js rename to packages/angular-cli/ember-cli/lib/utilities/json-generator.js diff --git a/packages/ember-cli/lib/utilities/markdown-color.js b/packages/angular-cli/ember-cli/lib/utilities/markdown-color.js similarity index 100% rename from packages/ember-cli/lib/utilities/markdown-color.js rename to packages/angular-cli/ember-cli/lib/utilities/markdown-color.js diff --git a/packages/ember-cli/lib/utilities/merge-blueprint-options.js b/packages/angular-cli/ember-cli/lib/utilities/merge-blueprint-options.js similarity index 100% rename from packages/ember-cli/lib/utilities/merge-blueprint-options.js rename to packages/angular-cli/ember-cli/lib/utilities/merge-blueprint-options.js diff --git a/packages/ember-cli/lib/utilities/mk-tmp-dir-in.js b/packages/angular-cli/ember-cli/lib/utilities/mk-tmp-dir-in.js similarity index 100% rename from packages/ember-cli/lib/utilities/mk-tmp-dir-in.js rename to packages/angular-cli/ember-cli/lib/utilities/mk-tmp-dir-in.js diff --git a/packages/ember-cli/lib/utilities/normalize-blueprint-option.js b/packages/angular-cli/ember-cli/lib/utilities/normalize-blueprint-option.js similarity index 100% rename from packages/ember-cli/lib/utilities/normalize-blueprint-option.js rename to packages/angular-cli/ember-cli/lib/utilities/normalize-blueprint-option.js diff --git a/packages/ember-cli/lib/utilities/npm.js b/packages/angular-cli/ember-cli/lib/utilities/npm.js similarity index 100% rename from packages/ember-cli/lib/utilities/npm.js rename to packages/angular-cli/ember-cli/lib/utilities/npm.js diff --git a/packages/ember-cli/lib/utilities/open-editor.js b/packages/angular-cli/ember-cli/lib/utilities/open-editor.js similarity index 100% rename from packages/ember-cli/lib/utilities/open-editor.js rename to packages/angular-cli/ember-cli/lib/utilities/open-editor.js diff --git a/packages/ember-cli/lib/utilities/parse-options.js b/packages/angular-cli/ember-cli/lib/utilities/parse-options.js similarity index 100% rename from packages/ember-cli/lib/utilities/parse-options.js rename to packages/angular-cli/ember-cli/lib/utilities/parse-options.js diff --git a/packages/ember-cli/lib/utilities/path.js b/packages/angular-cli/ember-cli/lib/utilities/path.js similarity index 100% rename from packages/ember-cli/lib/utilities/path.js rename to packages/angular-cli/ember-cli/lib/utilities/path.js diff --git a/packages/ember-cli/lib/utilities/platform-checker.js b/packages/angular-cli/ember-cli/lib/utilities/platform-checker.js similarity index 100% rename from packages/ember-cli/lib/utilities/platform-checker.js rename to packages/angular-cli/ember-cli/lib/utilities/platform-checker.js diff --git a/packages/ember-cli/lib/utilities/print-command.js b/packages/angular-cli/ember-cli/lib/utilities/print-command.js similarity index 100% rename from packages/ember-cli/lib/utilities/print-command.js rename to packages/angular-cli/ember-cli/lib/utilities/print-command.js diff --git a/packages/ember-cli/lib/utilities/printable-properties.js b/packages/angular-cli/ember-cli/lib/utilities/printable-properties.js similarity index 100% rename from packages/ember-cli/lib/utilities/printable-properties.js rename to packages/angular-cli/ember-cli/lib/utilities/printable-properties.js diff --git a/packages/ember-cli/lib/utilities/require-as-hash.js b/packages/angular-cli/ember-cli/lib/utilities/require-as-hash.js similarity index 100% rename from packages/ember-cli/lib/utilities/require-as-hash.js rename to packages/angular-cli/ember-cli/lib/utilities/require-as-hash.js diff --git a/packages/ember-cli/lib/utilities/require-local.js b/packages/angular-cli/ember-cli/lib/utilities/require-local.js similarity index 100% rename from packages/ember-cli/lib/utilities/require-local.js rename to packages/angular-cli/ember-cli/lib/utilities/require-local.js diff --git a/packages/ember-cli/lib/utilities/root-command.js b/packages/angular-cli/ember-cli/lib/utilities/root-command.js similarity index 100% rename from packages/ember-cli/lib/utilities/root-command.js rename to packages/angular-cli/ember-cli/lib/utilities/root-command.js diff --git a/packages/ember-cli/lib/utilities/sequence.js b/packages/angular-cli/ember-cli/lib/utilities/sequence.js similarity index 100% rename from packages/ember-cli/lib/utilities/sequence.js rename to packages/angular-cli/ember-cli/lib/utilities/sequence.js diff --git a/packages/ember-cli/lib/utilities/valid-project-name.js b/packages/angular-cli/ember-cli/lib/utilities/valid-project-name.js similarity index 100% rename from packages/ember-cli/lib/utilities/valid-project-name.js rename to packages/angular-cli/ember-cli/lib/utilities/valid-project-name.js diff --git a/packages/ember-cli/lib/utilities/version-utils.js b/packages/angular-cli/ember-cli/lib/utilities/version-utils.js similarity index 100% rename from packages/ember-cli/lib/utilities/version-utils.js rename to packages/angular-cli/ember-cli/lib/utilities/version-utils.js diff --git a/packages/ember-cli/lib/utilities/windows-admin.js b/packages/angular-cli/ember-cli/lib/utilities/windows-admin.js similarity index 100% rename from packages/ember-cli/lib/utilities/windows-admin.js rename to packages/angular-cli/ember-cli/lib/utilities/windows-admin.js diff --git a/packages/angular-cli/ember-cli/package.json b/packages/angular-cli/ember-cli/package.json new file mode 100644 index 000000000000..074e63b92e6a --- /dev/null +++ b/packages/angular-cli/ember-cli/package.json @@ -0,0 +1,21 @@ +{ + "author": { + "name": "Stefan Penner, Robert Jackson and ember-cli contributors" + }, + "bugs": { + "url": "https://github.com/ember-cli/ember-cli/issues" + }, + "dependencies": { + }, + "description": "Command line tool for developing ambitious ember.js apps", + "directories": {}, + "homepage": "https://github.com/ember-cli/ember-cli#readme", + "license": "MIT", + "main": "lib/cli/index.js", + "name": "angular-cli/ember-cli", + "repository": { + "type": "git", + "url": "git+https://github.com/ember-cli/ember-cli.git" + }, + "version": "2.5.0" +} diff --git a/packages/ember-cli/tsconfig.json b/packages/angular-cli/ember-cli/tsconfig.json similarity index 100% rename from packages/ember-cli/tsconfig.json rename to packages/angular-cli/ember-cli/tsconfig.json diff --git a/packages/angular-cli/lib/cli/index.js b/packages/angular-cli/lib/cli/index.js index 8e7082978b7a..c94d8af20601 100644 --- a/packages/angular-cli/lib/cli/index.js +++ b/packages/angular-cli/lib/cli/index.js @@ -1,9 +1,9 @@ /*eslint-disable no-console */ // This file hooks up on require calls to transpile TypeScript. -const cli = require('@angular-cli/ember-cli/lib/cli'); -const UI = require('@angular-cli/ember-cli/lib/ui'); -const Watcher = require('@angular-cli/ember-cli/lib/models/watcher'); +const cli = require('../../ember-cli/lib/cli'); +const UI = require('../../ember-cli/lib/ui'); +const Watcher = require('../../ember-cli/lib/models/watcher'); const path = require('path'); Error.stackTraceLimit = Infinity; diff --git a/packages/angular-cli/package.json b/packages/angular-cli/package.json index 6db5ec962d60..ff7e17c1c30c 100644 --- a/packages/angular-cli/package.json +++ b/packages/angular-cli/package.json @@ -27,7 +27,6 @@ "dependencies": { "@angular-cli/ast-tools": "^1.0.1", "@angular-cli/base-href-webpack": "^1.0.0", - "@angular-cli/ember-cli": "^1.0.0", "@angular/common": "~2.1.0", "@angular/compiler": "~2.1.0", "@angular/compiler-cli": "~2.1.0", @@ -41,20 +40,36 @@ "chalk": "^1.1.3", "common-tags": "^1.3.1", "compression-webpack-plugin": "^0.3.2", + "configstore": "^2.0.0", "core-js": "^2.4.0", + "core-object": "0.0.2", "css-loader": "^0.23.1", + "debug": "^2.1.3", "denodeify": "^1.2.1", + "diff": "^2.2.2", + "ember-cli-normalize-entity-name": "^1.0.0", + "ember-cli-preprocess-registry": "^2.0.0", "ember-cli-string-utils": "^1.0.0", "enhanced-resolve": "^2.2.2", + "exists-sync": "0.0.3", "exit": "^0.1.2", "exports-loader": "^0.6.3", "expose-loader": "^0.7.1", "extract-text-webpack-plugin": "^2.0.0-beta.4", "file-loader": "^0.8.5", + "findup": "0.1.5", + "findup-sync": "^0.2.1", "fs-extra": "^0.30.0", + "fs-monitor-stack": "^1.0.2", "fs.realpath": "^1.0.0", + "get-caller-file": "^1.0.0", + "git-repo-info": "^1.0.4", "glob": "^7.0.3", "html-webpack-plugin": "^2.19.0", + "inflection": "^1.7.0", + "inquirer": "^0.12.0", + "is-git-url": "^0.2.0", + "isbinaryfile": "^2.0.3", "istanbul-instrumenter-loader": "^0.2.0", "json-loader": "^0.5.4", "karma-sourcemap-loader": "^0.3.7", @@ -63,21 +78,34 @@ "less": "^2.7.1", "less-loader": "^2.2.3", "lodash": "^4.11.1", + "markdown-it": "4.3.0", + "markdown-it-terminal": "0.0.3", + "minimatch": "^3.0.0", + "mkdirp": "^0.5.1", + "node-modules-path": "^1.0.0", "node-sass": "^3.10.1", + "node-uuid": "^1.4.3", + "nopt": "^3.0.1", "npm-run-all": "^3.0.0", "offline-plugin": "^3.4.1", "opn": "4.0.1", + "ora": "^0.2.0", "parse5": "^2.1.5", "portfinder": "1.0.9", "postcss-loader": "^0.9.1", "protractor": "^3.3.0", + "quick-temp": "0.1.5", "raw-loader": "^0.5.1", + "readline2": "0.1.1", "remap-istanbul": "^0.6.4", "resolve": "^1.1.7", "rimraf": "^2.5.3", + "rsvp": "^3.0.17", "rxjs": "5.0.0-beta.12", + "sane": "^1.1.1", "sass-loader": "^3.2.0", "script-loader": "^0.7.0", + "semver": "^5.1.0", "shelljs": "^0.7.0", "silent-error": "^1.0.0", "source-map-loader": "^0.1.5", @@ -86,15 +114,20 @@ "style-loader": "^0.13.1", "stylus": "^0.54.5", "stylus-loader": "^2.1.0", + "temp": "0.8.3", + "through": "^2.3.6", + "tree-sync": "^1.1.0", "ts-loader": "^0.8.2", "tslint": "^3.15.1", "tslint-loader": "^2.1.4", "typescript": "~2.0.3", "url-loader": "^0.5.7", + "walk-sync": "^0.2.6", "webpack": "2.1.0-beta.25", "webpack-dev-server": "2.1.0-beta.9", "webpack-md5-hash": "0.0.5", "webpack-merge": "^0.14.0", + "yam": "0.0.18", "zone.js": "^0.6.23" }, "ember-addon": { diff --git a/packages/angular-cli/tasks/build-webpack-watch.ts b/packages/angular-cli/tasks/build-webpack-watch.ts index 9b8b8be50537..45a1f6e55a55 100644 --- a/packages/angular-cli/tasks/build-webpack-watch.ts +++ b/packages/angular-cli/tasks/build-webpack-watch.ts @@ -1,6 +1,6 @@ import * as rimraf from 'rimraf'; import * as path from 'path'; -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as webpack from 'webpack'; const ProgressPlugin = require('webpack/lib/ProgressPlugin'); import { NgCliWebpackConfig } from '../models/webpack-config'; diff --git a/packages/angular-cli/tasks/build-webpack.ts b/packages/angular-cli/tasks/build-webpack.ts index fba722378042..e47564863eeb 100644 --- a/packages/angular-cli/tasks/build-webpack.ts +++ b/packages/angular-cli/tasks/build-webpack.ts @@ -1,6 +1,6 @@ import * as rimraf from 'rimraf'; import * as path from 'path'; -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as webpack from 'webpack'; import { BuildOptions } from '../commands/build'; import { NgCliWebpackConfig } from '../models/webpack-config'; diff --git a/packages/angular-cli/tasks/create-github-repo.ts b/packages/angular-cli/tasks/create-github-repo.ts index 0a3d9b9255fe..554d38396671 100644 --- a/packages/angular-cli/tasks/create-github-repo.ts +++ b/packages/angular-cli/tasks/create-github-repo.ts @@ -1,5 +1,5 @@ import * as denodeify from 'denodeify'; -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); const SilentError = require('silent-error'); import { exec } from 'child_process'; import * as https from 'https'; diff --git a/packages/angular-cli/tasks/doc.ts b/packages/angular-cli/tasks/doc.ts index d400d91d01b9..9ed47c1e206a 100644 --- a/packages/angular-cli/tasks/doc.ts +++ b/packages/angular-cli/tasks/doc.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); const opn = require('opn'); export const DocTask: any = Task.extend({ diff --git a/packages/angular-cli/tasks/e2e.ts b/packages/angular-cli/tasks/e2e.ts index afee9c5abda6..4de5cbac8fc7 100644 --- a/packages/angular-cli/tasks/e2e.ts +++ b/packages/angular-cli/tasks/e2e.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/git-init.js b/packages/angular-cli/tasks/git-init.js index 5d58640224b3..1ee9655061f0 100644 --- a/packages/angular-cli/tasks/git-init.js +++ b/packages/angular-cli/tasks/git-init.js @@ -1,12 +1,12 @@ 'use strict'; -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('../ember-cli/lib/ext/promise'); var exec = Promise.denodeify(require('child_process').exec); var path = require('path'); var pkg = require('../package.json'); var fs = require('fs'); var template = require('lodash/template'); -var Task = require('@angular-cli/ember-cli/lib/models/task'); +var Task = require('../ember-cli/lib/models/task'); var gitEnvironmentVariables = { GIT_AUTHOR_NAME: 'angular-cli', diff --git a/packages/angular-cli/tasks/link-cli.ts b/packages/angular-cli/tasks/link-cli.ts index d6a8c390365a..cb2ee1175e68 100644 --- a/packages/angular-cli/tasks/link-cli.ts +++ b/packages/angular-cli/tasks/link-cli.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/lint.ts b/packages/angular-cli/tasks/lint.ts index 0cf1bafc9a2f..08f9d5a653e2 100644 --- a/packages/angular-cli/tasks/lint.ts +++ b/packages/angular-cli/tasks/lint.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/npm-install.ts b/packages/angular-cli/tasks/npm-install.ts index 57c17c053c94..02e3f5d1cc27 100644 --- a/packages/angular-cli/tasks/npm-install.ts +++ b/packages/angular-cli/tasks/npm-install.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; import {exec} from 'child_process'; diff --git a/packages/angular-cli/tasks/serve-webpack.ts b/packages/angular-cli/tasks/serve-webpack.ts index 177e88eca36a..3f7d87849ee5 100644 --- a/packages/angular-cli/tasks/serve-webpack.ts +++ b/packages/angular-cli/tasks/serve-webpack.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as chalk from 'chalk'; const SilentError = require('silent-error'); -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as webpack from 'webpack'; const WebpackDevServer = require('webpack-dev-server'); const ProgressPlugin = require('webpack/lib/ProgressPlugin'); diff --git a/packages/angular-cli/tasks/test.ts b/packages/angular-cli/tasks/test.ts index df3de3147c72..56ba9e1c1d87 100644 --- a/packages/angular-cli/tasks/test.ts +++ b/packages/angular-cli/tasks/test.ts @@ -1,4 +1,4 @@ -const Task = require('@angular-cli/ember-cli/lib/models/task'); +const Task = require('../ember-cli/lib/models/task'); import * as path from 'path'; // require dependencies within the target project diff --git a/packages/ast-tools/src/change.spec.ts b/packages/ast-tools/src/change.spec.ts index 28d25e204051..1a3cc1833bcf 100644 --- a/packages/ast-tools/src/change.spec.ts +++ b/packages/ast-tools/src/change.spec.ts @@ -8,7 +8,7 @@ import {InsertChange, NodeHost, RemoveChange, ReplaceChange} from './change'; import fs = require('fs'); let path = require('path'); -let Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +let Promise = require('angular-cli/ember-cli/lib/ext/promise'); const readFile = Promise.denodeify(fs.readFile); diff --git a/packages/ember-cli/package.json b/packages/ember-cli/package.json deleted file mode 100644 index 1b3bf9cd4c3c..000000000000 --- a/packages/ember-cli/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "author": { - "name": "Stefan Penner, Robert Jackson and ember-cli contributors" - }, - "bugs": { - "url": "https://github.com/ember-cli/ember-cli/issues" - }, - "dependencies": { - "chalk": "^1.1.1", - "configstore": "^2.0.0", - "core-object": "0.0.2", - "debug": "^2.1.3", - "diff": "^2.2.2", - "ember-cli-normalize-entity-name": "^1.0.0", - "ember-cli-preprocess-registry": "^2.0.0", - "ember-cli-string-utils": "^1.0.0", - "exists-sync": "0.0.3", - "exit": "^0.1.2", - "findup": "0.1.5", - "findup-sync": "^0.2.1", - "fs-extra": "0.26.7", - "fs-monitor-stack": "^1.0.2", - "get-caller-file": "^1.0.0", - "git-repo-info": "^1.0.4", - "glob": "7.0.3", - "inflection": "^1.7.0", - "inquirer": "^0.12.0", - "is-git-url": "^0.2.0", - "isbinaryfile": "^2.0.3", - "leek": "0.0.21", - "lodash": "^4.11.1", - "markdown-it": "4.3.0", - "markdown-it-terminal": "0.0.3", - "minimatch": "^3.0.0", - "mkdirp": "^0.5.1", - "node-modules-path": "^1.0.0", - "node-uuid": "^1.4.3", - "nopt": "^3.0.1", - "ora": "^0.2.0", - "portfinder": "^1.0.7", - "quick-temp": "0.1.5", - "readline2": "0.1.1", - "resolve": "^1.1.6", - "rimraf": "^2.4.4", - "rsvp": "^3.0.17", - "sane": "^1.1.1", - "semver": "^5.1.0", - "silent-error": "^1.0.0", - "temp": "0.8.3", - "through": "^2.3.6", - "tree-sync": "^1.1.0", - "walk-sync": "^0.2.6", - "yam": "0.0.18" - }, - "description": "Command line tool for developing ambitious ember.js apps", - "directories": {}, - "homepage": "https://github.com/ember-cli/ember-cli#readme", - "license": "MIT", - "main": "lib/cli/index.js", - "name": "@angular-cli/ember-cli", - "repository": { - "type": "git", - "url": "git+https://github.com/ember-cli/ember-cli.git" - }, - "version": "2.5.0" -} diff --git a/tests/acceptance/generate-component.spec.js b/tests/acceptance/generate-component.spec.js index e0010c9ac8c6..20bd25460bbe 100644 --- a/tests/acceptance/generate-component.spec.js +++ b/tests/acceptance/generate-component.spec.js @@ -7,7 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); diff --git a/tests/acceptance/generate-directive.spec.js b/tests/acceptance/generate-directive.spec.js index 116e12b0636f..efeca10e03be 100644 --- a/tests/acceptance/generate-directive.spec.js +++ b/tests/acceptance/generate-directive.spec.js @@ -7,7 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); diff --git a/tests/acceptance/generate-pipe.spec.js b/tests/acceptance/generate-pipe.spec.js index 1ddca3d98948..767df23995bf 100644 --- a/tests/acceptance/generate-pipe.spec.js +++ b/tests/acceptance/generate-pipe.spec.js @@ -8,7 +8,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); diff --git a/tests/acceptance/generate-service.spec.js b/tests/acceptance/generate-service.spec.js index f2c5c3aee5ca..7d407c575554 100644 --- a/tests/acceptance/generate-service.spec.js +++ b/tests/acceptance/generate-service.spec.js @@ -7,7 +7,7 @@ var expect = require('chai').expect; var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var SilentError = require('silent-error'); const denodeify = require('denodeify'); diff --git a/tests/acceptance/github-pages-deploy.spec.js b/tests/acceptance/github-pages-deploy.spec.js index 7c12c290c23b..dff59065bac3 100644 --- a/tests/acceptance/github-pages-deploy.spec.js +++ b/tests/acceptance/github-pages-deploy.spec.js @@ -3,7 +3,7 @@ var ng = require('../helpers/ng'); var tmp = require('../helpers/tmp'); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var fs = require('fs'); var path = require('path'); var chai = require('chai'); diff --git a/tests/acceptance/init.spec.js b/tests/acceptance/init.spec.js index b299972f23cf..629767618e44 100644 --- a/tests/acceptance/init.spec.js +++ b/tests/acceptance/init.spec.js @@ -4,7 +4,7 @@ var ng = require('../helpers/ng'); var expect = require('chai').expect; var walkSync = require('walk-sync'); var glob = require('glob'); -var Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +var Blueprint = require('angular-cli/ember-cli/lib/models/blueprint'); var path = require('path'); var tmp = require('../helpers/tmp'); var root = path.join(__dirname, '../../packages/angular-cli'); diff --git a/tests/acceptance/new.spec.js b/tests/acceptance/new.spec.js index 505b364fccd0..02f60bb66f96 100644 --- a/tests/acceptance/new.spec.js +++ b/tests/acceptance/new.spec.js @@ -6,7 +6,7 @@ var existsSync = require('exists-sync'); var expect = require('chai').expect; var forEach = require('lodash/forEach'); var walkSync = require('walk-sync'); -var Blueprint = require('@angular-cli/ember-cli/lib/models/blueprint'); +var Blueprint = require('angular-cli/ember-cli/lib/models/blueprint'); var path = require('path'); var tmp = require('../helpers/tmp'); var root = process.cwd(); diff --git a/tests/helpers/mock-ui.js b/tests/helpers/mock-ui.js index 66785bc998e2..07f322998037 100644 --- a/tests/helpers/mock-ui.js +++ b/tests/helpers/mock-ui.js @@ -1,8 +1,8 @@ 'use strict'; -var UI = require('@angular-cli/ember-cli/lib/ui'); +var UI = require('angular-cli/ember-cli/lib/ui'); var through = require('through'); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); module.exports = MockUI; function MockUI() { diff --git a/tests/helpers/tmp.js b/tests/helpers/tmp.js index 6b58cd556e9b..733e7a3a8ef4 100644 --- a/tests/helpers/tmp.js +++ b/tests/helpers/tmp.js @@ -2,7 +2,7 @@ var fs = require('fs-extra'); var existsSync = require('exists-sync'); -var Promise = require('@angular-cli/ember-cli/lib/ext/promise'); +var Promise = require('angular-cli/ember-cli/lib/ext/promise'); var remove = Promise.denodeify(fs.remove); var root = process.cwd(); From b02a8dc5f67b831eadf5305b282b502bcfeccdfc Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 9 Nov 2016 16:16:38 -0800 Subject: [PATCH 3/3] further remove files --- packages/angular-cli/ember-cli/bin/ember | 35 -------- .../angular-cli/ember-cli/lib/cli/index.js | 2 +- .../ember-cli/lib/errors/silent.js | 11 --- .../ember-cli/lib/models/blueprint.js | 66 --------------- .../ember-cli/lib/tasks/addon-install.js | 81 ------------------- .../ember-cli/lib/tasks/bower-install.js | 57 ------------- .../ember-cli/lib/tasks/build-watch.js | 29 ------- .../angular-cli/ember-cli/lib/tasks/build.js | 52 ------------ .../ember-cli/lib/tasks/git-init.js | 2 +- .../ember-cli/lib/utilities/version-utils.js | 2 +- packages/angular-cli/ember-cli/package.json | 21 ----- packages/angular-cli/ember-cli/tsconfig.json | 34 -------- 12 files changed, 3 insertions(+), 389 deletions(-) delete mode 100755 packages/angular-cli/ember-cli/bin/ember delete mode 100644 packages/angular-cli/ember-cli/lib/errors/silent.js delete mode 100644 packages/angular-cli/ember-cli/lib/tasks/addon-install.js delete mode 100644 packages/angular-cli/ember-cli/lib/tasks/bower-install.js delete mode 100644 packages/angular-cli/ember-cli/lib/tasks/build-watch.js delete mode 100644 packages/angular-cli/ember-cli/lib/tasks/build.js delete mode 100644 packages/angular-cli/ember-cli/package.json delete mode 100644 packages/angular-cli/ember-cli/tsconfig.json diff --git a/packages/angular-cli/ember-cli/bin/ember b/packages/angular-cli/ember-cli/bin/ember deleted file mode 100755 index 7ccd04fde179..000000000000 --- a/packages/angular-cli/ember-cli/bin/ember +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -// Provide a title to the process in `ps` -process.title = 'ember'; - -var resolve = require('resolve'); -var exit = require('exit'); - -resolve('ember-cli', { - basedir: process.cwd() -}, function(error, projectLocalCli) { - var cli; - if (error) { - // If there is an error, resolve could not find the ember-cli - // library from a package.json. Instead, include it from a relative - // path to this script file (which is likely a globally installed - // npm package). Most common cause for hitting this is `ember new` - cli = require('../lib/cli'); - } else { - // No error implies a projectLocalCli, which will load whatever - // version of ember-cli you have installed in a local package.json - cli = require(projectLocalCli); - } - - cli({ - cliArgs: process.argv.slice(2), - inputStream: process.stdin, - outputStream: process.stdout, - errorStream: process.stderr - }).then(function(result) { - var exitCode = typeof result === 'object' ? result.exitCode : result; - exit(exitCode); - }); -}); diff --git a/packages/angular-cli/ember-cli/lib/cli/index.js b/packages/angular-cli/ember-cli/lib/cli/index.js index 1a4168965b8c..da0b31fe6ed6 100644 --- a/packages/angular-cli/ember-cli/lib/cli/index.js +++ b/packages/angular-cli/ember-cli/lib/cli/index.js @@ -8,7 +8,7 @@ var commands = requireAsHash('../commands/*.js', Command); var Task = require('../models/task'); var tasks = requireAsHash('../tasks/*.js', Task); var CLI = require('./cli'); -var packageConfig = require('../../package.json'); +var packageConfig = require('../../../package.json'); var debug = require('debug')('ember-cli:cli/index'); var merge = require('lodash/merge'); var path = require('path'); diff --git a/packages/angular-cli/ember-cli/lib/errors/silent.js b/packages/angular-cli/ember-cli/lib/errors/silent.js deleted file mode 100644 index 25be58c57161..000000000000 --- a/packages/angular-cli/ember-cli/lib/errors/silent.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var SilentError = require('silent-error'); -var deprecate = require('../utilities/deprecate'); - -Object.defineProperty(module, 'exports', { - get: function () { - deprecate('`ember-cli/lib/errors/silent.js` is deprecated, use `silent-error` instead.', true); - return SilentError; - } -}); diff --git a/packages/angular-cli/ember-cli/lib/models/blueprint.js b/packages/angular-cli/ember-cli/lib/models/blueprint.js index b5f56fdb44e8..b7bd48d686b1 100644 --- a/packages/angular-cli/ember-cli/lib/models/blueprint.js +++ b/packages/angular-cli/ember-cli/lib/models/blueprint.js @@ -1065,72 +1065,6 @@ Blueprint.prototype.addBowerPackagesToProject = function(packages, installOption }); }; -/** - Used to add an addon to the project's `package.json` and run it's - `defaultBlueprint` if it provides one. - - Generally, this would be done from the `afterInstall` hook, to - ensure that a package that is required by a given blueprint is - available. - - @method addAddonToProject - @param {Object} options - @return {Promise} -*/ -Blueprint.prototype.addAddonToProject = function(options) { - return this.addAddonsToProject({ - packages: [options], - extraArgs: options.extraArgs || {}, - blueprintOptions: options.blueprintOptions || {} - }); -}; - -/** - Used to add multiple addons to the project's `package.json` and run their - `defaultBlueprint` if they provide one. - - Generally, this would be done from the `afterInstall` hook, to - ensure that a package that is required by a given blueprint is - available. - - @method addAddonsToProject - @param {Object} options - @return {Promise} -*/ -Blueprint.prototype.addAddonsToProject = function (options) { - var taskOptions = { - packages: [], - extraArgs: options.extraArgs || [], - blueprintOptions: options.blueprintOptions || {} - }; - - var packages = options.packages; - if (packages && packages.length) { - taskOptions.packages = packages.map(function (pkg) { - if (typeof pkg === 'string') { - return pkg; - } - - if (!pkg.name) { - throw new SilentError('You must provide a package `name` to addAddonsToProject'); - } - - if (pkg.target) { - pkg.name += '@' + pkg.target; - } - - return pkg.name; - }); - } else { - throw new SilentError('You must provide package to addAddonsToProject'); - } - - var installText = (packages.length > 1) ? 'install addons' : 'install addon'; - this._writeStatusToUI(chalk.green, installText, taskOptions['packages'].join(', ')); - - return this.taskFor('addon-install').run(taskOptions); -}; - /** Used to retrieve a task with the given name. Passes the new task the standard information available (like `ui`, `analytics`, `project`, etc). diff --git a/packages/angular-cli/ember-cli/lib/tasks/addon-install.js b/packages/angular-cli/ember-cli/lib/tasks/addon-install.js deleted file mode 100644 index caec02b3a1c7..000000000000 --- a/packages/angular-cli/ember-cli/lib/tasks/addon-install.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; - -var Task = require('../models/task'); -var SilentError = require('silent-error'); -var merge = require('lodash/merge'); -var getPackageBaseName = require('../utilities/get-package-base-name'); -var Promise = require('../ext/promise'); - -module.exports = Task.extend({ - init: function() { - this.NpmInstallTask = this.NpmInstallTask || require('./npm-install'); - this.BlueprintTask = this.BlueprintTask || require('./generate-from-blueprint'); - }, - - run: function(options) { - var chalk = require('chalk'); - var ui = this.ui; - var packageNames = options['packages']; - var blueprintOptions = options.blueprintOptions || {}; - - var npmInstall = new this.NpmInstallTask({ - ui: this.ui, - analytics: this.analytics, - project: this.project - }); - - var blueprintInstall = new this.BlueprintTask({ - ui: this.ui, - analytics: this.analytics, - project: this.project, - testing: this.testing - }); - - ui.startProgress(chalk.green('Installing addon package'), chalk.green('.')); - - return npmInstall.run({ - packages: packageNames, - 'save-dev': true, - 'save-exact': true - }).then(function() { - return this.project.reloadAddons(); - }.bind(this)).then(function() { - return this.installBlueprint(blueprintInstall, packageNames, blueprintOptions); - }.bind(this)) - .finally(function() { ui.stopProgress(); }) - .then(function() { - ui.writeLine(chalk.green('Installed addon package.')); - }); - }, - - installBlueprint: function(install, packageNames, blueprintOptions) { - var blueprintName, taskOptions, addonInstall = this; - - return packageNames.reduce(function(promise, packageName) { - return promise.then(function() { - blueprintName = addonInstall.findDefaultBlueprintName(packageName); - taskOptions = merge({ - args: [blueprintName], - ignoreMissingMain: true - }, blueprintOptions || {}); - return install.run(taskOptions); - }); - }, Promise.resolve()); - }, - - findDefaultBlueprintName: function(givenName) { - var addon = this.project.findAddonByName(givenName); - - if (!addon) { - throw new SilentError('Install failed. Could not find addon with name: ' + givenName); - } - - var emberAddon = addon.pkg['ember-addon']; - - if (emberAddon && emberAddon.defaultBlueprint) { - return emberAddon.defaultBlueprint; - } - - return getPackageBaseName(addon.pkg.name); - } -}); diff --git a/packages/angular-cli/ember-cli/lib/tasks/bower-install.js b/packages/angular-cli/ember-cli/lib/tasks/bower-install.js deleted file mode 100644 index 81fe4b582c13..000000000000 --- a/packages/angular-cli/ember-cli/lib/tasks/bower-install.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; - -// Runs `bower install` in cwd - -var Promise = require('../ext/promise'); -var Task = require('../models/task'); - -module.exports = Task.extend({ - init: function() { - this.bower = this.bower || require('bower'); - this.bowerConfig = this.bowerConfig || require('bower-config'); - }, - // Options: Boolean verbose - run: function(options) { - var chalk = require('chalk'); - var bower = this.bower; - var bowerConfig = this.bowerConfig; - var ui = this.ui; - var packages = options.packages || []; - var installOptions = options.installOptions || { save: true }; - - ui.startProgress(chalk.green('Installing browser packages via Bower'), chalk.green('.')); - - var config = bowerConfig.read(); - config.interactive = true; - - return new Promise(function(resolve, reject) { - bower.commands.install(packages, installOptions, config) // Packages, options, config - .on('log', logBowerMessage) - .on('prompt', ui.prompt.bind(ui)) - .on('error', reject) - .on('end', resolve); - }) - .finally(function() { ui.stopProgress(); }) - .then(function() { - ui.writeLine(chalk.green('Installed browser packages via Bower.')); - }); - - function logBowerMessage(message) { - if (message.level === 'conflict') { - // e.g. - // conflict Unable to find suitable version for ember-data - // 1) ember-data 1.0.0-beta.6 - // 2) ember-data ~1.0.0-beta.7 - ui.writeLine(' ' + chalk.red('conflict') + ' ' + message.message); - message.data.picks.forEach(function(pick, index) { - ui.writeLine(' ' + chalk.green((index + 1) + ')') + ' ' + - message.data.name + ' ' + pick.endpoint.target); - }); - } else if (message.level === 'info' && options.verbose) { - // e.g. - // cached git://example.com/some-package.git#1.0.0 - ui.writeLine(' ' + chalk.green(message.id) + ' ' + message.message); - } - } - } -}); diff --git a/packages/angular-cli/ember-cli/lib/tasks/build-watch.js b/packages/angular-cli/ember-cli/lib/tasks/build-watch.js deleted file mode 100644 index 92c7029fc65a..000000000000 --- a/packages/angular-cli/ember-cli/lib/tasks/build-watch.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -var chalk = require('chalk'); -var Task = require('../models/task'); -var Watcher = require('../models/watcher'); -var Builder = require('../models/builder'); -var Promise = require('../ext/promise'); - -module.exports = Task.extend({ - run: function(options) { - this.ui.startProgress( - chalk.green('Building'), chalk.green('.') - ); - - return new Watcher({ - ui: this.ui, - builder: new Builder({ - ui: this.ui, - outputPath: options.outputPath, - environment: options.environment, - project: this.project - }), - analytics: this.analytics, - options: options - }).then(function() { - return new Promise(function () {}); // Run until failure or signal to exit - }); - } -}); diff --git a/packages/angular-cli/ember-cli/lib/tasks/build.js b/packages/angular-cli/ember-cli/lib/tasks/build.js deleted file mode 100644 index ae03e57efd0c..000000000000 --- a/packages/angular-cli/ember-cli/lib/tasks/build.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -var chalk = require('chalk'); -var Task = require('../models/task'); -var Builder = require('../models/builder'); - -module.exports = Task.extend({ - // Options: String outputPath - run: function(options) { - var ui = this.ui; - var analytics = this.analytics; - - ui.startProgress(chalk.green('Building'), chalk.green('.')); - - var builder = new Builder({ - ui: ui, - outputPath: options.outputPath, - environment: options.environment, - project: this.project - }); - - return builder.build() - .then(function(results) { - var totalTime = results.totalTime / 1e6; - - analytics.track({ - name: 'ember build', - message: totalTime + 'ms' - }); - - analytics.trackTiming({ - category: 'rebuild', - variable: 'build time', - label: 'broccoli build time', - value: parseInt(totalTime, 10) - }); - }) - .finally(function() { - ui.stopProgress(); - return builder.cleanup(); - }) - .then(function() { - ui.writeLine(chalk.green('Built project successfully. Stored in "' + - options.outputPath + '".')); - }) - .catch(function(err) { - ui.writeLine(chalk.red('Build failed.')); - - throw err; - }); - } -}); diff --git a/packages/angular-cli/ember-cli/lib/tasks/git-init.js b/packages/angular-cli/ember-cli/lib/tasks/git-init.js index 11fcf4e10e12..2152003c3505 100644 --- a/packages/angular-cli/ember-cli/lib/tasks/git-init.js +++ b/packages/angular-cli/ember-cli/lib/tasks/git-init.js @@ -4,7 +4,7 @@ var Promise = require('../../lib/ext/promise'); var Task = require('../models/task'); var exec = Promise.denodeify(require('child_process').exec); var path = require('path'); -var pkg = require('../../package.json'); +var pkg = require('../../../package.json'); var fs = require('fs'); var template = require('lodash/template'); diff --git a/packages/angular-cli/ember-cli/lib/utilities/version-utils.js b/packages/angular-cli/ember-cli/lib/utilities/version-utils.js index 7315cd7ce7e0..bad42d4737f5 100644 --- a/packages/angular-cli/ember-cli/lib/utilities/version-utils.js +++ b/packages/angular-cli/ember-cli/lib/utilities/version-utils.js @@ -7,7 +7,7 @@ var getRepoInfo = require('git-repo-info'); module.exports = { emberCLIVersion: function emberCLIVersion() { var gitPath = path.join(__dirname, '..','..','.git'); - var output = [require('../../package.json').version]; + var output = [require('../../../package.json').version]; if (existsSync(gitPath)) { var repoInfo = getRepoInfo(gitPath); diff --git a/packages/angular-cli/ember-cli/package.json b/packages/angular-cli/ember-cli/package.json deleted file mode 100644 index 074e63b92e6a..000000000000 --- a/packages/angular-cli/ember-cli/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "author": { - "name": "Stefan Penner, Robert Jackson and ember-cli contributors" - }, - "bugs": { - "url": "https://github.com/ember-cli/ember-cli/issues" - }, - "dependencies": { - }, - "description": "Command line tool for developing ambitious ember.js apps", - "directories": {}, - "homepage": "https://github.com/ember-cli/ember-cli#readme", - "license": "MIT", - "main": "lib/cli/index.js", - "name": "angular-cli/ember-cli", - "repository": { - "type": "git", - "url": "git+https://github.com/ember-cli/ember-cli.git" - }, - "version": "2.5.0" -} diff --git a/packages/angular-cli/ember-cli/tsconfig.json b/packages/angular-cli/ember-cli/tsconfig.json deleted file mode 100644 index 9623f183e150..000000000000 --- a/packages/angular-cli/ember-cli/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "mapRoot": "", - "module": "commonjs", - "moduleResolution": "node", - "noEmitOnError": true, - "noImplicitAny": true, - "outDir": "../../dist/angular-cli", - "rootDir": ".", - "sourceMap": true, - "sourceRoot": "/", - "target": "es5", - "lib": ["es6"], - "skipLibCheck": true, - "typeRoots": [ - "../../node_modules/@types" - ], - "baseUrl": "", - "paths": { - "@angular-cli/ast-tools": [ "../../dist/ast-tools/src" ], - "@angular-cli/base-href-webpack": [ "../../dist/base-href-webpack/src" ], - "@ngtools/webpack": [ "../../dist/webpack/src" ] - } - }, - "include": [ - "**/*" - ], - "exclude": [ - "blueprints/*/files/**/*" - ] -}