generator-aspnetpostgresql
Version:
Yeoman generator for ASP.NET MVC Core apps with PostgreSQL support
457 lines (390 loc) • 20.4 kB
JavaScript
'use strict';
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var mkdirp = require('mkdirp');
var path = require('path');
var guid = require('uuid');
var projectName = require('vs_projectname');
var AspnetGenerator = yeoman.generators.Base.extend({
constructor: function() {
yeoman.generators.Base.apply(this, arguments);
this.argument('type', { type: String, required: false, desc: 'the project type to create' });
this.argument('applicationName', { type: String, required: false, desc: 'the name of the application' });
this.argument('ui', {type: String, required: false, defaults: 'bootstrap', desc: 'the ui library to use (bootstrap OR semantic)'});
},
init: function() {
this.log(yosay('Welcome to the marvellous ASP.NET Core generator!'));
this.log(chalk.green('This is an ugly hack of Omnisharp ASp net generator to support PostgreSQL databases.'));
this.log();
this.log();
this.log(chalk.green('If you have questions or suggestions, you can reach me at vlad.radu@gmail.com .'));
this.log();
this.log();
this.log(chalk.green('github repository: https://github.com/DeathArrow01/generator-aspnetpostgresql'));
this.log();
this.log();
this.log();
this.templatedata = {};
},
_checkProjectType: function() {
if (this.type) {
//normalize to lower case
this.type = this.type.toLowerCase();
var validProjectTypes = ['emptyweb', 'consoleapp', 'web', 'webbasic', 'webapi', 'nancy', 'classlibrary', 'unittest'];
if (validProjectTypes.indexOf(this.type) === -1) {
//if it's not in the list, send them through the normal path
this.log('"%s" is not a valid project type', chalk.cyan(this.type));
this.type = undefined;
this.applicationName = undefined;
this.connectionstring = undefined;
} else {
this.log('Creating "%s" project', chalk.cyan(this.type));
}
}
},
askFor: function() {
this._checkProjectType();
if (!this.type) {
var done = this.async();
var prompts = [{
type: 'list',
name: 'type',
message: 'What type of application do you want to create?',
choices: [
{
name: 'Empty Web Application',
value: 'emptyweb'
}, {
name: 'Console Application',
value: 'consoleapp'
}, {
name: 'MVC Web Application using PostgreSQL database',
value: 'web'
}, {
name: 'Web Application Basic [without Membership and Authorization]',
value: 'webbasic'
}, {
name: 'Web API Application',
value: 'webapi'
}, {
name: 'Nancy ASP.NET Application',
value: 'nancy'
}, {
name: 'Class Library',
value: 'classlibrary'
}, {
name: 'Unit test project (xUnit.net)',
value: 'unittest'
}
]
},
{
type: 'list',
name: 'ui',
message: 'Which UI framework would you like to use?',
default: 'bootstrap',
choices: [
{
name: 'Bootstrap (3.3.6)',
value: 'bootstrap'
},
{
name: 'Semantic UI (2.1.8)',
value: 'semantic'
}
],
when: function (answers){
return answers.type === 'web' || answers.type === 'webbasic';
}
}
];
this.prompt(prompts, function (props) {
this.type = props.type;
this.ui = props.ui;
done();
}.bind(this));
}
},
_buildTemplateData: function() {
this.templatedata.namespace = projectName(this.applicationName);
this.templatedata.applicationname = this.applicationName;
this.templatedata.guid = guid.v4();
this.templatedata.sqlite = (this.type === 'web') ? true : false;
this.templatedata.ui = this.ui;
this.templatedata.connectionstring = this.connectionstring;
},
askForName: function() {
if (!this.applicationName) {
var done = this.async();
var app = '';
switch (this.type) {
case 'emptyweb':
app = 'EmptyWebApplication';
break;
case 'consoleapp':
app = 'ConsoleApplication';
break;
case 'web':
app = 'WebApplication';
break;
case 'webbasic':
app = 'WebApplicationBasic';
break;
case 'webapi':
app = 'WebAPIApplication';
break;
case 'nancy':
app = 'NancyApplication';
break;
case 'classlibrary':
app = 'ClassLibrary';
break;
case 'unittest':
app = 'UnitTest';
break;
}
var prompts = [{
name: 'applicationName',
message: 'What\'s the name of your ASP.NET application?',
default: app
}];
this.prompt(prompts, function (props) {
this.applicationName = props.applicationName;
this._buildTemplateData();
done();
}.bind(this));
} else {
this._buildTemplateData();
}
},
askConnectionDetails: function() {
if (!this.connectionstring) {
var done = this.async();
var userID = 'username';
var password = 'password';
var host = 'localhost';
var port = '5432';
var database = 'database';
var prompts = [{
name: 'userID',
message: 'What\'s PostgreSQL user name?',
default: userID
},
{
name: 'password',
message: 'Input your PostgreSQL server password',
default: password
},
{
name: 'host',
message: 'What\'s the hostname of the PostgreSQL Server?',
default: host
},
{
name: 'port',
message: 'What\'s port the PostgreSQL server is listening to?',
default: port
},
{
name: 'database',
message: 'What\'s the database name?',
default: database
}
];
this.prompt(prompts, function (props) {
this.userID = props.userID;
this.password = props.password;
this.host = props.host;
this.port = props.port;
this.database = props.database;
this.connectionstring = 'User ID=' + this.userID + ';' + 'Password=' + this.password + ';' + 'Host=' + this.host + ';' + 'Port=' + this.port + ';' + 'Database=' + this.database + ';' + 'Pooling=true;';
this._buildTemplateData();
done();
}.bind(this));
} else {
this._buildTemplateData();
}
},
writing: function() {
this.sourceRoot(path.join(__dirname, './templates/projects'));
switch (this.type) {
case 'emptyweb':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
this.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.template(this.sourceRoot() + '/Program.cs', this.applicationName + '/Program.cs', this.templatedata);
this.template(this.sourceRoot() + '/Startup.cs', this.applicationName + '/Startup.cs', this.templatedata);
this.template(this.sourceRoot() + '/project.json', this.applicationName + '/project.json', this.templatedata);
this.copy(this.sourceRoot() + '/web.config', this.applicationName + '/web.config');
this.fs.copyTpl(this.sourceRoot() + '/../../Dockerfile.txt', this.applicationName + '/Dockerfile', this.templatedata);
/// Properties
this.fs.copyTpl(this.templatePath('Properties/**/*'), this.applicationName + '/Properties', this.templatedata);
this.fs.copy(this.sourceRoot() + '/README.md', this.applicationName + '/README.md');
mkdirp.sync(this.applicationName + '/wwwroot');
break;
case 'webapi':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
this.fs.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.copy(this.sourceRoot() + '/appsettings.json', this.applicationName + '/appsettings.json');
this.fs.copyTpl(this.sourceRoot() + '/../../Dockerfile.txt', this.applicationName + '/Dockerfile', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/Startup.cs', this.applicationName + '/Startup.cs', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/Program.cs', this.applicationName + '/Program.cs', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/project.json', this.applicationName + '/project.json', this.templatedata);
this.fs.copyTpl(this.templatePath('Properties/**/*'), this.applicationName + '/Properties', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/Controllers/ValuesController.cs', this.applicationName + '/Controllers/ValuesController.cs', this.templatedata);
this.fs.copy(this.sourceRoot() + '/web.config', this.applicationName + '/web.config');
this.fs.copy(this.sourceRoot() + '/README.md', this.applicationName + '/README.md');
mkdirp.sync(this.applicationName + '/wwwroot');
break;
case 'web':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
// individual files (configs, etc)
this.fs.copyTpl(this.sourceRoot() + '/../../Dockerfile.txt', this.applicationName + '/Dockerfile', this.templatedata);
this.fs.copy(this.templatePath('.bowerrc'), this.applicationName + '/.bowerrc');
this.fs.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.fs.copyTpl(this.templatePath('appsettings.json'), this.applicationName + '/appsettings.json', this.templatedata);
this.fs.copyTpl(this.templatePath('bower.json'), this.applicationName + '/bower.json', this.templatedata);
this.fs.copy(this.templatePath('bundleconfig.json'), this.applicationName + '/bundleconfig.json');
this.fs.copyTpl(this.templatePath('Program.cs'), this.applicationName + '/Program.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('project.json'), this.applicationName + '/project.json', this.templatedata);
this.fs.copy(this.templatePath('README.md'), this.applicationName + '/README.md');
this.fs.copyTpl(this.templatePath('Startup.cs'), this.applicationName + '/Startup.cs', this.templatedata);
// Controllers
this.fs.copyTpl(this.templatePath('Controllers/AccountController.cs'), this.applicationName + '/Controllers/AccountController.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Controllers/HomeController.cs'), this.applicationName + '/Controllers/HomeController.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Controllers/ManageController.cs'), this.applicationName + '/Controllers/ManageController.cs', this.templatedata);
// Migrations
this.fs.copyTpl(this.templatePath('Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs'), this.applicationName + '/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Data/Migrations/00000000000000_CreateIdentitySchema.cs'), this.applicationName + '/Data/Migrations/00000000000000_CreateIdentitySchema.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Data/Migrations/ApplicationDbContextModelSnapshot.cs'), this.applicationName + '/Data/Migrations/ApplicationDbContextModelSnapshot.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Data/ApplicationDbContext.cs'), this.applicationName + '/Data/ApplicationDbContext.cs', this.templatedata);
// Models
this.fs.copyTpl(this.templatePath('Models/ApplicationUser.cs'), this.applicationName + '/Models/ApplicationUser.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Models/AccountViewModels/**/*'), this.applicationName + '/Models/AccountViewModels', this.templatedata);
this.fs.copyTpl(this.templatePath('Models/ManageViewModels/**/*'), this.applicationName + '/Models/ManageViewModels', this.templatedata);
// Properties
this.fs.copyTpl(this.templatePath('Properties/**/*'), this.applicationName + '/Properties', this.templatedata);
// Services
this.fs.copyTpl(this.templatePath('Services/IEmailSender.cs'), this.applicationName + '/Services/IEmailSender.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Services/ISmsSender.cs'), this.applicationName + '/Services/ISmsSender.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('Services/MessageServices.cs'), this.applicationName + '/Services/MessageServices.cs', this.templatedata);
// Views
this.fs.copyTpl(this.templatePath('Views/**/*'), this.applicationName + '/Views', this.templatedata);
// wwwroot
// wwwroot - the content in the wwwroot does not include any direct references or imports
// So again it is copied 1-to-1 - but tests cover list of all files
this.fs.copy(this.templatePath('wwwroot/**/*'), this.applicationName + '/wwwroot');
this.fs.copy(this.templatePath('web.config'), this.applicationName + '/web.config');
// UI Component Overrides
// If the developer has placed anything in overrides/ui-module/project-type/**/* then use it
this.fs.copyTpl(this.templatePath('/../../overrides/' + this.ui + '/' + this.type + '/**/*'), this.applicationName + '/', this.templatedata);
break;
case 'webbasic':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
// individual files (configs, etc)
this.fs.copyTpl(this.sourceRoot() + '/../../Dockerfile.txt', this.applicationName + '/Dockerfile', this.templatedata);
this.fs.copy(this.templatePath('.bowerrc'), this.applicationName + '/.bowerrc');
this.fs.copy(this.templatePath('bundleconfig.json'), this.applicationName + '/bundleconfig.json');
this.fs.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.fs.copyTpl(this.templatePath('bower.json'), this.applicationName + '/bower.json', this.templatedata);
this.fs.copyTpl(this.templatePath('appsettings.json'), this.applicationName + '/appsettings.json', this.templatedata);
this.fs.copyTpl(this.templatePath('project.json'), this.applicationName + '/project.json', this.templatedata);
this.fs.copyTpl(this.templatePath('Program.cs'), this.applicationName + '/Program.cs', this.templatedata);
// Properties
this.fs.copyTpl(this.templatePath('Properties/**/*'), this.applicationName + '/Properties', this.templatedata);
this.fs.copy(this.templatePath('README.md'), this.applicationName + '/README.md');
this.fs.copyTpl(this.templatePath('Startup.cs'), this.applicationName + '/Startup.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('web.config'), this.applicationName + '/web.config', this.templatedata);
// Controllers
this.fs.copyTpl(this.templatePath('Controllers/HomeController.cs'), this.applicationName + '/Controllers/HomeController.cs', this.templatedata);
// Views
this.fs.copyTpl(this.templatePath('Views/**/*'), this.applicationName + '/Views', this.templatedata);
// wwwroot - the content in the wwwroot does not include any direct references or imports
// So again it is copied 1-to-1 - but tests cover list of all files
this.fs.copy(this.templatePath('wwwroot/**/*'), this.applicationName + '/wwwroot');
// UI Component Overrides
// If the developer has placed anything in overrides/ui-module/project-type/**/* then use it
this.fs.copyTpl(this.templatePath('/../../overrides/' + this.ui + '/' + this.type + '/**/*'), this.applicationName + '/', this.templatedata);
break;
case 'nancy':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
this.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.template(this.sourceRoot() + '/Startup.cs', this.applicationName + '/Startup.cs', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/project.json', this.applicationName + '/project.json', this.templatedata);
this.template(this.sourceRoot() + '/HomeModule.cs', this.applicationName + '/HomeModule.cs', this.templatedata);
this.template(this.sourceRoot() + '/Program.cs', this.applicationName + '/Program.cs', this.templatedata);
break;
case 'consoleapp':
this.sourceRoot(path.join(__dirname, '../templates/projects/consoleapp'));
this.fs.copy(path.join(__dirname, '../templates/gitignore.txt'), this.applicationName + '/.gitignore');
this.fs.copyTpl(this.templatePath('Program.cs'), this.applicationName + '/Program.cs', this.templatedata);
this.fs.copyTpl(this.templatePath('project.json'), this.applicationName + '/project.json', this.templatedata);
break;
case 'classlibrary':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
this.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.template(this.sourceRoot() + '/class.cs', this.applicationName + '/Class1.cs', this.templatedata);
this.fs.copyTpl(this.sourceRoot() + '/project.json', this.applicationName + '/project.json', this.templatedata);
break;
case 'unittest':
this.sourceRoot(path.join(__dirname, '../templates/projects/' + this.type));
this.copy(this.sourceRoot() + '/../../gitignore.txt', this.applicationName + '/.gitignore');
this.fs.copyTpl(this.templatePath('**.*'), this.destinationPath(this.applicationName), this.templatedata);
break;
default:
this.log('Unknown project type');
}
},
/**
* Called on the very end of Yo execution
* Dependencies are installed only for web type
* of projects that depends on client side libraries
* and tools like Gulp or Grunt
* Uses can skip installing dependencies using built-in yo
* --skip-install option
*/
end: function() {
if(!this.options['skip-install'] && (this.type === 'web' || this.type === 'webbasic')) {
process.chdir(this.applicationName);
this.installDependencies({
npm: false,
bower: true,
callback: this._showUsageHints.bind(this)
});
} else {
this._showUsageHints();
}
},
/**
* Shows usage hints to end user
* Called on the very end of all processes
*/
_showUsageHints: function() {
this.log('\r\n');
this.log('Your project is now created, you can use the following commands to get going');
this.log(chalk.green(' cd "' + this.applicationName + '"'));
this.log(chalk.green(' dotnet restore'));
this.log(chalk.green(' dotnet build') + ' (optional, build will also happen when it\'s run)');
if(this.type === 'web') {
this.log(chalk.green(' dotnet ef migrations add MigrationName') + ' (to initiate an initial database migration)' );
this.log(chalk.green(' dotnet ef database update') + ' (to create the PostgreSQL database for the project)');
}
switch (this.type) {
case 'consoleapp':
this.log(chalk.green(' dotnet run'));
break;
case 'emptyweb':
case 'nancy':
case 'web':
case 'webapi':
case 'webbasic':
this.log(chalk.green(' dotnet run'));
break;
case 'unittest':
this.log(chalk.green(' dotnet test'));
break;
}
this.log('\r\n');
}
});
module.exports = AspnetGenerator;