UNPKG

4.51 kBJavaScriptView Raw
1'use strict';
2
3const { join } = require('path');
4const fse = require('fs-extra');
5const inquirer = require('inquirer');
6const execa = require('execa');
7const { merge, pick } = require('lodash');
8
9const stopProcess = require('./utils/stop-process');
10const { trackUsage } = require('./utils/usage');
11const defaultConfigs = require('./utils/db-configs');
12const clientDependencies = require('./utils/db-client-dependencies');
13const dbQuestions = require('./utils/db-questions');
14const createProject = require('./create-project');
15
16module.exports = async scope => {
17 await trackUsage({ event: 'didChooseCustomDatabase', scope });
18
19 const configuration = await askDbInfosAndTest(scope).catch(error => {
20 return trackUsage({ event: 'didNotConnectDatabase', scope, error }).then(
21 () => {
22 throw error;
23 }
24 );
25 });
26
27 console.log();
28 console.log('Creating a project with custom database options.');
29 await trackUsage({ event: 'didConnectDatabase', scope });
30 return createProject(scope, configuration);
31};
32
33const MAX_RETRIES = 5;
34async function askDbInfosAndTest(scope) {
35 let retries = 0;
36
37 async function loop() {
38 // else ask for the client name
39 const { client, connection } = await askDatabaseInfos(scope);
40
41 const configuration = {
42 client,
43 connection,
44 dependencies: clientDependencies({ scope, client }),
45 };
46
47 return testDatabaseConnection({
48 scope,
49 configuration,
50 })
51 .then(result => {
52 if (
53 result &&
54 result.shouldRetry === true &&
55 retries < MAX_RETRIES - 1
56 ) {
57 console.log('Retrying...');
58 retries++;
59 return loop();
60 }
61 })
62 .then(
63 () => fse.remove(scope.tmpPath),
64 err => {
65 return fse.remove(scope.tmpPath).then(() => {
66 throw err;
67 });
68 }
69 )
70 .then(() => configuration)
71 .catch(err => {
72 if (retries < MAX_RETRIES - 1) {
73 console.log();
74 console.log(`⛔️ Connection test failed: ${err.message}`);
75 console.log();
76
77 if (scope.debug) {
78 console.log('Full error log:');
79 console.log(err);
80 }
81
82 console.log('Retrying...');
83 retries++;
84 return loop();
85 }
86
87 console.log(err);
88 stopProcess(
89 `️⛔️ Could not connect to your database after ${MAX_RETRIES} tries. Try to check your database configuration an retry.`
90 );
91 });
92 }
93
94 return loop();
95}
96
97async function testDatabaseConnection({ scope, configuration }) {
98 const { client } = configuration;
99
100 if (client === 'sqlite') return;
101
102 await installDatabaseTestingDep({
103 scope,
104 configuration,
105 });
106
107 const connectivityFile = join(
108 scope.tmpPath,
109 'node_modules',
110 `strapi-connector-${configuration.connection.connector}`,
111 'lib',
112 'utils',
113 'connectivity.js'
114 );
115
116 const tester = require(connectivityFile);
117 return tester({ scope, connection: configuration.connection });
118}
119
120const SETTINGS_FIELDS = [
121 'database',
122 'host',
123 'srv',
124 'port',
125 'username',
126 'password',
127 'filename',
128];
129
130const OPTIONS_FIELDS = ['authenticationDatabase'];
131
132async function askDatabaseInfos(scope) {
133 const { client } = await inquirer.prompt([
134 {
135 type: 'list',
136 name: 'client',
137 message: 'Choose your default database client',
138 choices: ['sqlite', 'postgres', 'mysql', 'mongo'],
139 default: 'sqlite',
140 },
141 ]);
142
143 const responses = await inquirer.prompt(
144 dbQuestions[client].map(q => q({ scope, client }))
145 );
146
147 const connection = merge({}, defaultConfigs[client] || {}, {
148 settings: pick(responses, SETTINGS_FIELDS),
149 options: pick(responses, OPTIONS_FIELDS),
150 });
151
152 if (responses.ssl === true) {
153 if (client === 'mongo') {
154 connection.options.ssl = true;
155 } else {
156 connection.settings.ssl = true;
157 }
158 }
159
160 return {
161 client,
162 connection,
163 };
164}
165
166async function installDatabaseTestingDep({ scope, configuration }) {
167 let packageManager = scope.useYarn ? 'yarnpkg' : 'npm';
168 let cmd = scope.useYarn
169 ? ['--cwd', scope.tmpPath, 'add']
170 : ['install', '--prefix', scope.tmpPath];
171
172 // Manually create the temp directory for yarn
173 if (scope.useYarn) {
174 await fse.ensureDir(scope.tmpPath);
175 }
176
177 const deps = Object.keys(configuration.dependencies).map(dep => {
178 return `${dep}@${configuration.dependencies[dep]}`;
179 });
180
181 await execa(packageManager, cmd.concat(deps));
182}