mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 23:24:03 +00:00
Create create-strap-app pacakge
This commit is contained in:
parent
9fdf6be746
commit
3295c6824b
7
packages/create-strapi-app/LICENSE.md
Normal file
7
packages/create-strapi-app/LICENSE.md
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright (c) 2015-2019 Strapi Solutions.
|
||||
|
||||
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.
|
||||
1
packages/create-strapi-app/README.md
Normal file
1
packages/create-strapi-app/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Create strapi app
|
||||
38
packages/create-strapi-app/create-strapi-app.js
Normal file
38
packages/create-strapi-app/create-strapi-app.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const commander = require('commander');
|
||||
const packageJson = require('./package.json');
|
||||
const generateNewApp = require('strapi-generate-new');
|
||||
|
||||
const program = new commander.Command(packageJson.name);
|
||||
|
||||
let projectName;
|
||||
|
||||
program
|
||||
.version(packageJson.version)
|
||||
.arguments('<directory>')
|
||||
.option('--debug', 'Display database connection error')
|
||||
.option('--quickstart', 'Quickstart app creation')
|
||||
.option('--dbclient <dbclient>', 'Database client')
|
||||
.option('--dbhost <dbhost>', 'Database host')
|
||||
.option('--dbsrv <dbsrv>', 'Database srv')
|
||||
.option('--dbport <dbport>', 'Database port')
|
||||
.option('--dbname <dbname>', 'Database name')
|
||||
.option('--dbusername <dbusername>', 'Database username')
|
||||
.option('--dbpassword <dbpassword>', 'Database password')
|
||||
.option('--dbssl <dbssl>', 'Database SSL')
|
||||
.option('--dbauth <dbauth>', 'Authentication Database')
|
||||
.option('--dbfile <dbfile>', 'Database file path for sqlite')
|
||||
.option('--dbforce', 'Overwrite database content if any')
|
||||
.description('create a new application')
|
||||
.action(directory => {
|
||||
projectName = directory;
|
||||
})
|
||||
.parse(process.argv);
|
||||
|
||||
if (projectName === undefined) {
|
||||
console.error('Please specify the <directory> of your project');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
generateNewApp(projectName, program);
|
||||
15
packages/create-strapi-app/index.js
Executable file
15
packages/create-strapi-app/index.js
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var currentNodeVersion = process.versions.node;
|
||||
var semver = currentNodeVersion.split('.');
|
||||
var major = semver[0];
|
||||
|
||||
if (major != 10) {
|
||||
console.error(`You are running Node ${currentNodeVersion}`);
|
||||
console.error('Strapi requires Node 10 only.');
|
||||
console.error('Please make sure to use the right version of Node.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
require('./create-strapi-app');
|
||||
43
packages/create-strapi-app/package.json
Normal file
43
packages/create-strapi-app/package.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "create-strapi-app",
|
||||
"version": "3.0.0-beta.6",
|
||||
"description": "Generate a new Strapi application.",
|
||||
"license": "MIT",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
"create-strapi-app",
|
||||
"create",
|
||||
"new",
|
||||
"generate",
|
||||
"strapi"
|
||||
],
|
||||
"main": "./index.js",
|
||||
"bin": {
|
||||
"create-strapi-app": "./index.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "^2.20.0",
|
||||
"strapi-generate-new": "3.0.0-beta.6"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
},
|
||||
"author": {
|
||||
"email": "hi@strapi.io",
|
||||
"name": "Strapi team",
|
||||
"url": "http://strapi.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/strapi/strapi.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/strapi/strapi/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Node.js core.
|
||||
const path = require('path');
|
||||
|
||||
const { green, cyan } = require('chalk');
|
||||
const fs = require('fs-extra');
|
||||
const ora = require('ora');
|
||||
const execa = require('execa');
|
||||
|
||||
// Logger.
|
||||
const trackSuccess = require('./success');
|
||||
|
||||
const installArguments = ['install', '--production', '--no-optional'];
|
||||
const runInstall = ({ rootPath, hasYarn }) => {
|
||||
if (hasYarn) {
|
||||
return execa('yarnpkg', installArguments, { cwd: rootPath });
|
||||
}
|
||||
return execa('npm', installArguments, { cwd: rootPath });
|
||||
};
|
||||
|
||||
module.exports = async (scope, cb) => {
|
||||
console.log('🏗 Application generation:');
|
||||
|
||||
let loader = ora('Copying files ...').start();
|
||||
|
||||
// Copy the default files.
|
||||
fs.copySync(
|
||||
path.resolve(__dirname, '..', 'files'),
|
||||
path.resolve(scope.rootPath)
|
||||
);
|
||||
|
||||
loader.succeed();
|
||||
|
||||
loader.start('Installing dependencies ...');
|
||||
|
||||
try {
|
||||
await runInstall(scope);
|
||||
loader.succeed();
|
||||
} catch (err) {
|
||||
loader.fail();
|
||||
trackSuccess('didNotInstallProjectDependencies', scope);
|
||||
cb(err);
|
||||
}
|
||||
|
||||
trackSuccess('didCreateProject', scope);
|
||||
|
||||
console.log();
|
||||
console.log(`👌 Your application was created at ${cyan(scope.rootPath)}.\n`);
|
||||
|
||||
if (scope.quick) {
|
||||
console.log('⚡️ Starting your application...');
|
||||
} else {
|
||||
console.log('⚡️ Change directory:');
|
||||
console.log(`$ ${green(`cd ${scope.name}`)}`);
|
||||
console.log();
|
||||
console.log('⚡️ Start your application:');
|
||||
console.log(`$ ${green('strapi develop')}`);
|
||||
}
|
||||
|
||||
cb();
|
||||
};
|
||||
@ -1,434 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Node.js core.
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const crypto = require('crypto');
|
||||
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
const { cyan, green } = require('chalk');
|
||||
const fs = require('fs-extra');
|
||||
const inquirer = require('inquirer');
|
||||
const execa = require('execa');
|
||||
|
||||
// Logger.
|
||||
const recordUsage = require('./success');
|
||||
|
||||
function hasYarn() {
|
||||
try {
|
||||
const { code } = execa.shellSync('yarnpkg --version');
|
||||
if (code === 0) return true;
|
||||
return false;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const databaseChoices = [
|
||||
{
|
||||
name: 'SQLite',
|
||||
value: {
|
||||
database: 'sqlite',
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
module: 'sqlite3',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'MongoDB',
|
||||
value: {
|
||||
database: 'mongo',
|
||||
connector: 'strapi-hook-mongoose',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'MySQL',
|
||||
value: {
|
||||
database: 'mysql',
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
module: 'mysql',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Postgres',
|
||||
value: {
|
||||
database: 'postgres',
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
module: 'pg',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* This `before` function is run before generating targets.
|
||||
* Validate, configure defaults, get extra dependencies, etc.
|
||||
*
|
||||
* @param {Object} scope
|
||||
* @param {Function} cb
|
||||
*/
|
||||
|
||||
/* eslint-disable no-useless-escape */
|
||||
module.exports = async scope => {
|
||||
// App info.
|
||||
const hasDatabaseConfig = !!scope.database;
|
||||
|
||||
_.defaults(scope, {
|
||||
name:
|
||||
scope.name === '.' || !scope.name
|
||||
? scope.name
|
||||
: path.basename(process.cwd()),
|
||||
author: process.env.USER || 'A Strapi developer',
|
||||
email: process.env.EMAIL || '',
|
||||
year: new Date().getFullYear(),
|
||||
license: 'MIT',
|
||||
database: {},
|
||||
hasYarn: hasYarn(),
|
||||
additionalsDependencies: [
|
||||
'strapi-plugin-settings-manager',
|
||||
'strapi-plugin-content-type-builder',
|
||||
'strapi-plugin-content-manager',
|
||||
'strapi-plugin-users-permissions',
|
||||
'strapi-plugin-email',
|
||||
'strapi-plugin-upload',
|
||||
],
|
||||
});
|
||||
|
||||
// Make changes to the rootPath where the Strapi project will be created.
|
||||
scope.rootPath = path.resolve(process.cwd(), scope.name || '');
|
||||
scope.tmpPath = path.resolve(
|
||||
os.tmpdir(),
|
||||
`strapi${crypto.randomBytes(6).toString('hex')}`
|
||||
);
|
||||
|
||||
await recordUsage('willCreateProject', scope);
|
||||
|
||||
// Ensure we aren't going to inadvertently delete any files
|
||||
if (await fs.exists(scope.rootPath)) {
|
||||
const stat = await fs.stat(scope.rootPath);
|
||||
|
||||
if (!stat.isDirectory()) {
|
||||
console.log(
|
||||
`⛔️ ${
|
||||
scope.rootPath
|
||||
} is not a directory. Make sure to create a Strapi application in an empty directory.`
|
||||
);
|
||||
throw new Error('Path is not a directory');
|
||||
}
|
||||
|
||||
const files = await fs.readdir(scope.rootPath);
|
||||
if (files.length > 1) {
|
||||
console.log(
|
||||
`⛔️ You can only create a Strapi app in an empty directory.`
|
||||
);
|
||||
|
||||
throw new Error('Directory is not empty');
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDatabaseConfig) {
|
||||
console.log(
|
||||
`Database determined by CLI args: ${scope.database.settings.client}`
|
||||
);
|
||||
}
|
||||
|
||||
const connectionValidation = async () => {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
when: !scope.quick && !hasDatabaseConfig,
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: 'Choose your installation type',
|
||||
choices: [
|
||||
{
|
||||
name: 'Quickstart (recommended)',
|
||||
value: 'quick',
|
||||
},
|
||||
{
|
||||
name: 'Custom (manual settings)',
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
when: answers => {
|
||||
return !hasDatabaseConfig && answers.type === 'custom';
|
||||
},
|
||||
type: 'list',
|
||||
name: 'client',
|
||||
message: 'Choose your main database:',
|
||||
choices: databaseChoices,
|
||||
default: () => {
|
||||
if (scope.client) {
|
||||
return _.findIndex(databaseChoices, {
|
||||
value: _.omit(scope.client, ['version']),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
scope.quick = answers.type === 'quick' || scope.quick;
|
||||
const isQuick = scope.quick;
|
||||
|
||||
if (isQuick) {
|
||||
answers.client = databaseChoices[0].value;
|
||||
}
|
||||
|
||||
if (hasDatabaseConfig) {
|
||||
const databaseChoice = _.find(databaseChoices, [
|
||||
'value.database',
|
||||
scope.database.settings.client,
|
||||
]);
|
||||
scope.database.connector = databaseChoice.value.connector;
|
||||
answers.client = {
|
||||
...databaseChoice.value,
|
||||
};
|
||||
} else {
|
||||
_.assign(scope.database, {
|
||||
connector: answers.client.connector,
|
||||
settings: {
|
||||
client: answers.client.database,
|
||||
},
|
||||
options: {},
|
||||
});
|
||||
}
|
||||
|
||||
scope.client = answers.client;
|
||||
|
||||
const connectedToTheDatabase = async (withMessage = true) => {
|
||||
if (withMessage) {
|
||||
console.log();
|
||||
console.log(
|
||||
`The app has been connected to the database ${green('successfully')}!`
|
||||
);
|
||||
}
|
||||
|
||||
if (isQuick) {
|
||||
await recordUsage('didChooseQuickstart', scope);
|
||||
} else {
|
||||
await recordUsage('didChooseCustomDatabase', scope);
|
||||
}
|
||||
|
||||
await recordUsage('didConnectDatabase', scope);
|
||||
};
|
||||
|
||||
await Promise.all([
|
||||
handleCustomDatabase({ scope, isQuick, hasDatabaseConfig }),
|
||||
installDatabaseTestingDep({ scope, isQuick }),
|
||||
]);
|
||||
|
||||
// Bypass real connection test.
|
||||
if (isQuick) {
|
||||
return connectedToTheDatabase(false);
|
||||
}
|
||||
|
||||
try {
|
||||
const connectivityFile = path.join(
|
||||
scope.tmpPath,
|
||||
'node_modules',
|
||||
scope.client.connector,
|
||||
'lib',
|
||||
'utils',
|
||||
'connectivity.js'
|
||||
);
|
||||
|
||||
return require(connectivityFile)(
|
||||
scope,
|
||||
connectedToTheDatabase,
|
||||
connectionValidation
|
||||
);
|
||||
} catch (err) {
|
||||
await recordUsage('didNotConnectDatabase', scope, err);
|
||||
console.log(err);
|
||||
fs.removeSync(scope.tmpPath);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
return connectionValidation();
|
||||
};
|
||||
|
||||
async function handleCustomDatabase({ scope, hasDatabaseConfig, isQuick }) {
|
||||
const isMongo = scope.client.database === 'mongo';
|
||||
const isSQLite = scope.database.settings.client === 'sqlite';
|
||||
|
||||
let answers = await inquirer.prompt([
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'input',
|
||||
name: 'database',
|
||||
message: 'Database name:',
|
||||
default: _.get(scope.database, 'database', scope.name),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'input',
|
||||
name: 'host',
|
||||
message: 'Host:',
|
||||
default: _.get(scope.database, 'host', '127.0.0.1'),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && isMongo,
|
||||
type: 'boolean',
|
||||
name: 'srv',
|
||||
message: '+srv connection:',
|
||||
default: _.get(scope.database, 'srv', false),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'input',
|
||||
name: 'port',
|
||||
message: `Port${
|
||||
isMongo ? ' (It will be ignored if you enable +srv)' : ''
|
||||
}:`,
|
||||
default: () => {
|
||||
// eslint-disable-line no-unused-vars
|
||||
if (_.get(scope.database, 'port')) {
|
||||
return scope.database.port;
|
||||
}
|
||||
|
||||
const ports = {
|
||||
mongo: 27017,
|
||||
postgres: 5432,
|
||||
mysql: 3306,
|
||||
};
|
||||
|
||||
return ports[scope.client.database];
|
||||
},
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'input',
|
||||
name: 'username',
|
||||
message: 'Username:',
|
||||
default: _.get(scope.database, 'username', undefined),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'password',
|
||||
name: 'password',
|
||||
message: 'Password:',
|
||||
mask: '*',
|
||||
default: _.get(scope.database, 'password', undefined),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && isMongo,
|
||||
type: 'input',
|
||||
name: 'authenticationDatabase',
|
||||
message: 'Authentication database (Maybe "admin" or blank):',
|
||||
default: _.get(scope.database, 'authenticationDatabase', undefined),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && !isSQLite,
|
||||
type: 'boolean',
|
||||
name: 'ssl',
|
||||
message: 'Enable SSL connection:',
|
||||
default: _.get(scope.database, 'ssl', false),
|
||||
},
|
||||
{
|
||||
when: !hasDatabaseConfig && isSQLite && !isQuick,
|
||||
type: 'input',
|
||||
name: 'filename',
|
||||
message: 'Filename:',
|
||||
default: () => '.tmp/data.db',
|
||||
},
|
||||
]);
|
||||
|
||||
if (isQuick) {
|
||||
answers.filename = '.tmp/data.db';
|
||||
}
|
||||
|
||||
if (hasDatabaseConfig) {
|
||||
answers = _.merge(
|
||||
_.omit(scope.database.settings, ['client']),
|
||||
scope.database.options
|
||||
);
|
||||
}
|
||||
|
||||
scope.database.settings.host = answers.host;
|
||||
scope.database.settings.port = answers.port;
|
||||
scope.database.settings.database = answers.database;
|
||||
scope.database.settings.username = answers.username;
|
||||
scope.database.settings.password = answers.password;
|
||||
|
||||
if (answers.filename) {
|
||||
scope.database.settings.filename = answers.filename;
|
||||
}
|
||||
if (answers.srv) {
|
||||
scope.database.settings.srv = _.toString(answers.srv) === 'true';
|
||||
}
|
||||
if (answers.authenticationDatabase) {
|
||||
scope.database.options.authenticationDatabase =
|
||||
answers.authenticationDatabase;
|
||||
}
|
||||
|
||||
// SQLite requirements.
|
||||
if (isSQLite) {
|
||||
// Necessary for SQLite configuration (https://knexjs.org/#Builder-insert).
|
||||
scope.database.options = {
|
||||
useNullAsDefault: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (answers.ssl && scope.client.database === 'mongo') {
|
||||
scope.database.options.ssl = _.toString(answers.ssl) === 'true';
|
||||
} else if (answers.ssl) {
|
||||
scope.database.settings.ssl = _.toString(answers.ssl) === 'true';
|
||||
}
|
||||
|
||||
console.log();
|
||||
if (isQuick) {
|
||||
console.log('✅ Connected to the database');
|
||||
} else {
|
||||
console.log(
|
||||
'⏳ Testing database connection...\r\nIt might take a minute, please have a coffee ☕️'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function installDatabaseTestingDep({ scope, isQuick }) {
|
||||
let packageCmd = scope.hasYarn
|
||||
? `yarnpkg --cwd ${scope.tmpPath} add`
|
||||
: `npm install --prefix ${scope.tmpPath}`;
|
||||
|
||||
// Manually create the temp directory for yarn
|
||||
if (scope.hasYarn) {
|
||||
await fs.ensureDir(scope.tmpPath);
|
||||
}
|
||||
|
||||
let cmd = `${packageCmd} ${scope.client.connector}@${
|
||||
scope.strapiPackageJSON.version
|
||||
}`;
|
||||
|
||||
if (scope.client.module) {
|
||||
cmd += ` ${scope.client.module}`;
|
||||
}
|
||||
|
||||
if (scope.client.connector === 'strapi-hook-bookshelf') {
|
||||
cmd += ` strapi-hook-knex@${scope.strapiPackageJSON.version}`;
|
||||
scope.additionalsDependencies = scope.additionalsDependencies.concat([
|
||||
'strapi-hook-knex',
|
||||
'knex',
|
||||
]);
|
||||
}
|
||||
|
||||
if (isQuick) {
|
||||
scope.client.version = 'latest';
|
||||
return;
|
||||
}
|
||||
|
||||
await execa.shell(cmd);
|
||||
|
||||
if (scope.client.module) {
|
||||
const lock = require(path.join(
|
||||
`${scope.tmpPath}`,
|
||||
'/node_modules/',
|
||||
`${scope.client.module}/package.json`
|
||||
));
|
||||
scope.client.version = lock.version;
|
||||
}
|
||||
}
|
||||
429
packages/strapi-generate-new/lib/generate-new.js
Normal file
429
packages/strapi-generate-new/lib/generate-new.js
Normal file
@ -0,0 +1,429 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Node.js core.
|
||||
const { join } = require('path');
|
||||
const { merge, pick } = require('lodash');
|
||||
|
||||
const chalk = require('chalk');
|
||||
const inquirer = require('inquirer');
|
||||
const execa = require('execa');
|
||||
|
||||
// Local dependencies.
|
||||
const packageJSON = require('./resources/json/package.json');
|
||||
const databaseJSON = require('./resources/json/database.json.js');
|
||||
|
||||
const { trackError, trackUsage } = require('./utils/usage');
|
||||
const stopProcess = require('./utils/stop-process');
|
||||
const dbQuestions = require('./db-questions');
|
||||
const fse = require('fs-extra');
|
||||
|
||||
/**
|
||||
* Copy required files for the generated application
|
||||
*/
|
||||
|
||||
const defaultConfigs = {
|
||||
sqlite: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'sqlite',
|
||||
filename: '.tmp/data.db',
|
||||
},
|
||||
options: {
|
||||
useNullAsDefault: true,
|
||||
},
|
||||
},
|
||||
postgres: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'postgres',
|
||||
},
|
||||
},
|
||||
mysql: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'mysql',
|
||||
},
|
||||
},
|
||||
mongo: {
|
||||
connector: 'strapi-hook-mongoose',
|
||||
},
|
||||
};
|
||||
|
||||
const sqlClientModule = {
|
||||
sqlite: 'sqlite3',
|
||||
postgres: 'pg',
|
||||
mysql: 'mysql',
|
||||
};
|
||||
|
||||
const clientDependencies = ({ scope, client }) => {
|
||||
switch (client) {
|
||||
case 'sqlite':
|
||||
case 'postgres':
|
||||
case 'mysql':
|
||||
return {
|
||||
'strapi-hook-bookshelf': scope.strapiVersion,
|
||||
'strapi-hook-knex': scope.strapiVersion,
|
||||
knex: 'latest',
|
||||
[sqlClientModule[client]]: 'latest',
|
||||
};
|
||||
case 'mongo':
|
||||
return {
|
||||
'strapi-hook-mongoose': scope.strapiVersion,
|
||||
};
|
||||
default:
|
||||
throw new Error(`Invalid client ${client}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = async scope => {
|
||||
await trackUsage({ event: 'willCreateProject', scope });
|
||||
|
||||
const hasDatabaseConfig = Boolean(scope.database);
|
||||
|
||||
// check rootPath is empty
|
||||
if (await fse.exists(scope.rootPath)) {
|
||||
const stat = await fse.stat(scope.rootPath);
|
||||
|
||||
if (!stat.isDirectory()) {
|
||||
await trackError({ scope, error: 'Path is not a directory' });
|
||||
|
||||
stopProcess(
|
||||
`⛔️ ${chalk.green(
|
||||
scope.rootPath
|
||||
)} is not a directory. Make sure to create a Strapi application in an empty directory.`
|
||||
);
|
||||
}
|
||||
|
||||
const files = await fse.readdir(scope.rootPath);
|
||||
if (files.length > 1) {
|
||||
await trackError({ scope, error: 'Directory is not empty' });
|
||||
stopProcess(
|
||||
`⛔️ You can only create a Strapi app in an empty directory\nMake sure ${chalk.green(
|
||||
scope.rootPath
|
||||
)} is empty.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// if database config is provided don't test the connection and create the project directly
|
||||
if (hasDatabaseConfig) {
|
||||
console.log('Creating a project from CLI arguments.');
|
||||
await trackUsage({ event: 'didChooseCustomDatabase', scope });
|
||||
|
||||
const client = scope.database.settings.client;
|
||||
const configuration = {
|
||||
client,
|
||||
connection: merge(defaultConfigs[client] || {}, scope.database),
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
return createProject(scope, configuration);
|
||||
}
|
||||
|
||||
// if cli quickstart create project with default sqlite options
|
||||
if (scope.quick === true) {
|
||||
console.log('Creating a quickstart project.');
|
||||
return createQuickStartProject(scope);
|
||||
}
|
||||
|
||||
const useQuickStart = await askShouldUseQuickstart();
|
||||
|
||||
// else if question response is quickstart create project
|
||||
if (useQuickStart) {
|
||||
console.log('Creating a quickstart project.');
|
||||
return createQuickStartProject(scope);
|
||||
}
|
||||
await trackUsage({ event: 'didChooseCustomDatabase', scope });
|
||||
|
||||
const configuration = await askDbInfosAndTest(scope).catch(error => {
|
||||
return trackUsage({ event: 'didNotConnectDatabase', scope, error }).then(
|
||||
() => {
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
console.log('Creating a project with custom database options');
|
||||
await trackUsage({ event: 'didConnectDatabase', scope });
|
||||
return createProject(scope, configuration);
|
||||
};
|
||||
|
||||
const MAX_RETRIES = 5;
|
||||
async function askDbInfosAndTest(scope) {
|
||||
let retries = 0;
|
||||
|
||||
async function loop() {
|
||||
// else ask for the client name
|
||||
const { client, connection } = await askDatabaseInfos(scope);
|
||||
|
||||
const configuration = {
|
||||
client,
|
||||
connection,
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
|
||||
await testDatabaseConnection({
|
||||
scope,
|
||||
configuration,
|
||||
})
|
||||
.then(
|
||||
() => fse.remove(scope.tmpPath),
|
||||
err => {
|
||||
return fse.remove(scope.tmpPath).then(() => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
if (retries < MAX_RETRIES - 1) {
|
||||
console.log(`⛔️ Connection test failed: ${err.message}`);
|
||||
|
||||
if (scope.debug) {
|
||||
console.log('Full error log:');
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
console.log('Retrying...');
|
||||
retries++;
|
||||
return loop();
|
||||
}
|
||||
|
||||
console.log(err);
|
||||
stopProcess(
|
||||
`️⛔️ Could not connect to your database after ${MAX_RETRIES} tries. Try to check your database configuration an retry.`
|
||||
);
|
||||
});
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
return loop();
|
||||
}
|
||||
|
||||
async function testDatabaseConnection({ scope, configuration }) {
|
||||
const { client } = configuration;
|
||||
|
||||
if (client === 'sqlite') return;
|
||||
|
||||
await installDatabaseTestingDep({
|
||||
scope,
|
||||
configuration,
|
||||
});
|
||||
|
||||
// const connectivityFile = join(
|
||||
// scope.tmpPath,
|
||||
// 'node_modules',
|
||||
// configuration.connection.connector,
|
||||
// 'lib',
|
||||
// 'utils',
|
||||
// 'connectivity.js'
|
||||
// );
|
||||
|
||||
// const tester = require(connectivityFile);
|
||||
const tester = require(`${
|
||||
configuration.connection.connector
|
||||
}/lib/utils/connectivity.js`);
|
||||
return tester({ scope, connection: configuration.connection });
|
||||
}
|
||||
|
||||
async function createProject(
|
||||
scope,
|
||||
{ connection, dependencies },
|
||||
{ isQuickstart = false } = {}
|
||||
) {
|
||||
console.log('Creating files');
|
||||
|
||||
const { rootPath } = scope;
|
||||
const resources = join(__dirname, 'resources');
|
||||
|
||||
try {
|
||||
// copy files
|
||||
await fse.copy(join(resources, 'files'), rootPath);
|
||||
|
||||
// copy templates
|
||||
await fse.writeJSON(
|
||||
join(rootPath, 'package.json'),
|
||||
packageJSON({
|
||||
strapiDependencies: scope.strapiDependencies,
|
||||
additionalsDependencies: dependencies,
|
||||
strapiVersion: scope.strapiVersion,
|
||||
projectName: scope.name,
|
||||
uuid: scope.uuid,
|
||||
}),
|
||||
{
|
||||
spaces: 2,
|
||||
}
|
||||
);
|
||||
|
||||
// ensure node_modules is created
|
||||
await fse.ensureDir(join(rootPath, 'node_modules'));
|
||||
|
||||
await Promise.all(
|
||||
['development', 'staging', 'production'].map(env => {
|
||||
return fse.writeJSON(
|
||||
join(rootPath, `config/environments/${env}/database.json`),
|
||||
databaseJSON({
|
||||
connection,
|
||||
env,
|
||||
}),
|
||||
{ spaces: 2 }
|
||||
);
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
await fse.remove(scope.rootPath);
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log('Installing packages. This might take a few minutes.');
|
||||
console.log();
|
||||
|
||||
try {
|
||||
await runInstall(scope);
|
||||
} catch (error) {
|
||||
await trackUsage({
|
||||
event: 'didNotInstallProjectDependencies',
|
||||
scope,
|
||||
error,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
await trackUsage({ event: 'didCreateProject', scope });
|
||||
|
||||
console.log(`Your application was created at ${chalk.green(rootPath)}.\n`);
|
||||
|
||||
const cmd = scope.hasYarn ? 'yarn' : 'npm run';
|
||||
|
||||
if (!isQuickstart) {
|
||||
console.log('⚡ Change directory:');
|
||||
console.log(`${chalk.cyan('cd')} ${scope.rootPath}`);
|
||||
console.log();
|
||||
console.log('⚡️ Start your application:');
|
||||
console.log(`${chalk.cyan(cmd)} develop`);
|
||||
}
|
||||
}
|
||||
|
||||
async function createQuickStartProject(scope) {
|
||||
await trackUsage({ event: 'didChooseQuickstart', scope });
|
||||
|
||||
// get default sqlite config
|
||||
const client = 'sqlite';
|
||||
const configuration = {
|
||||
client,
|
||||
connection: defaultConfigs[client],
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
|
||||
await createProject(scope, configuration, { isQuickstart: true });
|
||||
|
||||
console.log('⚡️ Starting your application...');
|
||||
|
||||
await execa('npm', ['run', 'develop'], {
|
||||
stdio: 'inherit',
|
||||
cwd: scope.rootPath,
|
||||
env: {
|
||||
FORCE_COLOR: 1,
|
||||
},
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
async function askShouldUseQuickstart() {
|
||||
const answer = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: 'Choose your installation type',
|
||||
choices: [
|
||||
{
|
||||
name: 'Quickstart (recommended)',
|
||||
value: 'quick',
|
||||
},
|
||||
{
|
||||
name: 'Custom (manual settings)',
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
return answer.type === 'quick';
|
||||
}
|
||||
|
||||
const SETTINGS_FIELDS = [
|
||||
'database',
|
||||
'host',
|
||||
'srv',
|
||||
'port',
|
||||
'username',
|
||||
'password',
|
||||
'filename',
|
||||
];
|
||||
|
||||
const OPTIONS_FIELDS = ['authenticationDatabase'];
|
||||
|
||||
async function askDatabaseInfos(scope) {
|
||||
const { client } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'client',
|
||||
message: 'Choose your default database client',
|
||||
choices: ['sqlite', 'postgres', 'mysql', 'mongo'],
|
||||
default: 'sqlite',
|
||||
},
|
||||
]);
|
||||
|
||||
const responses = await inquirer.prompt(
|
||||
dbQuestions[client].map(q => q({ scope, client }))
|
||||
);
|
||||
|
||||
const connection = merge({}, defaultConfigs[client] || {}, {
|
||||
settings: pick(responses, SETTINGS_FIELDS),
|
||||
options: pick(responses, OPTIONS_FIELDS),
|
||||
});
|
||||
|
||||
if (responses.ssl === true) {
|
||||
if (client === 'mongo') {
|
||||
connection.options.ssl = true;
|
||||
} else {
|
||||
connection.settings.ssl = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
client,
|
||||
connection,
|
||||
};
|
||||
}
|
||||
|
||||
async function installDatabaseTestingDep({ scope, configuration }) {
|
||||
let packageCmd = scope.hasYarn
|
||||
? `yarnpkg --cwd ${scope.tmpPath} add`
|
||||
: `npm install --prefix ${scope.tmpPath}`;
|
||||
|
||||
// Manually create the temp directory for yarn
|
||||
if (scope.hasYarn) {
|
||||
await fse.ensureDir(scope.tmpPath);
|
||||
}
|
||||
|
||||
const depArgs = Object.keys(configuration.dependencies).map(dep => {
|
||||
return `${dep}@${configuration.dependencies[dep]}`;
|
||||
});
|
||||
|
||||
const cmd = `${packageCmd} ${depArgs.join(' ')}`;
|
||||
await execa.shell(cmd);
|
||||
}
|
||||
|
||||
const installArguments = ['install', '--production', '--no-optional'];
|
||||
function runInstall({ rootPath, hasYarn }) {
|
||||
if (hasYarn) {
|
||||
return execa('yarnpkg', installArguments, {
|
||||
cwd: rootPath,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
return execa('npm', installArguments, { cwd: rootPath, stdio: 'inherit' });
|
||||
}
|
||||
@ -1,92 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Node.js core.
|
||||
const { join, resolve, basename } = require('path');
|
||||
const { merge, pick } = require('lodash');
|
||||
const os = require('os');
|
||||
const crypto = require('crypto');
|
||||
const chalk = require('chalk');
|
||||
const { machineIdSync } = require('node-machine-id');
|
||||
const uuid = require('uuid/v4');
|
||||
const inquirer = require('inquirer');
|
||||
const execa = require('execa');
|
||||
|
||||
// Local dependencies.
|
||||
const packageJSON = require('./resources/json/package.json');
|
||||
const databaseJSON = require('./resources/json/database.json.js');
|
||||
const generateNew = require('./generate-new');
|
||||
const { trackError, trackUsage } = require('./utils/usage');
|
||||
const stopProcess = require('./utils/stop-process');
|
||||
|
||||
const { trackError, trackUsage } = require('./usage');
|
||||
const dbQuestions = require('./db-questions');
|
||||
const fse = require('fs-extra');
|
||||
|
||||
/**
|
||||
* Copy required files for the generated application
|
||||
*/
|
||||
|
||||
const defaultConfigs = {
|
||||
sqlite: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'sqlite',
|
||||
filename: '.tmp/data.db',
|
||||
},
|
||||
options: {
|
||||
useNullAsDefault: true,
|
||||
},
|
||||
},
|
||||
postgres: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'postgres',
|
||||
},
|
||||
},
|
||||
mysql: {
|
||||
connector: 'strapi-hook-bookshelf',
|
||||
settings: {
|
||||
client: 'mysql',
|
||||
},
|
||||
},
|
||||
mongo: {
|
||||
connector: 'strapi-hook-mongoose',
|
||||
},
|
||||
};
|
||||
|
||||
const sqlClientModule = {
|
||||
sqlite: 'sqlite3',
|
||||
postgres: 'pg',
|
||||
mysql: 'mysql',
|
||||
};
|
||||
|
||||
const clientDependencies = ({ scope, client }) => {
|
||||
switch (client) {
|
||||
case 'sqlite':
|
||||
case 'postgres':
|
||||
case 'mysql':
|
||||
return {
|
||||
'strapi-hook-bookshelf': scope.strapiVersion,
|
||||
'strapi-hook-knex': scope.strapiVersion,
|
||||
knex: 'latest',
|
||||
[sqlClientModule[client]]: 'latest',
|
||||
};
|
||||
case 'mongo':
|
||||
return {
|
||||
'strapi-hook-mongoose': scope.strapiVersion,
|
||||
};
|
||||
default:
|
||||
throw new Error(`Invalid client ${client}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = async (location, cliArguments = {}) => {
|
||||
console.log('🚀 Creating your Strapi application.\n');
|
||||
|
||||
const { debug = false, quickstart = false } = cliArguments;
|
||||
|
||||
// Build scope.
|
||||
const rootPath = resolve(location);
|
||||
module.exports = (projectDirectory, cliArguments) => {
|
||||
const rootPath = resolve(projectDirectory);
|
||||
|
||||
const tmpPath = join(
|
||||
os.tmpdir(),
|
||||
@ -98,9 +25,9 @@ module.exports = async (location, cliArguments = {}) => {
|
||||
name: basename(rootPath),
|
||||
// use pacakge version as strapiVersion (all packages have the same version);
|
||||
strapiVersion: require('../package.json').version,
|
||||
debug: debug !== false,
|
||||
quick: quickstart !== false,
|
||||
uuid: 'testing', //uuid(),
|
||||
debug: cliArguments.debug !== undefined,
|
||||
quick: cliArguments.quickstart !== undefined,
|
||||
uuid: uuid(),
|
||||
deviceId: machineIdSync(),
|
||||
tmpPath,
|
||||
hasYarn: hasYarn(),
|
||||
@ -119,330 +46,18 @@ module.exports = async (location, cliArguments = {}) => {
|
||||
};
|
||||
|
||||
parseDatabaseArguments({ scope, args: cliArguments });
|
||||
initCancelCatcher();
|
||||
initCancelCatcher(scope);
|
||||
|
||||
await trackUsage({ event: 'willCreateProject', scope });
|
||||
console.log(`Creating a new Strapi application in ${chalk.green(rootPath)}.`);
|
||||
console.log();
|
||||
|
||||
const hasDatabaseConfig = Boolean(scope.database);
|
||||
|
||||
// check rootPath is empty
|
||||
if (await fse.exists(scope.rootPath)) {
|
||||
const stat = await fse.stat(scope.rootPath);
|
||||
|
||||
if (!stat.isDirectory()) {
|
||||
await trackError({ scope, error: 'Path is not a directory' });
|
||||
|
||||
stopProcess(
|
||||
`⛔️ ${
|
||||
scope.rootPath
|
||||
} is not a directory. Make sure to create a Strapi application in an empty directory.`
|
||||
);
|
||||
}
|
||||
|
||||
const files = await fse.readdir(scope.rootPath);
|
||||
if (files.length > 1) {
|
||||
await trackError({ scope, error: 'Directory is not empty' });
|
||||
stopProcess(
|
||||
`⛔️ You can only create a Strapi app in an empty directory.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// if database config is provided don't test the connection and create the project directly
|
||||
if (hasDatabaseConfig) {
|
||||
await trackUsage({ event: 'didChooseCustomDatabase', scope });
|
||||
|
||||
const client = scope.database.settings.client;
|
||||
const configuration = {
|
||||
client,
|
||||
connection: merge(defaultConfigs[client] || {}, scope.database),
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
return createProject(scope, configuration);
|
||||
}
|
||||
|
||||
// if cli quickstart create project with default sqlite options
|
||||
if (scope.quick === true) {
|
||||
return createQuickStartProject(scope);
|
||||
}
|
||||
|
||||
const useQuickStart = await askShouldUseQuickstart();
|
||||
|
||||
// else if question response is quickstart create project
|
||||
if (useQuickStart) {
|
||||
return createQuickStartProject(scope);
|
||||
}
|
||||
|
||||
await trackUsage({ event: 'didChooseCustomDatabase', scope });
|
||||
|
||||
const configuration = await askDbInfosAndTest(scope).catch(error => {
|
||||
return trackUsage({ event: 'didNotConnectDatabase', scope, error }).then(
|
||||
() => {
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
await trackUsage({ event: 'didConnectDatabase', scope });
|
||||
return createProject(scope, configuration);
|
||||
};
|
||||
|
||||
function stopProcess(message) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const MAX_RETRIES = 5;
|
||||
async function askDbInfosAndTest(scope) {
|
||||
let retries = 0;
|
||||
|
||||
async function loop() {
|
||||
// else ask for the client name
|
||||
const { client, connection } = await askDatabaseInfos(scope);
|
||||
|
||||
const configuration = {
|
||||
client,
|
||||
connection,
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
|
||||
await testDatabaseConnection({
|
||||
scope,
|
||||
configuration,
|
||||
})
|
||||
.then(
|
||||
() => fse.remove(scope.tmpPath),
|
||||
err => {
|
||||
return fse.remove(scope.tmpPath).then(() => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
console.log(`⛔️ Connection test failed: ${err.message}`);
|
||||
|
||||
if (scope.debug) {
|
||||
console.log('Full error log:');
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
if (retries < MAX_RETRIES) {
|
||||
console.log('Retrying...');
|
||||
retries++;
|
||||
return loop();
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Could not connect to your database after ${MAX_RETRIES} tries`
|
||||
);
|
||||
});
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
return loop();
|
||||
}
|
||||
|
||||
async function testDatabaseConnection({ scope, configuration }) {
|
||||
const { client } = configuration;
|
||||
|
||||
if (client === 'sqlite') return;
|
||||
|
||||
await installDatabaseTestingDep({
|
||||
scope,
|
||||
configuration,
|
||||
});
|
||||
|
||||
// const connectivityFile = join(
|
||||
// scope.tmpPath,
|
||||
// 'node_modules',
|
||||
// configuration.connection.connector,
|
||||
// 'lib',
|
||||
// 'utils',
|
||||
// 'connectivity.js'
|
||||
// );
|
||||
|
||||
// const tester = require(connectivityFile);
|
||||
const tester = require(`${
|
||||
configuration.connection.connector
|
||||
}/lib/utils/connectivity.js`);
|
||||
return tester({ scope, connection: configuration.connection });
|
||||
}
|
||||
|
||||
async function createProject(scope, { client, connection, dependencies }) {
|
||||
try {
|
||||
const { rootPath } = scope;
|
||||
const resources = join(__dirname, 'resources');
|
||||
|
||||
// copy files
|
||||
await fse.copy(join(resources, 'files'), rootPath);
|
||||
|
||||
// copy templates
|
||||
await fse.writeJSON(
|
||||
join(rootPath, 'package.json'),
|
||||
packageJSON({
|
||||
strapiDependencies: scope.strapiDependencies,
|
||||
additionalsDependencies: dependencies,
|
||||
strapiVersion: scope.strapiVersion,
|
||||
projectName: scope.name,
|
||||
uuid: scope.uuid,
|
||||
}),
|
||||
{
|
||||
spaces: 2,
|
||||
}
|
||||
);
|
||||
|
||||
// ensure node_modules is created
|
||||
await fse.ensureDir(join(rootPath, 'node_modules'));
|
||||
|
||||
await Promise.all(
|
||||
['development', 'staging', 'production'].map(env => {
|
||||
return fse.writeJSON(
|
||||
join(rootPath, `config/environments/${env}/database.json`),
|
||||
databaseJSON({
|
||||
connection,
|
||||
env,
|
||||
}),
|
||||
{ spaces: 2 }
|
||||
);
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
await fse.remove(scope.rootPath);
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
await runInstall(scope);
|
||||
} catch (error) {
|
||||
await trackUsage({
|
||||
event: 'didNotInstallProjectDependencies',
|
||||
scope,
|
||||
error,
|
||||
return generateNew(scope).catch(error => {
|
||||
console.error(error);
|
||||
return trackError({ scope, error }).then(() => {
|
||||
process.exit(1);
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
await trackUsage({ event: 'didCreateProject', scope });
|
||||
}
|
||||
|
||||
async function createQuickStartProject(scope) {
|
||||
await trackUsage({ event: 'didChooseQuickstart', scope });
|
||||
|
||||
// get default sqlite config
|
||||
const client = 'sqlite';
|
||||
const configuration = {
|
||||
client,
|
||||
connection: defaultConfigs[client],
|
||||
dependencies: clientDependencies({ scope, client: client }),
|
||||
};
|
||||
|
||||
await createProject(scope, configuration);
|
||||
|
||||
await execa('npm', ['run', 'develop'], {
|
||||
stdio: 'inherit',
|
||||
cwd: scope.rootPath,
|
||||
env: {
|
||||
FORCE_COLOR: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function hasYarn() {
|
||||
try {
|
||||
const { code } = execa.shellSync('yarnpkg --version');
|
||||
if (code === 0) return true;
|
||||
return false;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function askShouldUseQuickstart() {
|
||||
const answer = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: 'Choose your installation type',
|
||||
choices: [
|
||||
{
|
||||
name: 'Quickstart (recommended)',
|
||||
value: 'quick',
|
||||
},
|
||||
{
|
||||
name: 'Custom (manual settings)',
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
return answer.type === 'quick';
|
||||
}
|
||||
|
||||
const SETTINGS_FIELDS = [
|
||||
'database',
|
||||
'host',
|
||||
'srv',
|
||||
'port',
|
||||
'username',
|
||||
'password',
|
||||
'filename',
|
||||
];
|
||||
|
||||
const OPTIONS_FIELDS = ['authenticationDatabase'];
|
||||
|
||||
async function askDatabaseInfos(scope) {
|
||||
const { client } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'client',
|
||||
message: 'Choose your default database client',
|
||||
choices: ['sqlite', 'postgres', 'mysql', 'mongo'],
|
||||
default: 'sqlite',
|
||||
},
|
||||
]);
|
||||
|
||||
const responses = await inquirer.prompt(
|
||||
dbQuestions[client].map(q => q({ scope, client }))
|
||||
);
|
||||
|
||||
const connection = merge({}, defaultConfigs[client] || {}, {
|
||||
settings: pick(responses, SETTINGS_FIELDS),
|
||||
options: pick(responses, OPTIONS_FIELDS),
|
||||
});
|
||||
|
||||
if (responses.ssl === true) {
|
||||
if (client === 'mongo') {
|
||||
connection.options.ssl = true;
|
||||
} else {
|
||||
connection.settings.ssl = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
client,
|
||||
connection,
|
||||
};
|
||||
}
|
||||
|
||||
async function installDatabaseTestingDep({ scope, configuration }) {
|
||||
let packageCmd = scope.hasYarn
|
||||
? `yarnpkg --cwd ${scope.tmpPath} add`
|
||||
: `npm install --prefix ${scope.tmpPath}`;
|
||||
|
||||
// Manually create the temp directory for yarn
|
||||
if (scope.hasYarn) {
|
||||
await fse.ensureDir(scope.tmpPath);
|
||||
}
|
||||
|
||||
const depArgs = Object.keys(configuration.dependencies).map(dep => {
|
||||
return `${dep}@${configuration.dependencies[dep]}`;
|
||||
});
|
||||
|
||||
const cmd = `${packageCmd} ${depArgs.join(' ')}`;
|
||||
await execa.shell(cmd);
|
||||
}
|
||||
};
|
||||
|
||||
const dbArguments = [
|
||||
'dbclient',
|
||||
@ -513,17 +128,20 @@ function initCancelCatcher(scope) {
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log('Cancelling...');
|
||||
process.exit();
|
||||
// trackUsage({ event: 'didStopCreateProject', scope }).then(() => {
|
||||
// });
|
||||
console.log('Cancelling');
|
||||
|
||||
trackUsage({ event: 'didStopCreateProject', scope }).then(() => {
|
||||
process.exit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const installArguments = ['install', '--production', '--no-optional'];
|
||||
function runInstall({ rootPath, hasYarn }) {
|
||||
if (hasYarn) {
|
||||
return execa('yarnpkg', installArguments, { cwd: rootPath });
|
||||
function hasYarn() {
|
||||
try {
|
||||
const { code } = execa.shellSync('yarnpkg --version');
|
||||
if (code === 0) return true;
|
||||
return false;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
return execa('npm', installArguments, { cwd: rootPath });
|
||||
}
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Node.js core.
|
||||
const os = require('os');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
module.exports = function recordUsage(event, scope, error) {
|
||||
return fetch('https://analytics.strapi.io/track', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
event,
|
||||
uuid: scope.uuid,
|
||||
deviceId: scope.deviceId,
|
||||
properties: {
|
||||
error: typeof error == 'string' ? error : error && error.message,
|
||||
os: os.type(),
|
||||
version: scope.strapiPackageJSON.version,
|
||||
},
|
||||
}),
|
||||
timeout: 1000,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}).catch(() => {});
|
||||
|
||||
// request
|
||||
// .post('https://analytics.strapi.io/track')
|
||||
// .form({
|
||||
// event,
|
||||
// uuid: scope.uuid,
|
||||
// deviceId: machineIdSync(),
|
||||
// properties: {
|
||||
// error,
|
||||
// os: os.type()
|
||||
// }
|
||||
// })
|
||||
// .on('error', () => {});
|
||||
};
|
||||
@ -1,44 +0,0 @@
|
||||
'use strict';
|
||||
const os = require('os');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
function trackEvent(event, body) {
|
||||
return fetch('https://analytics.strapi.io/track', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
event,
|
||||
...body,
|
||||
}),
|
||||
timeout: 1000,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function trackError({ scope, error }) {
|
||||
return trackEvent('didNotCreateProject', {
|
||||
uuid: scope.uuid,
|
||||
deviceId: scope.deviceId,
|
||||
properties: {
|
||||
error: typeof error == 'string' ? error : error && error.message,
|
||||
os: os.type(),
|
||||
version: scope.strapiVersion,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function trackUsage({ event, scope, error }) {
|
||||
return trackEvent(event, {
|
||||
uuid: scope.uuid,
|
||||
deviceId: scope.deviceId,
|
||||
properties: {
|
||||
error: typeof error == 'string' ? error : error && error.message,
|
||||
os: os.type(),
|
||||
version: scope.strapiVersion,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
trackError,
|
||||
trackUsage,
|
||||
};
|
||||
6
packages/strapi-generate-new/lib/utils/stop-process.js
Normal file
6
packages/strapi-generate-new/lib/utils/stop-process.js
Normal file
@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function stopProcess(message) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
};
|
||||
60
packages/strapi-generate-new/lib/utils/usage.js
Normal file
60
packages/strapi-generate-new/lib/utils/usage.js
Normal file
@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
const os = require('os');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
function trackEvent(event, body) {
|
||||
try {
|
||||
return fetch('https://analytics.strapi.io/track', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
event,
|
||||
...body,
|
||||
}),
|
||||
timeout: 1000,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}).catch(() => {});
|
||||
} catch (err) {
|
||||
/** ignore errors*/
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function trackError({ scope, error }) {
|
||||
try {
|
||||
return trackEvent('didNotCreateProject', {
|
||||
uuid: scope.uuid,
|
||||
deviceId: scope.deviceId,
|
||||
properties: {
|
||||
error: typeof error == 'string' ? error : error && error.message,
|
||||
os: os.type(),
|
||||
version: scope.strapiVersion,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
/** ignore errors*/
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function trackUsage({ event, scope, error }) {
|
||||
try {
|
||||
return trackEvent(event, {
|
||||
uuid: scope.uuid,
|
||||
deviceId: scope.deviceId,
|
||||
properties: {
|
||||
error: typeof error == 'string' ? error : error && error.message,
|
||||
os: os.type(),
|
||||
version: scope.strapiVersion,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
/** ignore errors*/
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
trackError,
|
||||
trackUsage,
|
||||
};
|
||||
@ -1,13 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
// Public node modules
|
||||
const rimraf = require('rimraf');
|
||||
|
||||
module.exports = (scope, success, error) => {
|
||||
module.exports = async ({ connection }) => {
|
||||
const Mongoose = require('mongoose');
|
||||
|
||||
const { username, password, srv } = scope.database.settings;
|
||||
const { authenticationDatabase, ssl } = scope.database.options;
|
||||
const { username, password, srv } = connection.settings;
|
||||
const { authenticationDatabase, ssl } = connection.options;
|
||||
|
||||
const connectOptions = {};
|
||||
|
||||
@ -25,27 +22,20 @@ module.exports = (scope, success, error) => {
|
||||
|
||||
connectOptions.ssl = ssl ? true : false;
|
||||
connectOptions.useNewUrlParser = true;
|
||||
connectOptions.dbName = scope.database.settings.database;
|
||||
connectOptions.dbName = connection.settings.database;
|
||||
|
||||
Mongoose.connect(`mongodb${srv ? '+srv' : ''}://${scope.database.settings.host}${!srv ? `:${scope.database.settings.port}` : ''}/`, connectOptions, function (err) {
|
||||
if (err) {
|
||||
console.log('⚠️ Database connection has failed! Make sure your database is running.');
|
||||
|
||||
if (scope.debug) {
|
||||
console.log('🐛 Full error log:');
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
return error();
|
||||
return Mongoose.connect(
|
||||
`mongodb${srv ? '+srv' : ''}://${connection.settings.host}${
|
||||
!srv ? `:${connection.settings.port}` : ''
|
||||
}/`,
|
||||
connectOptions
|
||||
).then(
|
||||
() => {
|
||||
Mongoose.connection.close();
|
||||
},
|
||||
error => {
|
||||
Mongoose.connection.close();
|
||||
throw error;
|
||||
}
|
||||
|
||||
Mongoose.connection.close();
|
||||
|
||||
rimraf(scope.tmpPath, (err) => {
|
||||
if (err) {
|
||||
console.log(`Error removing connection test folder: ${scope.tmpPath}`);
|
||||
}
|
||||
success();
|
||||
});
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
"mongoose": "^5.5.9",
|
||||
"mongoose-float": "^1.0.4",
|
||||
"pluralize": "^7.0.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"strapi-utils": "3.0.0-beta.6"
|
||||
},
|
||||
"author": {
|
||||
|
||||
@ -79,7 +79,7 @@ program
|
||||
|
||||
// `$ strapi new`
|
||||
program
|
||||
.command('new [name]')
|
||||
.command('new <directory>')
|
||||
.option('--debug', 'Display database connection error')
|
||||
.option('--quickstart', 'Quickstart app creation')
|
||||
.option('--dbclient <dbclient>', 'Database client')
|
||||
|
||||
@ -9,8 +9,5 @@
|
||||
*/
|
||||
|
||||
module.exports = function(...args) {
|
||||
return require('strapi-generate-new')(...args).catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
return require('strapi-generate-new')(...args);
|
||||
};
|
||||
|
||||
@ -10662,7 +10662,7 @@ listr@0.12.0:
|
||||
stream-to-observable "^0.1.0"
|
||||
strip-ansi "^3.0.1"
|
||||
|
||||
listr@^0.14.2, listr@^0.14.3:
|
||||
listr@^0.14.2:
|
||||
version "0.14.3"
|
||||
resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586"
|
||||
integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user