@scandipwa/magento-scripts 2.0.0-alpha.0 → 2.0.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/exec.js +71 -0
  2. package/index.js +1 -1
  3. package/lib/commands/cli.js +7 -2
  4. package/lib/commands/execute.js +3 -58
  5. package/lib/commands/import-db.js +1 -1
  6. package/lib/commands/logs.js +1 -1
  7. package/lib/commands/start.js +18 -8
  8. package/lib/commands/status.js +9 -1
  9. package/lib/config/config.js +20 -2
  10. package/lib/config/docker.js +79 -85
  11. package/lib/config/index.js +2 -2
  12. package/lib/config/php/versions/php-7.2.js +1 -0
  13. package/lib/config/php/versions/php-7.3.js +1 -0
  14. package/lib/config/php/versions/php-7.4.js +1 -0
  15. package/lib/config/php/versions/php-8.1.js +1 -0
  16. package/lib/config/php-config.js +4 -3
  17. package/lib/config/port-config.js +1 -1
  18. package/lib/config/services/composer/versions/composer-1.js +8 -0
  19. package/lib/config/services/composer/versions/composer-2.js +8 -0
  20. package/lib/config/services/composer/versions/index.js +4 -0
  21. package/lib/config/services/elasticsearch/base-repo.js +3 -0
  22. package/lib/config/services/elasticsearch/default-es-env.js +6 -0
  23. package/lib/config/services/elasticsearch/versions/elasticsearch-6.8.js +19 -0
  24. package/lib/config/services/elasticsearch/versions/index.js +5 -0
  25. package/lib/config/services/nginx/versions/index.js +3 -0
  26. package/lib/config/services/nginx/versions/nginx-1.18.js +11 -0
  27. package/lib/config/{ssl-terminator → services/ssl-terminator}/index.js +3 -0
  28. package/lib/config/templates/magentorc.template +6 -5
  29. package/lib/config/templates/mariadb.template.cnf +191 -0
  30. package/lib/config/templates/php-debug.template.ini +31 -0
  31. package/lib/config/templates/php-fpm.template.conf +1 -2
  32. package/lib/config/templates/php.template.ini +6 -202
  33. package/lib/config/templates/ssl-terminator.template.conf +10 -3
  34. package/lib/config/templates/varnish.template.vcl +20 -13
  35. package/lib/config/varnish/varnish-6-0.js +4 -0
  36. package/lib/config/varnish/varnish-6-6.js +4 -0
  37. package/lib/config/varnish/varnish-7-0.js +4 -0
  38. package/lib/config/versions/magento-2.3.0.js +7 -12
  39. package/lib/config/versions/magento-2.3.1.js +7 -12
  40. package/lib/config/versions/magento-2.3.2-p1.js +7 -12
  41. package/lib/config/versions/magento-2.3.2-p2.js +7 -12
  42. package/lib/config/versions/magento-2.3.2.js +7 -12
  43. package/lib/config/versions/magento-2.3.3-p1.js +7 -12
  44. package/lib/config/versions/magento-2.3.3.js +7 -12
  45. package/lib/config/versions/magento-2.3.4-p1.js +7 -12
  46. package/lib/config/versions/magento-2.3.4-p2.js +7 -12
  47. package/lib/config/versions/magento-2.3.4.js +7 -12
  48. package/lib/config/versions/magento-2.3.5-p1.js +5 -9
  49. package/lib/config/versions/magento-2.3.5-p2.js +5 -9
  50. package/lib/config/versions/magento-2.3.5.js +5 -9
  51. package/lib/config/versions/magento-2.3.6-p1.js +5 -9
  52. package/lib/config/versions/magento-2.3.6.js +5 -9
  53. package/lib/config/versions/magento-2.3.7-p1.js +5 -9
  54. package/lib/config/versions/magento-2.3.7-p2.js +5 -9
  55. package/lib/config/versions/magento-2.3.7-p3.js +5 -9
  56. package/lib/config/versions/magento-2.3.7-p4.js +40 -0
  57. package/lib/config/versions/magento-2.3.7.js +5 -9
  58. package/lib/config/versions/magento-2.4.0-p1.js +5 -9
  59. package/lib/config/versions/magento-2.4.0.js +5 -9
  60. package/lib/config/versions/magento-2.4.1-p1.js +5 -9
  61. package/lib/config/versions/magento-2.4.1.js +5 -9
  62. package/lib/config/versions/magento-2.4.2-p1.js +5 -9
  63. package/lib/config/versions/magento-2.4.2-p2.js +5 -9
  64. package/lib/config/versions/magento-2.4.2.js +5 -9
  65. package/lib/config/versions/magento-2.4.3-p1.js +5 -9
  66. package/lib/config/versions/magento-2.4.3-p2.js +5 -9
  67. package/lib/config/versions/magento-2.4.3-p3.js +42 -0
  68. package/lib/config/versions/magento-2.4.3.js +5 -9
  69. package/lib/config/versions/magento-2.4.4-p1.js +42 -0
  70. package/lib/config/versions/magento-2.4.4.js +5 -9
  71. package/lib/config/versions/magento-2.4.5.js +42 -0
  72. package/lib/tasks/cleanup.js +1 -1
  73. package/lib/tasks/composer/local-auth-json.js +1 -1
  74. package/lib/tasks/database/connect-to-database.js +120 -0
  75. package/lib/tasks/database/create-magento-database.js +21 -0
  76. package/lib/tasks/database/create-magento-user.js +50 -0
  77. package/lib/tasks/database/default-magento-database.js +3 -0
  78. package/lib/tasks/database/default-magento-user.js +7 -0
  79. package/lib/tasks/{mysql → database}/dump-theme-config.js +3 -3
  80. package/lib/tasks/{mysql → database}/fix-db.js +2 -2
  81. package/lib/tasks/{mysql/import-dump-to-mysql.js → database/import-dump-to-database.js} +21 -20
  82. package/lib/tasks/{mysql → database}/import-remote-db/index.js +0 -0
  83. package/lib/tasks/{mysql/import-remote-db/ssh/mysqldump-command.js → database/import-remote-db/ssh/database-dump-command.js} +2 -2
  84. package/lib/tasks/{mysql → database}/import-remote-db/ssh/index.js +0 -0
  85. package/lib/tasks/{mysql → database}/import-remote-db/ssh/readymage.js +4 -4
  86. package/lib/tasks/{mysql → database}/import-remote-db/ssh/regular-server.js +2 -2
  87. package/lib/tasks/{mysql → database}/index.js +2 -2
  88. package/lib/tasks/{mysql → database}/magento-tables.js +0 -0
  89. package/lib/tasks/{mysql → database}/restore-theme-config.js +4 -4
  90. package/lib/tasks/docker/api.d.ts +25 -1
  91. package/lib/tasks/docker/api.js +31 -1
  92. package/lib/tasks/docker/containers/container-api.d.ts +18 -0
  93. package/lib/tasks/docker/containers/container-api.js +76 -17
  94. package/lib/tasks/docker/containers/tasks.js +32 -1
  95. package/lib/tasks/docker/convert-legacy-volumes.js +8 -7
  96. package/lib/tasks/docker/convert-mysql-to-mariadb.js +284 -0
  97. package/lib/tasks/docker/index.js +6 -1
  98. package/lib/tasks/docker/network/network-api.d.ts +1 -1
  99. package/lib/tasks/docker/project-image-builder.js +7 -9
  100. package/lib/tasks/docker/volume/index.js +9 -0
  101. package/lib/tasks/docker/volume/tasks.js +94 -0
  102. package/lib/tasks/docker/volume/volume-api.d.ts +49 -0
  103. package/lib/tasks/docker/volume/volume-api.js +90 -0
  104. package/lib/tasks/execute.js +100 -0
  105. package/lib/tasks/file-system/create-mariadb-config.js +23 -0
  106. package/lib/tasks/file-system/create-nginx-config.js +3 -5
  107. package/lib/tasks/file-system/create-php-config.js +2 -23
  108. package/lib/tasks/file-system/create-php-debug-config.js +45 -0
  109. package/lib/tasks/file-system/create-php-fpm-config.js +2 -4
  110. package/lib/tasks/file-system/create-phpstorm-config/workspace-config/php-workspace-project-configuration-config.js +1 -1
  111. package/lib/tasks/file-system/create-ssl-terminator-config.js +4 -7
  112. package/lib/tasks/file-system/create-varnish-config.js +4 -7
  113. package/lib/tasks/file-system/index.js +5 -1
  114. package/lib/tasks/import-dump.js +6 -6
  115. package/lib/tasks/link.js +4 -2
  116. package/lib/tasks/magento/enable-magento-composer-plugins.js +85 -30
  117. package/lib/tasks/magento/install-magento-project.js +3 -2
  118. package/lib/tasks/magento/setup-magento/configure-elasticsearch.js +3 -5
  119. package/lib/tasks/magento/setup-magento/create-admin.js +1 -1
  120. package/lib/tasks/magento/setup-magento/delete-admin-users.js +2 -2
  121. package/lib/tasks/magento/setup-magento/delete-customers.js +4 -4
  122. package/lib/tasks/magento/setup-magento/delete-orders.js +4 -4
  123. package/lib/tasks/magento/setup-magento/flush-redis-config.js +3 -6
  124. package/lib/tasks/magento/setup-magento/increase-admin-session-lifetime.js +2 -2
  125. package/lib/tasks/magento/setup-magento/index.js +2 -0
  126. package/lib/tasks/magento/setup-magento/install-magento.js +15 -17
  127. package/lib/tasks/magento/setup-magento/migrate-database.js +5 -11
  128. package/lib/tasks/magento/setup-magento/set-base-url.js +3 -3
  129. package/lib/tasks/magento/setup-magento/set-url-rewrite.js +2 -2
  130. package/lib/tasks/magento/setup-magento/varnish-config.js +8 -13
  131. package/lib/tasks/magento/setup-magento/waiting-for-varnish.js +17 -16
  132. package/lib/tasks/php/php-container.js +7 -3
  133. package/lib/tasks/php/update-env-php.js +7 -6
  134. package/lib/tasks/php/update-env.php +12 -12
  135. package/lib/tasks/requirements/composer-credentials.js +7 -3
  136. package/lib/tasks/requirements/docker/context.js +88 -0
  137. package/lib/tasks/requirements/docker/index.js +110 -19
  138. package/lib/tasks/requirements/docker/install.js +21 -7
  139. package/lib/tasks/requirements/docker/permissions.js +2 -11
  140. package/lib/tasks/requirements/docker/running-status.js +94 -24
  141. package/lib/tasks/requirements/docker/version.js +1 -0
  142. package/lib/tasks/requirements/index.js +0 -2
  143. package/lib/tasks/requirements/php-version.js +4 -2
  144. package/lib/tasks/start.js +32 -31
  145. package/lib/tasks/status/index.js +17 -13
  146. package/lib/tasks/stop.js +2 -0
  147. package/lib/tasks/theme/link-theme.js +2 -2
  148. package/lib/util/config-file-validator.js +29 -13
  149. package/lib/util/database.js +7 -7
  150. package/lib/util/execute-in-container.js +63 -0
  151. package/lib/util/prefix.js +1 -1
  152. package/lib/util/systemctl.js +62 -13
  153. package/package.json +4 -3
  154. package/typings/context.d.ts +12 -5
  155. package/typings/index.d.ts +69 -31
  156. package/lib/tasks/docker/volumes.js +0 -63
  157. package/lib/tasks/execute/index.js +0 -23
  158. package/lib/tasks/mysql/connect-to-mysql.js +0 -127
  159. package/lib/tasks/mysql/create-magento-database.js +0 -18
  160. package/lib/tasks/requirements/dependency/arch.js +0 -50
  161. package/lib/tasks/requirements/dependency/centos.js +0 -36
  162. package/lib/tasks/requirements/dependency/fedora.js +0 -36
  163. package/lib/tasks/requirements/dependency/index.js +0 -33
  164. package/lib/tasks/requirements/dependency/mac.js +0 -124
  165. package/lib/tasks/requirements/dependency/ubuntu.js +0 -83
@@ -3,9 +3,9 @@ const { execAsyncSpawn } = require('../../../util/exec-async-command');
3
3
 
4
4
  /**
5
5
  * @param {import('./container-api').ContainerRunOptions} options
6
- * @param {import('../../../util/exec-async-command').ExecAsyncSpawnOptions<false>} execOptions
6
+ * @returns {string[]}
7
7
  */
8
- const run = (options, execOptions = {}) => {
8
+ const runCommand = (options) => {
9
9
  const {
10
10
  addHost,
11
11
  ports = [],
@@ -24,32 +24,35 @@ const run = (options, execOptions = {}) => {
24
24
  expose = [],
25
25
  detach = true,
26
26
  rm = false,
27
+ tty = false,
27
28
  user
28
29
  } = options;
29
30
 
30
31
  const detachArg = detach && '-d';
31
32
  const rmArg = rm && '--rm';
33
+ const ttyArg = tty && '-it';
32
34
  const exposeArg = expose && expose.map((e) => `--expose=${ e }`);
33
- const restartArg = !rm && restart && `--restart ${ restart }`;
34
- const networkArg = network && `--network ${ network }`;
35
- const portsArgs = ports.map((port) => `-p ${ port }`).join(' ');
36
- const mountsArgs = mounts.map((mount) => `--mount ${ mount }`).join(' ');
37
- const mountVolumesArgs = mountVolumes.map((mount) => `-v ${mount}`).join(' ');
38
- const envArgs = !env ? '' : Object.entries(env).map(([key, value]) => `--env ${ key }='${ value }'`).join(' ');
39
- const nameArg = name && `--name ${name}`;
40
- const entrypointArg = entrypoint && `--entrypoint "${entrypoint}"`;
41
- const healthCheckArg = healthCheck && Object.entries(healthCheck).map(([key, value]) => `--health-${key} '${value}'`).join(' ');
42
- const securityArg = securityOptions.length > 0 && securityOptions.map((opt) => `--security-opt ${opt}`).join(' ');
43
- const tmpfsArg = tmpfs.length > 0 && tmpfs.map((t) => `--tmpfs ${t}`).join(' ');
35
+ const restartArg = !rm && restart && `--restart=${ restart }`;
36
+ const networkArg = network && `--network=${ network }`;
37
+ const portsArgs = ports && ports.length > 0 && ports.map((port) => `-p=${ port }`).join(' ');
38
+ const mountsArgs = mounts && mounts.map((mount) => `--mount=${ mount }`).join(' ');
39
+ const mountVolumesArgs = mountVolumes && mountVolumes.map((mount) => `-v=${mount}`).join(' ');
40
+ const envArgs = !env ? '' : Object.entries(env).map(([key, value]) => `--env=${ key }='${ value }'`).join(' ');
41
+ const nameArg = name && `--name=${name}`;
42
+ const entrypointArg = entrypoint && `--entrypoint="${entrypoint}"`;
43
+ const healthCheckArg = healthCheck && Object.entries(healthCheck).map(([key, value]) => `--health-${key}='${value}'`).join(' ');
44
+ const securityArg = securityOptions.length > 0 && securityOptions.map((opt) => `--security-opt=${opt}`).join(' ');
45
+ const tmpfsArg = tmpfs.length > 0 && tmpfs.map((t) => `--tmpfs=${t}`).join(' ');
44
46
  const userArg = user && `--user=${user}`;
45
47
  const addHostArg = addHost && `--add-host=${addHost}`;
46
48
 
47
49
  const dockerCommand = [
48
50
  'docker',
49
51
  'run',
52
+ nameArg,
53
+ ttyArg,
50
54
  detachArg,
51
55
  rmArg,
52
- nameArg,
53
56
  networkArg,
54
57
  restartArg,
55
58
  portsArgs,
@@ -65,11 +68,17 @@ const run = (options, execOptions = {}) => {
65
68
  addHostArg,
66
69
  image,
67
70
  command
68
- ].filter(Boolean).join(' ');
71
+ ].filter(Boolean).filter((arg) => typeof arg === 'string');
69
72
 
70
- return execAsyncSpawn(dockerCommand, execOptions);
73
+ return dockerCommand;
71
74
  };
72
75
 
76
+ /**
77
+ * @param {import('./container-api').ContainerRunOptions} options
78
+ * @param {import('../../../util/exec-async-command').ExecAsyncSpawnOptions<false>} execOptions
79
+ */
80
+ const run = (options, execOptions = {}) => execAsyncSpawn(runCommand(options).join(' '), execOptions);
81
+
73
82
  /**
74
83
  * @param {string} command
75
84
  * @param {string} container container id or name
@@ -140,14 +149,64 @@ const ls = async (options = {}, execOptions = {}) => {
140
149
 
141
150
  if (formatToJSON) {
142
151
  const result = await execAsyncSpawn(`docker container ls ${args}`, execOptions);
152
+ if (result.startsWith('[')) {
153
+ return JSON.parse(result);
154
+ }
155
+
143
156
  return JSON.parse(`[${result.split('\n').join(', ')}]`);
144
157
  }
145
158
 
146
159
  return execAsyncSpawn(`docker container ls ${args}`, execOptions);
147
160
  };
148
161
 
162
+ /**
163
+ * @param {import('./container-api').ContainerLogsOptions} options
164
+ * @param {import('../../../util/exec-async-command').ExecAsyncSpawnOptions<false>} execOptions
165
+ */
166
+ const logs = async (options = {}, execOptions = {}) => {
167
+ const {
168
+ name,
169
+ details = false,
170
+ follow = false,
171
+ since = '',
172
+ tail = '',
173
+ timestamps = false,
174
+ until = '',
175
+ parser
176
+ } = options;
177
+ const detailsArg = details && '--details';
178
+ const followArg = follow && '--follow';
179
+ const sinceArg = since && `--since=${since}`;
180
+ const tailArg = tail && `--tail=${tail}`;
181
+ const timestampsArg = timestamps && '--timestamps';
182
+ const untilArg = until && `--until=${until}`;
183
+
184
+ const logsCommand = [
185
+ 'docker',
186
+ 'container',
187
+ 'logs',
188
+ detailsArg,
189
+ followArg,
190
+ sinceArg,
191
+ tailArg,
192
+ timestampsArg,
193
+ untilArg,
194
+ name
195
+ ].filter(Boolean).join(' ');
196
+
197
+ if (parser) {
198
+ const result = await execAsyncSpawn(logsCommand, execOptions);
199
+
200
+ return result.split('\n').map((line) => parser(line));
201
+ }
202
+
203
+ return execAsyncSpawn(logsCommand, execOptions);
204
+ };
205
+
149
206
  module.exports = {
150
207
  run,
208
+ runCommand,
151
209
  exec,
152
- ls
210
+ ls,
211
+ logs
153
212
  };
@@ -26,8 +26,39 @@ const remoteImageReducer = (acc, val) => {
26
26
  */
27
27
  const pullImages = () => ({
28
28
  title: 'Pulling container images',
29
- task: async ({ config: { docker } }, task) => {
29
+ task: async ({ config: { docker }, pullImages }, task) => {
30
30
  const containers = Object.values(docker.getContainers());
31
+
32
+ if (pullImages) {
33
+ return task.newListr(
34
+ containers
35
+ .reduce(remoteImageReducer, [])
36
+ .map((image) => {
37
+ const [repo, tag = 'latest'] = image.split(':');
38
+
39
+ return { repo, tag };
40
+ })
41
+ .reduce(
42
+ (acc, val) => acc.concat(
43
+ acc.some(
44
+ (c) => c.repo === val.repo
45
+ && c.tag === val.tag
46
+ )
47
+ ? []
48
+ : val
49
+ ),
50
+ []
51
+ )
52
+ .map(({ repo, tag }) => ({
53
+ title: `Pulling ${ logger.style.file(`${repo}:${tag}`) } image`,
54
+ task: () => pull(`${repo}:${tag}`)
55
+ })), {
56
+ concurrent: true,
57
+ exitOnError: true
58
+ }
59
+ );
60
+ }
61
+
31
62
  const imagesFilter = containers
32
63
  .reduce(remoteImageReducer, [])
33
64
  .map((image) => `reference='${image}'`);
@@ -1,10 +1,11 @@
1
+ /* eslint-disable no-param-reassign */
1
2
  /* eslint-disable max-len */
2
3
  const { stopServices } = require('./index');
3
4
  const { getBaseConfig, getConfigFromMagentoVersion } = require('../../config');
4
5
  const getDockerConfig = require('../../config/docker');
5
6
  const { execAsyncSpawn } = require('../../util/exec-async-command');
6
7
  const { folderName, legacyFolderName } = require('../../util/prefix');
7
- const { createVolume } = require('./volumes');
8
+ const { volumeApi } = require('./volume');
8
9
 
9
10
  /**
10
11
  * @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
@@ -14,20 +15,20 @@ const convertLegacyVolumes = () => ({
14
15
  const { config: { overridenConfiguration } } = ctx;
15
16
  const newDockerConfig = await getDockerConfig(ctx, overridenConfiguration, getBaseConfig(process.cwd(), folderName));
16
17
 
17
- const newVolumeNames = Object.values(newDockerConfig.volumes).filter((v) => !v.opts).map(({ name }) => name);
18
+ const newVolumeNames = Object.values(newDockerConfig.volumes).filter((v) => !v.opt).map(({ name }) => name);
18
19
 
19
- const existingVolumes = (await execAsyncSpawn('docker volume ls -q')).split('\n');
20
+ const existingVolumes = await volumeApi.ls({ formatToJSON: true });
20
21
 
21
22
  if (newVolumeNames.every((v) => existingVolumes.includes(v))) {
22
23
  return;
23
24
  }
24
25
 
25
26
  const legacyDockerConfig = await getDockerConfig(ctx, overridenConfiguration, getBaseConfig(process.cwd(), legacyFolderName));
26
- const legacyVolumeNames = Object.values(legacyDockerConfig.volumes).filter((v) => !v.opts).map(({ name }) => name);
27
+ const legacyVolumeNames = Object.values(legacyDockerConfig.volumes).filter((v) => !v.opt).map(({ name }) => name);
27
28
 
28
29
  if (
29
- newVolumeNames.every((name) => !existingVolumes.includes(name))
30
- && legacyVolumeNames.every((name) => existingVolumes.includes(name))
30
+ newVolumeNames.every((name) => !existingVolumes.some((v) => v.Name === name))
31
+ && legacyVolumeNames.every((name) => existingVolumes.some((v) => v.Name === name))
31
32
  ) {
32
33
  ctx.config = await getConfigFromMagentoVersion(ctx, {
33
34
  magentoVersion: ctx.magentoVersion,
@@ -46,7 +47,7 @@ const convertLegacyVolumes = () => ({
46
47
  const legacyVolumeConfig = legacyDockerConfig.volumes[volumeName];
47
48
 
48
49
  subTask.output = `Creating volume ${volumeConfig.name}...`;
49
- await createVolume(volumeConfig);
50
+ await volumeApi.create(volumeConfig);
50
51
  subTask.output = `Copying data from ${legacyVolumeConfig.name} to ${volumeConfig.name}...`;
51
52
  await execAsyncSpawn(
52
53
  `docker run --rm -v ${legacyVolumeConfig.name}:/from:ro -v ${volumeConfig.name}:/to alpine ash -c "cd /from; cp -av . /to"`, {
@@ -0,0 +1,284 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const logger = require('@scandipwa/scandipwa-dev-utils/logger');
4
+ const { volumeApi, createVolumes } = require('./volume');
5
+ const { execAsyncSpawn } = require('../../util/exec-async-command');
6
+ const { containerApi, stopContainers, pullImages } = require('./containers');
7
+ const { importDumpToDatabase, connectToDatabase } = require('../database');
8
+ const { setPrefix } = require('../prefix');
9
+ const getProjectConfiguration = require('../../config/get-project-configuration');
10
+ const { getAvailablePorts, getCachedPorts } = require('../../config/get-port-config');
11
+ const { saveConfiguration } = require('../../config/save-config');
12
+ const { buildProjectImage, buildDebugProjectImage } = require('./project-image-builder');
13
+ const checkPHPVersion = require('../requirements/php-version');
14
+ const { getComposerVersionTask } = require('../composer');
15
+ const { prepareFileSystem } = require('../file-system');
16
+ const { installMagentoProject } = require('../magento');
17
+ const enableMagentoComposerPlugins = require('../magento/enable-magento-composer-plugins');
18
+ const { startServices } = require('./index');
19
+ const dockerNetwork = require('./network');
20
+ const KnownError = require('../../errors/known-error');
21
+ const { createCacheFolder } = require('../cache');
22
+ const { getSystemConfigTask } = require('../../config/system-config');
23
+ const sleep = require('../../util/sleep');
24
+
25
+ /**
26
+ * @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
27
+ */
28
+ const convertMySQLDatabaseToMariaDB = () => ({
29
+ task: async (ctx, task) => {
30
+ const mysqlVolumeName = `${ ctx.config.baseConfig.prefix }_mysql-data`;
31
+ const volumes = await volumeApi.ls({ formatToJSON: true });
32
+ if (ctx.isArmMac) {
33
+ if (volumes.some(
34
+ (volume) => volume.Name === mysqlVolumeName
35
+ ) && !volumes.some(
36
+ (volume) => volume.Name === ctx.config.docker.volumes.mariadb.name
37
+ )
38
+ ) {
39
+ task.title = 'Converting MySQL database to MariaDB';
40
+ return task.newListr([
41
+ stopContainers(),
42
+ {
43
+ title: 'Converting MySQL volume to MariaDB',
44
+ task: async (subCtx, subTask) => {
45
+ subTask.output = `Creating volume ${subCtx.config.docker.volumes.mariadb.name}...`;
46
+ await volumeApi.create(subCtx.config.docker.volumes.mariadb);
47
+ subTask.output = `Copying data from ${mysqlVolumeName} to ${subCtx.config.docker.volumes.mariadb.name}...`;
48
+ await execAsyncSpawn(
49
+ // eslint-disable-next-line max-len
50
+ `docker run --rm -v ${mysqlVolumeName}:/from:ro -v ${subCtx.config.docker.volumes.mariadb.name}:/to alpine ash -c "cd /from; cp -av . /to"`, {
51
+ callback: (t) => {
52
+ subTask.output = t;
53
+ }
54
+ }
55
+ );
56
+ subTask.output = 'Deleting old volume...';
57
+ await execAsyncSpawn(`docker volume rm ${mysqlVolumeName}`);
58
+ },
59
+ options: {
60
+ bottomBar: 10
61
+ }
62
+ }
63
+ ]);
64
+ }
65
+
66
+ return;
67
+ }
68
+
69
+ if (volumes.some(
70
+ (volume) => volume.Name === mysqlVolumeName
71
+ ) && !volumes.some(
72
+ (volume) => volume.Name === ctx.config.docker.volumes.mariadb.name
73
+ )
74
+ ) {
75
+ task.title = 'Converting MySQL database to MariaDB';
76
+ const confirmConvert = await task.prompt({
77
+ type: 'Select',
78
+ message: `We see that you have old mysql-data volume in the project!
79
+ Since ${logger.style.code('magento-scripts@2.0.0')} ${logger.style.misc('MariaDB')} is used as database instead of MySQL.
80
+
81
+ To use MariaDB with data from MySQL we need to convert your database.
82
+ `,
83
+ choices: [
84
+ {
85
+ name: 'yes',
86
+ message: 'Okay, let\'s do that!'
87
+ },
88
+ {
89
+ name: 'no',
90
+ message: 'ABORT ABORT ABORT'
91
+ }
92
+ ]
93
+ });
94
+
95
+ if (confirmConvert === 'yes') {
96
+ const pathToMySQLDumpFile = path.join(process.cwd(), 'mysql-database.sql');
97
+ const containerName = 'mysql-database';
98
+ task.output = 'Creating dump file from MySQL database...';
99
+
100
+ const existingContainers = await containerApi.ls({ formatToJSON: true, all: true });
101
+
102
+ if (existingContainers.some((c) => c.Names === containerName)) {
103
+ await execAsyncSpawn(`docker container stop ${containerName}`);
104
+ await execAsyncSpawn(`docker container rm ${containerName}`);
105
+ }
106
+
107
+ task.output = 'Starting MySQL server...';
108
+
109
+ await containerApi.run(
110
+ {
111
+ mounts: [
112
+ `source=${ mysqlVolumeName },target=/var/lib/mysql`
113
+ ],
114
+ env: {
115
+ MYSQL_PORT: 3306,
116
+ MYSQL_ROOT_PASSWORD: 'scandipwa',
117
+ MYSQL_USER: 'magento',
118
+ MYSQL_PASSWORD: 'magento',
119
+ MYSQL_DATABASE: 'magento'
120
+ },
121
+ command: [
122
+ '--log_bin_trust_function_creators=1',
123
+ '--default-authentication-plugin=mysql_native_password',
124
+ '--max_allowed_packet=1GB',
125
+ '--bind-address=0.0.0.0'
126
+ ]
127
+ .join(' '),
128
+ securityOptions: [
129
+ 'seccomp=unconfined'
130
+ ],
131
+ name: containerName,
132
+ image: `mysql:${ ctx.config.overridenConfiguration.configuration.mysql.version }`
133
+ }
134
+ );
135
+
136
+ task.output = 'Waiting for MySQL to initialize...';
137
+
138
+ let mysqlReadyForConnections = false;
139
+
140
+ while (!mysqlReadyForConnections) {
141
+ const mysqlOutput = await execAsyncSpawn(`docker logs ${containerName}`);
142
+ if (mysqlOutput.includes('ready for connections')) {
143
+ mysqlReadyForConnections = true;
144
+ task.output = 'MySQL is ready!';
145
+ break;
146
+ } else if (mysqlOutput.includes('Initializing database files')) {
147
+ task.output = `MySQL is initializing database files!
148
+ Please wait, this will take some time and do not restart the MySQL container until initialization is finished!`;
149
+
150
+ let mysqlFinishedInitialization = false;
151
+ while (!mysqlFinishedInitialization) {
152
+ const mysqlOutput = await execAsyncSpawn(`docker logs ${containerName}`);
153
+ if (mysqlOutput.includes('init process done.') && !mysqlFinishedInitialization) {
154
+ mysqlFinishedInitialization = true;
155
+ task.output = 'MySQL is initialized!';
156
+ break;
157
+ }
158
+ await sleep(2000);
159
+ }
160
+ }
161
+
162
+ await sleep(2000);
163
+ }
164
+
165
+ task.output = 'Dumping MySQL database to dump file...';
166
+
167
+ await containerApi.exec(
168
+ [
169
+ 'mysqldump',
170
+ '--user=root',
171
+ '--password=scandipwa',
172
+ 'magento',
173
+ `--result-file=${ path.parse(pathToMySQLDumpFile).base }`
174
+ ].join(' '),
175
+ containerName,
176
+ {},
177
+ {
178
+ callback: (t) => {
179
+ task.output = t;
180
+ }
181
+ }
182
+ );
183
+
184
+ task.output = 'Copying dump file from container to system...';
185
+
186
+ await execAsyncSpawn(
187
+ `docker cp ${containerName}:/${ path.parse(pathToMySQLDumpFile).base } ${ pathToMySQLDumpFile }`
188
+ );
189
+
190
+ task.output = 'Removing migration container...';
191
+
192
+ await execAsyncSpawn(
193
+ `docker container stop ${containerName}`
194
+ );
195
+ await execAsyncSpawn(
196
+ `docker container rm ${containerName}`
197
+ );
198
+
199
+ ctx.importDb = pathToMySQLDumpFile;
200
+
201
+ return task.newListr([
202
+ createCacheFolder(),
203
+ getSystemConfigTask(),
204
+ getCachedPorts(),
205
+ stopContainers(),
206
+ setPrefix(),
207
+ getProjectConfiguration(),
208
+ // get fresh ports
209
+ getAvailablePorts(),
210
+ saveConfiguration(),
211
+ pullImages(),
212
+ dockerNetwork.tasks.createNetwork(),
213
+ createVolumes(),
214
+ {
215
+ task: (ctx, task) => task.newListr([
216
+ buildProjectImage(),
217
+ buildDebugProjectImage()
218
+ ], {
219
+ concurrent: true
220
+ })
221
+ },
222
+ checkPHPVersion(),
223
+ getComposerVersionTask(),
224
+ prepareFileSystem(),
225
+ installMagentoProject(),
226
+ enableMagentoComposerPlugins(),
227
+ startServices(),
228
+ connectToDatabase(),
229
+ importDumpToDatabase(),
230
+ {
231
+ task: async (subCtx, subTask) => {
232
+ const confirmDeleteOldVolume = await subTask.prompt({
233
+ type: 'Select',
234
+ message: 'Okay, looks like conversion went well, do you want to delete old mysql-data volume?',
235
+ choices: [
236
+ {
237
+ name: 'yes',
238
+ message: 'Sure'
239
+ },
240
+ {
241
+ name: 'no',
242
+ message: 'No, I want to keep it'
243
+ }
244
+ ]
245
+ });
246
+
247
+ if (confirmDeleteOldVolume === 'yes') {
248
+ await execAsyncSpawn(`docker volume rm ${ mysqlVolumeName }`);
249
+
250
+ const confirmDeleteDump = await subTask.prompt({
251
+ type: 'Select',
252
+ message: `Last question for today.
253
+ Do you want to keep database dump created during conversion process? (${logger.style.file(pathToMySQLDumpFile)})`,
254
+ choices: [
255
+ {
256
+ name: 'yes',
257
+ message: 'I don\'t need it, thanks'
258
+ },
259
+ {
260
+ name: 'no',
261
+ message: 'I would like to keep it, thanks'
262
+ }
263
+ ]
264
+ });
265
+
266
+ if (confirmDeleteDump === 'yes') {
267
+ await fs.promises.rm(pathToMySQLDumpFile);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ ]);
273
+ }
274
+ throw new KnownError('ABORTING');
275
+ }
276
+
277
+ task.skip();
278
+ },
279
+ options: {
280
+ bottomBar: 10
281
+ }
282
+ });
283
+
284
+ module.exports = convertMySQLDatabaseToMariaDB;
@@ -1,5 +1,7 @@
1
1
  const containers = require('./containers');
2
2
  const network = require('./network');
3
+ const volume = require('./volume');
4
+ const dockerApi = require('./api');
3
5
 
4
6
  /**
5
7
  * @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
@@ -19,13 +21,16 @@ const startServices = () => ({
19
21
  * @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
20
22
  */
21
23
  const stopServices = () => ({
24
+ title: 'Stopping Docker services',
22
25
  task: (ctx, task) => task.newListr([
23
26
  containers.stopContainers(),
27
+ volume.removeLocalVolumes(),
24
28
  network.tasks.removeNetwork()
25
29
  ])
26
30
  });
27
31
 
28
32
  module.exports = {
29
33
  startServices,
30
- stopServices
34
+ stopServices,
35
+ dockerApi
31
36
  };
@@ -15,7 +15,7 @@ export interface NetworkLsResult {
15
15
  IPv6: string
16
16
  Internal: string
17
17
  Labels: string
18
- Name: StreamPipeOptions
18
+ Name: string
19
19
  Scope: string
20
20
  }
21
21
 
@@ -27,13 +27,13 @@ const getEnabledExtensionsFromImage = async (imageWithTag) => {
27
27
  .reduce((acc, [name, version]) => ({ ...acc, [name]: version }), {});
28
28
  };
29
29
 
30
- const addExtensionToBuilder = (builder, ctx) => ([extensionName, extensionInstructions]) => {
30
+ const addExtensionToBuilder = (builder, ctx) => async ([extensionName, extensionInstructions]) => {
31
31
  const { command, ...extensionInstructionsWithoutCommand } = extensionInstructions;
32
32
  let runCommand = '';
33
33
  if (typeof command === 'string') {
34
34
  runCommand += ` ${command}`;
35
- } else if (typeof command === 'function') {
36
- runCommand += ` ${command({ ...extensionInstructionsWithoutCommand, ctx })}`;
35
+ } else if (typeof command === 'function' || command instanceof Promise) {
36
+ runCommand += ` ${await Promise.resolve(command({ ...extensionInstructionsWithoutCommand, ctx }))}`;
37
37
  } else {
38
38
  runCommand += ` docker-php-ext-install ${extensionInstructionsWithoutCommand.name}`;
39
39
  }
@@ -68,10 +68,6 @@ const buildDockerFileInstructions = async (ctx, { image, tag }) => {
68
68
  .comment('project image')
69
69
  .from({ image, tag });
70
70
 
71
- // install bash in image
72
- dockerFileInstructions
73
- .run('apk add --no-cache bash');
74
-
75
71
  if (missingExtensions.length > 0) {
76
72
  const allDependencies = missingExtensions.map(
77
73
  ([_extensionName, extensionInstructions]) => (extensionInstructions.dependencies || [])
@@ -79,7 +75,9 @@ const buildDockerFileInstructions = async (ctx, { image, tag }) => {
79
75
  .reduce((acc, val) => acc.concat(val.filter((ex) => !acc.includes(ex))), []);
80
76
 
81
77
  dockerFileInstructions.run(`apk add --no-cache ${allDependencies.join(' ')}`);
82
- missingExtensions.forEach(addExtensionToBuilder(dockerFileInstructions, ctx));
78
+ for (const missingExtensionInstructions of missingExtensions) {
79
+ await addExtensionToBuilder(dockerFileInstructions, ctx)(missingExtensionInstructions);
80
+ }
83
81
  }
84
82
 
85
83
  const composerVersion = /^\d$/.test(composer.version)
@@ -101,7 +99,7 @@ const buildDockerFileInstructions = async (ctx, { image, tag }) => {
101
99
  }
102
100
 
103
101
  dockerFileInstructions
104
- .workDir('/var/www/html');
102
+ .workDir(ctx.config.baseConfig.containerMagentoDir);
105
103
 
106
104
  return dockerFileInstructions;
107
105
  };
@@ -0,0 +1,9 @@
1
+ const volumeApi = require('./volume-api');
2
+ const { createVolumes, removeVolumes, removeLocalVolumes } = require('./tasks');
3
+
4
+ module.exports = {
5
+ createVolumes,
6
+ removeVolumes,
7
+ removeLocalVolumes,
8
+ volumeApi
9
+ };