Skip to content

Commit

Permalink
feat(@angular/cli): allow to create new projects in existing directory
Browse files Browse the repository at this point in the history
Unless the directory is already under an Angular CLI project.

Fixes #4762
Close #4901
  • Loading branch information
hansl authored and filipesilva committed Feb 22, 2017
1 parent d79fd00 commit e4fc294
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 77 deletions.
52 changes: 41 additions & 11 deletions packages/@angular/cli/commands/new.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import * as fs from 'fs';
import * as path from 'path';
import denodeify = require('denodeify');

import InitCommand from './init';
import { CliConfig } from '../models/config';
import { validateProjectName } from '../utilities/validate-project-name';
import { oneLine } from 'common-tags';

const Command = require('../ember-cli/lib/models/command');
const Project = require('../ember-cli/lib/models/project');
const SilentError = require('silent-error');
const mkdir = denodeify(fs.mkdir);


const NewCommand = Command.extend({
name: 'new',
Expand All @@ -28,6 +36,10 @@ const NewCommand = Command.extend({
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] }
],

isProject: function (projectPath: string) {
return CliConfig.fromProject(projectPath) !== null;
},

run: function (commandOptions: any, rawArgs: string[]) {
const packageName = rawArgs.shift();

Expand All @@ -44,24 +56,42 @@ const NewCommand = Command.extend({
commandOptions.skipGit = true;
}

if (!commandOptions.directory) {
commandOptions.directory = packageName;
}

const createAndStepIntoDirectory =
new this.tasks.CreateAndStepIntoDirectory({ ui: this.ui });
const directoryName = path.join(process.cwd(),
commandOptions.directory ? commandOptions.directory : packageName);

const initCommand = new InitCommand({
ui: this.ui,
tasks: this.tasks,
project: Project.nullProject(this.ui, this.cli)
});

return createAndStepIntoDirectory
.run({
directoryName: commandOptions.directory,
dryRun: commandOptions.dryRun
})
let createDirectory;
if (commandOptions.dryRun) {
createDirectory = Promise.resolve()
.then(() => {
if (fs.existsSync(directoryName) && this.isProject(directoryName)) {
throw new SilentError(oneLine`
Directory ${directoryName} exists and is already an Angular CLI project.
`);
}
});
} else {
createDirectory = mkdir(directoryName)
.catch(err => {
if (err.code === 'EEXIST') {
if (this.isProject(directoryName)) {
throw new SilentError(oneLine`
Directory ${directoryName} exists and is already an Angular CLI project.
`);
}
} else {
throw err;
}
})
.then(() => process.chdir(directoryName));
}

return createDirectory
.then(initCommand.run.bind(initCommand, commandOptions, rawArgs));
}
});
Expand Down
1 change: 0 additions & 1 deletion packages/@angular/cli/ember-cli/lib/tasks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

module.exports = {
CreateAndStepIntoDirectory: require('./tasks/create-and-step-into-directory'),
DestroyFromBlueprint: require('./tasks/destroy-from-blueprint'),
GenerateFromBlueprint: require('./tasks/generate-from-blueprint'),
GitInit: require('./tasks/git-init'),
Expand Down

This file was deleted.

22 changes: 13 additions & 9 deletions packages/@angular/cli/models/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
|| findUp(CLI_CONFIG_FILE_NAME_ALT, __dirname);
}

static fromGlobal(): CliConfig {
static globalConfigFilePath(): string {
let globalConfigPath = path.join(getUserHome(), CLI_CONFIG_FILE_NAME);
const altGlobalConfigPath = path.join(getUserHome(), CLI_CONFIG_FILE_NAME_ALT);
if (!fs.existsSync(globalConfigPath) && fs.existsSync(altGlobalConfigPath)) {
globalConfigPath = altGlobalConfigPath;
return altGlobalConfigPath;
}
return globalConfigPath;
}

static fromGlobal(): CliConfig {
const globalConfigPath = this.globalConfigFilePath();

if (configCacheMap.has(globalConfigPath)) {
return configCacheMap.get(globalConfigPath);
Expand All @@ -62,7 +67,7 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
cliConfig.alias('defaults.component.service', 'defaults.spec.service');

// If any of them returned true, output a deprecation warning.
if (aliases.some(x => !!x)) {
if (aliases.some(x => x)) {
console.error(chalk.yellow(oneLine`
The "defaults.prefix" and "defaults.sourceDir" properties of .angular-cli.json
are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n
Expand All @@ -74,9 +79,9 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
return cliConfig;
}

static fromProject(): CliConfig {
const configPath = this.configFilePath();
if (!configPath) {
static fromProject(projectPath?: string): CliConfig {
const configPath = this.configFilePath(projectPath);
if (!configPath || configPath === this.globalConfigFilePath()) {
return null;
}
if (configCacheMap.has(configPath)) {
Expand All @@ -89,8 +94,7 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
globalConfigPath = altGlobalConfigPath;
}

const cliConfig = CliConfigBase.fromConfigPath<ConfigInterface>(
CliConfig.configFilePath(), [globalConfigPath]);
const cliConfig = CliConfigBase.fromConfigPath<ConfigInterface>(configPath, [globalConfigPath]);

const aliases = [
cliConfig.alias('apps.0.root', 'defaults.sourceDir'),
Expand All @@ -109,7 +113,7 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
cliConfig.alias('defaults.component.service', 'defaults.spec.service');

// If any of them returned true, output a deprecation warning.
if (aliases.some(x => !!x)) {
if (aliases.some(x => x)) {
console.error(chalk.yellow(oneLine`
The "defaults.prefix" and "defaults.sourceDir" properties of .angular-cli.json
are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n
Expand Down
4 changes: 3 additions & 1 deletion packages/@angular/cli/utilities/find-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import * as path from 'path';
import { existsSync } from 'fs';

export function findUp(name: string, from: string, stopOnNodeModules = false) {
const root = path.parse(from).root;

let currentDir = from;
while (currentDir && currentDir !== path.parse(currentDir).root) {
while (currentDir && currentDir !== root) {
const p = path.join(currentDir, name);
if (existsSync(p)) {
return p;
Expand Down
15 changes: 15 additions & 0 deletions tests/e2e/tests/commands/new/existing-directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as fs from 'fs';
import denodeify = require('denodeify');

import {ng} from '../../../utils/process';
import {getGlobalVariable} from '../../../utils/env';

const mkdir = denodeify(fs.mkdir);


export default function() {
return Promise.resolve()
.then(() => process.chdir(getGlobalVariable('tmp-root')))
.then(() => mkdir('empty-directory'))
.then(() => ng('new', 'foo', '--dir=empty-directory', '--skip-install', '--skip-git'));
}

0 comments on commit e4fc294

Please sign in to comment.