Skip to content

Commit 3f2eda1

Browse files
hanslZhicheng Wang
authored and
Zhicheng Wang
committed
feat(@angular/cli): allow to create new projects in existing directory
Unless the directory is already under an Angular CLI project. Fixes angular#4762 Close angular#4901
1 parent c482605 commit 3f2eda1

File tree

6 files changed

+72
-77
lines changed

6 files changed

+72
-77
lines changed

packages/@angular/cli/commands/new.ts

+41-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
import denodeify = require('denodeify');
4+
15
import InitCommand from './init';
6+
import { CliConfig } from '../models/config';
27
import { validateProjectName } from '../utilities/validate-project-name';
8+
import { oneLine } from 'common-tags';
39

410
const Command = require('../ember-cli/lib/models/command');
511
const Project = require('../ember-cli/lib/models/project');
612
const SilentError = require('silent-error');
13+
const mkdir = denodeify(fs.mkdir);
14+
715

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

39+
isProject: function (projectPath: string) {
40+
return CliConfig.fromProject(projectPath) !== null;
41+
},
42+
3143
run: function (commandOptions: any, rawArgs: string[]) {
3244
const packageName = rawArgs.shift();
3345

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

47-
if (!commandOptions.directory) {
48-
commandOptions.directory = packageName;
49-
}
50-
51-
const createAndStepIntoDirectory =
52-
new this.tasks.CreateAndStepIntoDirectory({ ui: this.ui });
59+
const directoryName = path.join(process.cwd(),
60+
commandOptions.directory ? commandOptions.directory : packageName);
5361

5462
const initCommand = new InitCommand({
5563
ui: this.ui,
5664
tasks: this.tasks,
5765
project: Project.nullProject(this.ui, this.cli)
5866
});
5967

60-
return createAndStepIntoDirectory
61-
.run({
62-
directoryName: commandOptions.directory,
63-
dryRun: commandOptions.dryRun
64-
})
68+
let createDirectory;
69+
if (commandOptions.dryRun) {
70+
createDirectory = Promise.resolve()
71+
.then(() => {
72+
if (fs.existsSync(directoryName) && this.isProject(directoryName)) {
73+
throw new SilentError(oneLine`
74+
Directory ${directoryName} exists and is already an Angular CLI project.
75+
`);
76+
}
77+
});
78+
} else {
79+
createDirectory = mkdir(directoryName)
80+
.catch(err => {
81+
if (err.code === 'EEXIST') {
82+
if (this.isProject(directoryName)) {
83+
throw new SilentError(oneLine`
84+
Directory ${directoryName} exists and is already an Angular CLI project.
85+
`);
86+
}
87+
} else {
88+
throw err;
89+
}
90+
})
91+
.then(() => process.chdir(directoryName));
92+
}
93+
94+
return createDirectory
6595
.then(initCommand.run.bind(initCommand, commandOptions, rawArgs));
6696
}
6797
});

packages/@angular/cli/ember-cli/lib/tasks.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11

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

packages/@angular/cli/ember-cli/lib/tasks/create-and-step-into-directory.js

-55
This file was deleted.

packages/@angular/cli/models/config.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,17 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
3232
|| findUp(CLI_CONFIG_FILE_NAME_ALT, __dirname);
3333
}
3434

35-
static fromGlobal(): CliConfig {
35+
static globalConfigFilePath(): string {
3636
let globalConfigPath = path.join(getUserHome(), CLI_CONFIG_FILE_NAME);
3737
const altGlobalConfigPath = path.join(getUserHome(), CLI_CONFIG_FILE_NAME_ALT);
3838
if (!fs.existsSync(globalConfigPath) && fs.existsSync(altGlobalConfigPath)) {
39-
globalConfigPath = altGlobalConfigPath;
39+
return altGlobalConfigPath;
4040
}
41+
return globalConfigPath;
42+
}
43+
44+
static fromGlobal(): CliConfig {
45+
const globalConfigPath = this.globalConfigFilePath();
4146

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

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

77-
static fromProject(): CliConfig {
78-
const configPath = this.configFilePath();
79-
if (!configPath) {
82+
static fromProject(projectPath?: string): CliConfig {
83+
const configPath = this.configFilePath(projectPath);
84+
if (!configPath || configPath === this.globalConfigFilePath()) {
8085
return null;
8186
}
8287
if (configCacheMap.has(configPath)) {
@@ -89,8 +94,7 @@ export class CliConfig extends CliConfigBase<ConfigInterface> {
8994
globalConfigPath = altGlobalConfigPath;
9095
}
9196

92-
const cliConfig = CliConfigBase.fromConfigPath<ConfigInterface>(
93-
CliConfig.configFilePath(), [globalConfigPath]);
97+
const cliConfig = CliConfigBase.fromConfigPath<ConfigInterface>(configPath, [globalConfigPath]);
9498

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

111115
// If any of them returned true, output a deprecation warning.
112-
if (aliases.some(x => !!x)) {
116+
if (aliases.some(x => x)) {
113117
console.error(chalk.yellow(oneLine`
114118
The "defaults.prefix" and "defaults.sourceDir" properties of .angular-cli.json
115119
are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n

packages/@angular/cli/utilities/find-up.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import * as path from 'path';
22
import { existsSync } from 'fs';
33

44
export function findUp(name: string, from: string, stopOnNodeModules = false) {
5+
const root = path.parse(from).root;
6+
57
let currentDir = from;
6-
while (currentDir && currentDir !== path.parse(currentDir).root) {
8+
while (currentDir && currentDir !== root) {
79
const p = path.join(currentDir, name);
810
if (existsSync(p)) {
911
return p;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as fs from 'fs';
2+
import denodeify = require('denodeify');
3+
4+
import {ng} from '../../../utils/process';
5+
import {getGlobalVariable} from '../../../utils/env';
6+
7+
const mkdir = denodeify(fs.mkdir);
8+
9+
10+
export default function() {
11+
return Promise.resolve()
12+
.then(() => process.chdir(getGlobalVariable('tmp-root')))
13+
.then(() => mkdir('empty-directory'))
14+
.then(() => ng('new', 'foo', '--dir=empty-directory', '--skip-install', '--skip-git'));
15+
}

0 commit comments

Comments
 (0)