@scandipwa/magento-scripts 2.4.0-alpha.2 → 2.4.0-alpha.3
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.
- package/lib/commands/import-db.js +36 -3
- package/lib/config/templates/php-fpm.template.conf +3 -4
- package/lib/tasks/database/fix-db.js +2 -0
- package/lib/tasks/database/import-dump-to-database.js +7 -4
- package/lib/tasks/docker/project-image-builder.js +6 -3
- package/lib/tasks/file-system/create-php-fpm-config.js +6 -1
- package/lib/tasks/file-system/create-php-fpm-debug-config.js +6 -1
- package/lib/tasks/magento/install-magento-project.js +63 -12
- package/lib/tasks/magento/setup-magento/check-file-permissions.php +35 -12
- package/lib/tasks/magento/setup-magento/disable-custom-admin-path.js +21 -0
- package/lib/tasks/magento/setup-magento/disable-maintenance-mode.js +13 -0
- package/lib/tasks/magento/setup-magento/set-deployment-mode.js +8 -5
- package/lib/tasks/magento/setup-magento/set-mail-config.js +16 -2
- package/lib/tasks/magento/setup-magento/setup-file-permissions.js +134 -58
- package/lib/tasks/php/php-container.js +7 -6
- package/lib/tasks/status/index.js +1 -0
- package/lib/util/database.js +36 -0
- package/package.json +2 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const logger = require('@scandipwa/scandipwa-dev-utils/logger')
|
|
2
2
|
const { Listr } = require('listr2')
|
|
3
3
|
const importDump = require('../tasks/import-dump')
|
|
4
|
+
const { getInstanceMetadata } = require('../util/instance-metadata')
|
|
5
|
+
const ConsoleBlock = require('../util/console-block')
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* @param {import('yargs')} yargs
|
|
@@ -37,14 +39,45 @@ module.exports = (yargs) => {
|
|
|
37
39
|
}
|
|
38
40
|
})
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
/**
|
|
43
|
+
* @type {import('../../typings/context').ListrContext}
|
|
44
|
+
*/
|
|
45
|
+
let ctx
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
try {
|
|
48
|
+
ctx = await tasks.run()
|
|
44
49
|
} catch (e) {
|
|
45
50
|
logger.error(e.message || e)
|
|
46
51
|
process.exit(1)
|
|
47
52
|
}
|
|
53
|
+
|
|
54
|
+
const instanceMetadata = getInstanceMetadata(ctx)
|
|
55
|
+
|
|
56
|
+
const block = new ConsoleBlock()
|
|
57
|
+
block.addHeader('Magento 2').addEmptyLine()
|
|
58
|
+
|
|
59
|
+
block.addLine(logger.style.misc('Frontend'))
|
|
60
|
+
instanceMetadata.frontend.forEach(({ title, text }) => {
|
|
61
|
+
block.addLine(` ${title}: ${text}`)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
block.addEmptyLine()
|
|
65
|
+
|
|
66
|
+
block.addLine(logger.style.misc('Admin'))
|
|
67
|
+
instanceMetadata.admin.forEach(({ title, text }) => {
|
|
68
|
+
block.addLine(` ${title}: ${text}`)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
block.addEmptyLine()
|
|
72
|
+
|
|
73
|
+
block.addLine(logger.style.misc('MailDev'))
|
|
74
|
+
instanceMetadata.maildev.forEach(({ title, text }) => {
|
|
75
|
+
block.addLine(` ${title}: ${text}`)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
block.log()
|
|
79
|
+
|
|
80
|
+
process.exit(0)
|
|
48
81
|
}
|
|
49
82
|
)
|
|
50
83
|
}
|
|
@@ -4,10 +4,9 @@ log_level = debug
|
|
|
4
4
|
|
|
5
5
|
[www]
|
|
6
6
|
clear_env = no
|
|
7
|
-
user =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
; group = nobody
|
|
7
|
+
user = <%= it.user %>
|
|
8
|
+
|
|
9
|
+
group = <%= it.user %>
|
|
11
10
|
|
|
12
11
|
catch_workers_output = yes
|
|
13
12
|
|
|
@@ -2,6 +2,7 @@ const configureElasticsearch = require('../magento/setup-magento/configure-searc
|
|
|
2
2
|
const deleteAdminUsers = require('../magento/setup-magento/delete-admin-users')
|
|
3
3
|
const deleteCustomers = require('../magento/setup-magento/delete-customers')
|
|
4
4
|
const deleteOrders = require('../magento/setup-magento/delete-orders')
|
|
5
|
+
const disableCustomAdminPath = require('../magento/setup-magento/disable-custom-admin-path')
|
|
5
6
|
const varnishConfigSetup = require('../magento/setup-magento/varnish-config')
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -30,6 +31,7 @@ const fixDB = () => ({
|
|
|
30
31
|
[
|
|
31
32
|
varnishConfigSetup(),
|
|
32
33
|
configureElasticsearch(),
|
|
34
|
+
disableCustomAdminPath(),
|
|
33
35
|
{
|
|
34
36
|
title: 'Deleting customers data',
|
|
35
37
|
skip: ({ withCustomersData }) => withCustomersData,
|
|
@@ -39,14 +39,16 @@ const copyDatabaseDumpIntoContainer = () => ({
|
|
|
39
39
|
const runSetGlobalLogBinTrustFunctionCreatorsCommand = () => ({
|
|
40
40
|
task: async (ctx, task) => {
|
|
41
41
|
const {
|
|
42
|
-
config: { docker },
|
|
42
|
+
config: { docker, overridenConfiguration },
|
|
43
43
|
ports
|
|
44
44
|
} = ctx
|
|
45
45
|
const { mariadb } = docker.getContainers(ports)
|
|
46
46
|
|
|
47
|
+
const { binFileName } = overridenConfiguration.configuration.mariadb
|
|
48
|
+
|
|
47
49
|
return task.newListr(
|
|
48
50
|
execCommandTask(
|
|
49
|
-
`docker exec ${mariadb.name} bash -c '
|
|
51
|
+
`docker exec ${mariadb.name} bash -c '${binFileName} -uroot -p${mariadb.env.MARIADB_ROOT_PASSWORD} -e "SET GLOBAL log_bin_trust_function_creators = 1;"'`
|
|
50
52
|
)
|
|
51
53
|
)
|
|
52
54
|
}
|
|
@@ -95,10 +97,11 @@ Note that you will lose your existing database!`,
|
|
|
95
97
|
const executeImportDumpSQL = () => ({
|
|
96
98
|
task: async (ctx, task) => {
|
|
97
99
|
const {
|
|
98
|
-
config: { docker },
|
|
100
|
+
config: { docker, overridenConfiguration },
|
|
99
101
|
ports
|
|
100
102
|
} = ctx
|
|
101
103
|
const { mariadb } = docker.getContainers(ports)
|
|
104
|
+
const { binFileName } = overridenConfiguration.configuration.mariadb
|
|
102
105
|
|
|
103
106
|
const userCredentialsForMariaDBCLI = await task.prompt({
|
|
104
107
|
type: 'Select',
|
|
@@ -117,7 +120,7 @@ const executeImportDumpSQL = () => ({
|
|
|
117
120
|
]
|
|
118
121
|
})
|
|
119
122
|
|
|
120
|
-
const importCommand = `docker exec ${mariadb.name} bash -c "
|
|
123
|
+
const importCommand = `docker exec ${mariadb.name} bash -c "${binFileName} ${userCredentialsForMariaDBCLI} magento < ./dump.sql"`
|
|
121
124
|
|
|
122
125
|
const startImportTime = Date.now()
|
|
123
126
|
const tickInterval = setInterval(() => {
|
|
@@ -169,9 +169,12 @@ const buildDockerFileInstructions = async (
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
if (
|
|
173
|
-
const {
|
|
174
|
-
dockerFileInstructions.run(
|
|
172
|
+
if (ctx.platform === 'linux') {
|
|
173
|
+
const { gid, username } = os.userInfo()
|
|
174
|
+
dockerFileInstructions.run(
|
|
175
|
+
`addgroup -g ${gid} ${username} && adduser -u ${gid} -G ${username} -H -s /sbin/nologin -D ${username} && \
|
|
176
|
+
addgroup www-data ${username}`
|
|
177
|
+
)
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
dockerFileInstructions.workDir(ctx.config.baseConfig.containerMagentoDir)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const os = require('os')
|
|
1
2
|
const UnknownError = require('../../errors/unknown-error')
|
|
2
3
|
const setConfigFile = require('../../util/set-config')
|
|
3
4
|
|
|
@@ -13,13 +14,17 @@ const createPhpFpmConfig = () => ({
|
|
|
13
14
|
} = ctx
|
|
14
15
|
const port = !isDockerDesktop ? ctx.ports.fpm : 9000
|
|
15
16
|
|
|
17
|
+
const user =
|
|
18
|
+
ctx.platform === 'linux' ? os.userInfo().username : 'www-data'
|
|
19
|
+
|
|
16
20
|
try {
|
|
17
21
|
await setConfigFile({
|
|
18
22
|
configPathname: php.fpmConfPath,
|
|
19
23
|
template: php.fpmTemplatePath,
|
|
20
24
|
overwrite: true,
|
|
21
25
|
templateArgs: {
|
|
22
|
-
port
|
|
26
|
+
port,
|
|
27
|
+
user
|
|
23
28
|
}
|
|
24
29
|
})
|
|
25
30
|
} catch (e) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const os = require('os')
|
|
1
2
|
const UnknownError = require('../../errors/unknown-error')
|
|
2
3
|
const setConfigFile = require('../../util/set-config')
|
|
3
4
|
|
|
@@ -13,13 +14,17 @@ const createPhpFpmDebugConfig = () => ({
|
|
|
13
14
|
} = ctx
|
|
14
15
|
const port = !isDockerDesktop ? ctx.ports.fpmXdebug : 9000
|
|
15
16
|
|
|
17
|
+
const user =
|
|
18
|
+
ctx.platform === 'linux' ? os.userInfo().username : 'www-data'
|
|
19
|
+
|
|
16
20
|
try {
|
|
17
21
|
await setConfigFile({
|
|
18
22
|
configPathname: php.debugFpmConfPath,
|
|
19
23
|
template: php.fpmTemplatePath,
|
|
20
24
|
overwrite: true,
|
|
21
25
|
templateArgs: {
|
|
22
|
-
port
|
|
26
|
+
port,
|
|
27
|
+
user
|
|
23
28
|
}
|
|
24
29
|
})
|
|
25
30
|
} catch (e) {
|
|
@@ -160,6 +160,46 @@ mv ${tempDir}/composer.json ${
|
|
|
160
160
|
)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Will check if the following conditions are met:
|
|
165
|
+
* - composer.lock file exists
|
|
166
|
+
* - vendor directory exists
|
|
167
|
+
* - all packages from composer.lock are installed in vendor directory
|
|
168
|
+
* @param {string} magentoDir
|
|
169
|
+
*/
|
|
170
|
+
const getIsVendorFolderCorrupted = async (magentoDir) => {
|
|
171
|
+
const composerLockFile = path.join(magentoDir, 'composer.lock')
|
|
172
|
+
const vendorDir = path.join(magentoDir, 'vendor')
|
|
173
|
+
const [vendorDirStat, composerLockFileStat] = await Promise.all([
|
|
174
|
+
pathExists(vendorDir),
|
|
175
|
+
pathExists(composerLockFile)
|
|
176
|
+
])
|
|
177
|
+
if (!vendorDirStat || !composerLockFileStat) {
|
|
178
|
+
return true
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* @type {{ packages: { name: string }[] } | null}
|
|
182
|
+
*/
|
|
183
|
+
const composerLockData = await getJsonFileData(composerLockFile)
|
|
184
|
+
if (!composerLockData || !composerLockData.packages) {
|
|
185
|
+
return true
|
|
186
|
+
}
|
|
187
|
+
const { packages } = composerLockData
|
|
188
|
+
const packagesNames = packages.map((pkg) => pkg.name)
|
|
189
|
+
|
|
190
|
+
const hasCorruptPackages = await Promise.all(
|
|
191
|
+
packagesNames.map(async (pkg) => {
|
|
192
|
+
const vendorPackage = path.join(vendorDir, pkg)
|
|
193
|
+
const composerJson = path.join(vendorPackage, 'composer.json')
|
|
194
|
+
if (!(await pathExists(composerJson))) {
|
|
195
|
+
return true
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return hasCorruptPackages.every((result) => result === true)
|
|
201
|
+
}
|
|
202
|
+
|
|
163
203
|
/**
|
|
164
204
|
* @returns {import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
|
|
165
205
|
*/
|
|
@@ -197,7 +237,11 @@ const installMagentoProject = () => ({
|
|
|
197
237
|
'composer.lock': true
|
|
198
238
|
})
|
|
199
239
|
|
|
200
|
-
|
|
240
|
+
const isVendorFolderCorrupted = await getIsVendorFolderCorrupted(
|
|
241
|
+
baseConfig.magentoDir
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
if (isFsMatching && !isVendorFolderCorrupted) {
|
|
201
245
|
ctx.magentoFirstInstall = false
|
|
202
246
|
task.skip()
|
|
203
247
|
return
|
|
@@ -206,17 +250,24 @@ const installMagentoProject = () => ({
|
|
|
206
250
|
task.title = `Installing Magento ${magentoPackageVersion}`
|
|
207
251
|
task.output = `Creating Magento ${magentoPackageVersion} project`
|
|
208
252
|
|
|
209
|
-
if (!
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
253
|
+
if (!isFsMatching) {
|
|
254
|
+
if (
|
|
255
|
+
!(await pathExists(path.join(process.cwd(), 'composer.json')))
|
|
256
|
+
) {
|
|
257
|
+
await createMagentoProject(ctx, task, {
|
|
258
|
+
magentoProject,
|
|
259
|
+
magentoPackageVersion
|
|
260
|
+
})
|
|
261
|
+
}
|
|
215
262
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
263
|
+
if (!(await pathExists(path.join(process.cwd(), 'app', 'etc')))) {
|
|
264
|
+
await fs.promises.mkdir(
|
|
265
|
+
path.join(process.cwd(), 'app', 'etc'),
|
|
266
|
+
{
|
|
267
|
+
recursive: true
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
}
|
|
220
271
|
}
|
|
221
272
|
|
|
222
273
|
return task.newListr([
|
|
@@ -226,7 +277,7 @@ const installMagentoProject = () => ({
|
|
|
226
277
|
title: 'Installing Magento dependencies',
|
|
227
278
|
task: async () => {
|
|
228
279
|
try {
|
|
229
|
-
await runComposerCommand(ctx, 'install', {
|
|
280
|
+
await runComposerCommand(ctx, 'install -vvv', {
|
|
230
281
|
callback: !ctx.verbose
|
|
231
282
|
? undefined
|
|
232
283
|
: (t) => {
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
'/generated',
|
|
5
|
-
'/vendor',
|
|
6
|
-
'/pub/static',
|
|
7
|
-
'/pub/media',
|
|
8
|
-
'/app/etc',
|
|
9
|
-
];
|
|
2
|
+
// receive directories from command line arguments
|
|
3
|
+
$directories = explode(",", $argv[1]);
|
|
10
4
|
|
|
11
5
|
$results = [];
|
|
12
6
|
|
|
13
|
-
foreach ($directories as $
|
|
14
|
-
$directory = getcwd() . $dir;
|
|
7
|
+
foreach ($directories as $directory) {
|
|
15
8
|
$result = [];
|
|
9
|
+
$result['directory'] = $directory;
|
|
16
10
|
$result['exists'] = file_exists($directory);
|
|
17
11
|
$result['writable'] = is_writable($directory);
|
|
18
12
|
$result['readable'] = is_readable($directory);
|
|
@@ -22,11 +16,40 @@ foreach ($directories as $dir) {
|
|
|
22
16
|
$result['group'] = posix_getgrgid(filegroup($directory));
|
|
23
17
|
$result['current_user'] = posix_getpwuid(posix_geteuid());
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
// Check if current user is in the group
|
|
20
|
+
if ($result['group']['members'] && is_array($result['group']['members'])) {
|
|
21
|
+
$result['current_user_in_group'] = in_array($result['current_user']['name'], $result['group']['members']);
|
|
22
|
+
} else {
|
|
23
|
+
$result['current_user_in_group'] = false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check if the directory has group write permissions (g+w)
|
|
27
|
+
$permissions = fileperms($directory);
|
|
28
|
+
$result['has_group_write_permissions'] = ($permissions & 0x0010) !== 0;
|
|
29
|
+
|
|
30
|
+
$result['permissions'] = substr(sprintf('%o', fileperms($directory)), -4);
|
|
26
31
|
$result['is_current_user_directory_owner'] = $result['current_user'] === $result['owner'];
|
|
32
|
+
|
|
33
|
+
if ($result['writable']) {
|
|
34
|
+
// Check if new files inherit the directory's group
|
|
35
|
+
try {
|
|
36
|
+
$tempFile = $directory . DIRECTORY_SEPARATOR . '.temp_file_' . uniqid();
|
|
37
|
+
touch($tempFile);
|
|
38
|
+
|
|
39
|
+
$tempFileGroup = posix_getgrgid(filegroup($tempFile));
|
|
40
|
+
$result['new_files_inherit_group'] = $tempFileGroup === $result['group'];
|
|
41
|
+
} catch (Exception $e) {
|
|
42
|
+
$result['new_files_inherit_group'] = false;
|
|
43
|
+
} finally {
|
|
44
|
+
// Clean up the temporary file
|
|
45
|
+
if (file_exists($tempFile)) {
|
|
46
|
+
unlink($tempFile);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
27
50
|
}
|
|
28
51
|
|
|
29
52
|
$results[] = $result;
|
|
30
53
|
}
|
|
31
54
|
|
|
32
|
-
echo json_encode($results, JSON_PRETTY_PRINT);
|
|
55
|
+
echo json_encode($results, JSON_PRETTY_PRINT);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { deleteTableValues } = require('../../../util/database')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @returns {import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
|
|
5
|
+
*/
|
|
6
|
+
const disableCustomAdminPath = () => ({
|
|
7
|
+
title: 'Disabling custom admin path',
|
|
8
|
+
task: async ({ databaseConnection }, task) => {
|
|
9
|
+
await deleteTableValues(
|
|
10
|
+
'core_config_data',
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
path: 'admin/url/use_custom_path'
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
{ databaseConnection, task }
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
module.exports = disableCustomAdminPath
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const pathExists = require('../../../util/path-exists')
|
|
1
3
|
const runMagentoCommand = require('../../../util/run-magento')
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -6,6 +8,17 @@ const runMagentoCommand = require('../../../util/run-magento')
|
|
|
6
8
|
const disableMaintenanceMode = () => ({
|
|
7
9
|
title: 'Disabling maintenance mode',
|
|
8
10
|
task: async (ctx, task) => {
|
|
11
|
+
const maintenanceModeFile = `var/.maintenance.flag`
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
!(await pathExists(
|
|
15
|
+
path.join(ctx.config.baseConfig.magentoDir, maintenanceModeFile)
|
|
16
|
+
))
|
|
17
|
+
) {
|
|
18
|
+
task.skip()
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
const { result } = await runMagentoCommand(ctx, 'maintenance:status', {
|
|
10
23
|
throwNonZeroCode: false
|
|
11
24
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
const envPhpToJson = require('../../../util/env-php-json')
|
|
1
2
|
const magentoTask = require('../../../util/magento-task')
|
|
2
|
-
const runMagentoCommand = require('../../../util/run-magento')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @returns {import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
|
|
@@ -12,11 +12,14 @@ module.exports = () => ({
|
|
|
12
12
|
magentoConfiguration: { mode }
|
|
13
13
|
}
|
|
14
14
|
} = ctx
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const envPhpData = await envPhpToJson(ctx)
|
|
16
|
+
if (!envPhpData) {
|
|
17
|
+
task.skip()
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
const { MAGE_MODE } = envPhpData
|
|
18
21
|
|
|
19
|
-
if (
|
|
22
|
+
if (MAGE_MODE === mode) {
|
|
20
23
|
task.skip()
|
|
21
24
|
return
|
|
22
25
|
}
|
|
@@ -10,14 +10,28 @@ const setMailConfig = () => ({
|
|
|
10
10
|
'core_config_data',
|
|
11
11
|
[
|
|
12
12
|
{
|
|
13
|
-
path: 'smtp/
|
|
13
|
+
path: 'system/smtp/transport',
|
|
14
|
+
value: 'smtp'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
path: 'system/smtp/host',
|
|
18
|
+
value: isDockerDesktop
|
|
19
|
+
? 'host.docker.internal'
|
|
20
|
+
: '127.0.0.1'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
path: 'system/smtp/port',
|
|
14
24
|
value: `${ports.maildevSMTP}`
|
|
15
25
|
},
|
|
16
26
|
{
|
|
17
27
|
path: 'smtp/configuration_option/host',
|
|
18
28
|
value: isDockerDesktop
|
|
19
29
|
? 'host.docker.internal'
|
|
20
|
-
: '
|
|
30
|
+
: '127.0.0.1'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
path: 'smtp/configuration_option/port',
|
|
34
|
+
value: `${ports.maildevSMTP}`
|
|
21
35
|
}
|
|
22
36
|
],
|
|
23
37
|
{ databaseConnection, task }
|
|
@@ -6,33 +6,58 @@ const {
|
|
|
6
6
|
runPHPContainerCommand
|
|
7
7
|
} = require('../../php/php-container')
|
|
8
8
|
|
|
9
|
+
const directoriesToCheck = [
|
|
10
|
+
'var',
|
|
11
|
+
'generated',
|
|
12
|
+
'vendor',
|
|
13
|
+
'pub/media',
|
|
14
|
+
'pub/static',
|
|
15
|
+
'app/etc'
|
|
16
|
+
]
|
|
17
|
+
|
|
9
18
|
/**
|
|
19
|
+
* @param {string[]} directories
|
|
10
20
|
* @returns {import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
|
|
11
21
|
*/
|
|
12
|
-
const makeNewFilesCreatedInFolderUseDirectoryGroup = () => ({
|
|
22
|
+
const makeNewFilesCreatedInFolderUseDirectoryGroup = (directories) => ({
|
|
13
23
|
title: 'Make new files created in folder use directory group',
|
|
14
|
-
task: (ctx, task) =>
|
|
15
|
-
|
|
24
|
+
task: async (ctx, task) => {
|
|
25
|
+
if (directories.length === 0) {
|
|
26
|
+
task.skip()
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return task.newListr([
|
|
16
31
|
runPHPContainerCommandTask(
|
|
17
|
-
|
|
32
|
+
`find ${directories.join(' ')} -type d -exec chmod g+ws {} +`,
|
|
18
33
|
{
|
|
19
34
|
// should prevent command from failing the task
|
|
20
35
|
// if the folder does not exist
|
|
21
|
-
withCode: true
|
|
36
|
+
withCode: true,
|
|
37
|
+
useAutomaticUser: false
|
|
22
38
|
}
|
|
23
39
|
)
|
|
24
40
|
])
|
|
41
|
+
}
|
|
25
42
|
})
|
|
26
43
|
|
|
27
44
|
/**
|
|
45
|
+
* @param {string[]} directories
|
|
28
46
|
* @returns {import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
|
|
29
47
|
*/
|
|
30
|
-
const makeFilesWritableForGroupMembers = () => ({
|
|
48
|
+
const makeFilesWritableForGroupMembers = (directories) => ({
|
|
31
49
|
title: 'Make files writable for group members',
|
|
32
|
-
task: (ctx, task) =>
|
|
33
|
-
|
|
50
|
+
task: async (ctx, task) => {
|
|
51
|
+
if (directories.length === 0) {
|
|
52
|
+
task.skip()
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return task.newListr([
|
|
34
57
|
runPHPContainerCommandTask(
|
|
35
|
-
|
|
58
|
+
`find ${directories.join(
|
|
59
|
+
' '
|
|
60
|
+
)} -type -type f -exec chmod g+w {} +`,
|
|
36
61
|
{
|
|
37
62
|
// should prevent command from failing the task
|
|
38
63
|
// if the folder does not exist
|
|
@@ -40,6 +65,7 @@ const makeFilesWritableForGroupMembers = () => ({
|
|
|
40
65
|
}
|
|
41
66
|
)
|
|
42
67
|
])
|
|
68
|
+
}
|
|
43
69
|
})
|
|
44
70
|
|
|
45
71
|
/**
|
|
@@ -65,39 +91,41 @@ const makeFolderOwnedByUser = (folder, user, group) => ({
|
|
|
65
91
|
|
|
66
92
|
/**
|
|
67
93
|
* @param {import('../../../../typings/context').ListrContext} ctx
|
|
94
|
+
* @param {string[]} directories
|
|
95
|
+
* @return {Promise<{directory: string, exists: boolean, new_files_inherit_group: boolean, has_group_write_permissions: boolean, writable: boolean, permissions: string, directory_owner: {name: string, passwd: string, uid: number, gid: number, gecos: string, dir: string, shell: string} | boolean, directory_group: boolean, current_user: {name: string, passwd: string, uid: number, gid: number, gecos: string, dir: string, shell: string} | boolean, is_current_user_directory_owner: boolean}[]>}
|
|
68
96
|
*/
|
|
69
|
-
const
|
|
97
|
+
const checkDirectoriesPermissions = async (ctx, directories) => {
|
|
70
98
|
const checkPHPPermissionsFileName = 'check-file-permissions.php'
|
|
71
99
|
const cacheDirFilePath = path.join(
|
|
72
100
|
ctx.config.baseConfig.cacheDir,
|
|
73
|
-
checkPHPPermissionsFileName
|
|
101
|
+
`${Date.now()}-${checkPHPPermissionsFileName}`
|
|
74
102
|
)
|
|
75
103
|
await fs.promises.copyFile(
|
|
76
104
|
path.join(__dirname, checkPHPPermissionsFileName),
|
|
77
105
|
cacheDirFilePath
|
|
78
106
|
)
|
|
107
|
+
const user =
|
|
108
|
+
ctx.platform === 'linux' ? `${os.userInfo().username}` : 'www-data'
|
|
109
|
+
const group =
|
|
110
|
+
ctx.platform === 'linux' ? `${os.userInfo().username}` : 'www-data'
|
|
111
|
+
|
|
112
|
+
const userWithGroup = `${user}:${group}`
|
|
79
113
|
|
|
80
114
|
const result = await runPHPContainerCommand(
|
|
81
115
|
ctx,
|
|
82
|
-
`php ${path.relative(
|
|
116
|
+
`php ${path.relative(
|
|
117
|
+
ctx.config.baseConfig.containerMagentoDir,
|
|
118
|
+
cacheDirFilePath
|
|
119
|
+
)} ${directories.join(',')}`,
|
|
83
120
|
{
|
|
84
|
-
user:
|
|
121
|
+
user: userWithGroup,
|
|
85
122
|
cwd: ctx.config.baseConfig.containerMagentoDir
|
|
86
123
|
}
|
|
87
124
|
)
|
|
88
125
|
|
|
89
126
|
await fs.promises.unlink(cacheDirFilePath)
|
|
90
127
|
|
|
91
|
-
|
|
92
|
-
* @type {{directory: string, exists: boolean, writable: boolean, permissions: string, directory_owner: {name: string, passwd: string, uid: number, gid: number, gecos: string, dir: string, shell: string} | boolean, directory_group: boolean, current_user: {name: string, passwd: string, uid: number, gid: number, gecos: string, dir: string, shell: string} | boolean, is_current_user_directory_owner: boolean}[]}
|
|
93
|
-
*/
|
|
94
|
-
const parsedResult = JSON.parse(result)
|
|
95
|
-
|
|
96
|
-
if (parsedResult.some(({ exists, writable }) => exists && !writable)) {
|
|
97
|
-
return true
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return false
|
|
128
|
+
return JSON.parse(result)
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
/**
|
|
@@ -105,27 +133,69 @@ const doesFileSystemNeedsPermissionsSetup = async (ctx) => {
|
|
|
105
133
|
*/
|
|
106
134
|
const setupMagentoFilePermissions = () => ({
|
|
107
135
|
title: 'Setting Magento file permissions',
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
task.newListr(
|
|
114
|
-
[
|
|
115
|
-
makeNewFilesCreatedInFolderUseDirectoryGroup(),
|
|
116
|
-
makeFilesWritableForGroupMembers()
|
|
117
|
-
].concat(
|
|
118
|
-
ctx.isDockerDesktop
|
|
119
|
-
? [
|
|
120
|
-
makeFolderOwnedByUser(
|
|
121
|
-
ctx.config.baseConfig.containerMagentoDir,
|
|
122
|
-
'www-data',
|
|
123
|
-
'www-data'
|
|
124
|
-
)
|
|
125
|
-
]
|
|
126
|
-
: []
|
|
136
|
+
task: async (ctx, task) => {
|
|
137
|
+
const parsedResult = await checkDirectoriesPermissions(
|
|
138
|
+
ctx,
|
|
139
|
+
directoriesToCheck.map((directory) =>
|
|
140
|
+
path.join(ctx.config.baseConfig.containerMagentoDir, directory)
|
|
127
141
|
)
|
|
128
142
|
)
|
|
143
|
+
const nonWritableDirectories = parsedResult.filter(
|
|
144
|
+
({ exists, writable }) => exists && !writable
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const tasks = []
|
|
148
|
+
|
|
149
|
+
if (nonWritableDirectories.length !== 0) {
|
|
150
|
+
const nonWritableDirectoriesPaths = nonWritableDirectories.map(
|
|
151
|
+
({ directory }) => directory
|
|
152
|
+
)
|
|
153
|
+
const user =
|
|
154
|
+
ctx.platform === 'linux'
|
|
155
|
+
? `${os.userInfo().username}`
|
|
156
|
+
: 'www-data'
|
|
157
|
+
const group =
|
|
158
|
+
ctx.platform === 'linux'
|
|
159
|
+
? `${os.userInfo().username}`
|
|
160
|
+
: 'www-data'
|
|
161
|
+
|
|
162
|
+
tasks.push(
|
|
163
|
+
makeFilesWritableForGroupMembers(nonWritableDirectoriesPaths),
|
|
164
|
+
{
|
|
165
|
+
task: (subCtx, subTask) =>
|
|
166
|
+
subTask.newListr(
|
|
167
|
+
nonWritableDirectoriesPaths.map((directory) =>
|
|
168
|
+
makeFolderOwnedByUser(directory, user, group)
|
|
169
|
+
)
|
|
170
|
+
),
|
|
171
|
+
options: {
|
|
172
|
+
concurrent: true
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const directoriesThatNeedNewFilesInheritGroup = parsedResult
|
|
179
|
+
.filter(
|
|
180
|
+
({ exists, new_files_inherit_group: nfig }) => exists && !nfig
|
|
181
|
+
)
|
|
182
|
+
.map(({ directory }) => directory)
|
|
183
|
+
|
|
184
|
+
if (directoriesThatNeedNewFilesInheritGroup.length > 0) {
|
|
185
|
+
tasks.push(
|
|
186
|
+
makeNewFilesCreatedInFolderUseDirectoryGroup(
|
|
187
|
+
directoriesThatNeedNewFilesInheritGroup
|
|
188
|
+
)
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (tasks.length === 0) {
|
|
193
|
+
task.skip()
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return task.newListr(tasks)
|
|
198
|
+
}
|
|
129
199
|
})
|
|
130
200
|
|
|
131
201
|
/**
|
|
@@ -133,23 +203,29 @@ const setupMagentoFilePermissions = () => ({
|
|
|
133
203
|
*/
|
|
134
204
|
const setupComposerCachePermissions = () => ({
|
|
135
205
|
title: 'Setting Composer Cache permissions',
|
|
136
|
-
task: (ctx, task) =>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
runPHPContainerCommandTask('chmod g+
|
|
206
|
+
task: async (ctx, task) => {
|
|
207
|
+
const parsedResult = await checkDirectoriesPermissions(ctx, [
|
|
208
|
+
'/composer/home'
|
|
209
|
+
])
|
|
210
|
+
|
|
211
|
+
if (parsedResult.every((dir) => dir.writable)) {
|
|
212
|
+
task.skip()
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const userAndGroup =
|
|
217
|
+
ctx.platform === 'linux' ? `${os.userInfo().username}` : 'www-data'
|
|
218
|
+
|
|
219
|
+
return task.newListr([
|
|
220
|
+
makeFolderOwnedByUser('/composer/home', userAndGroup, userAndGroup),
|
|
221
|
+
runPHPContainerCommandTask('chmod g+ws /composer/home/cache', {
|
|
222
|
+
user: ctx.platform === 'linux' ? 'root:root' : ''
|
|
223
|
+
}),
|
|
224
|
+
runPHPContainerCommandTask('chmod g+w /composer/home/cache', {
|
|
225
|
+
user: ctx.platform === 'linux' ? 'root:root' : ''
|
|
226
|
+
})
|
|
152
227
|
])
|
|
228
|
+
}
|
|
153
229
|
})
|
|
154
230
|
|
|
155
231
|
module.exports = {
|
|
@@ -9,6 +9,7 @@ const { containerApi } = require('../docker/containers')
|
|
|
9
9
|
* @param {Parameters<typeof import('./php-container')['runPHPContainerCommand']>[2] & { useAutomaticUser?: boolean}} [options]
|
|
10
10
|
*/
|
|
11
11
|
const runPHPContainerCommand = async (ctx, command, options = {}) => {
|
|
12
|
+
const { useAutomaticUser = true } = options
|
|
12
13
|
const { php } = ctx.config.docker.getContainers(ctx.ports)
|
|
13
14
|
|
|
14
15
|
const containers = await containerApi.ls({
|
|
@@ -29,16 +30,16 @@ const runPHPContainerCommand = async (ctx, command, options = {}) => {
|
|
|
29
30
|
rm: true,
|
|
30
31
|
command
|
|
31
32
|
},
|
|
32
|
-
|
|
33
|
+
useAutomaticUser && ctx.platform === 'linux'
|
|
33
34
|
? {
|
|
34
|
-
user:
|
|
35
|
+
user: `${os.userInfo().username}:${
|
|
36
|
+
os.userInfo().username
|
|
37
|
+
}`
|
|
35
38
|
}
|
|
36
39
|
: {},
|
|
37
|
-
options.
|
|
40
|
+
options.user
|
|
38
41
|
? {
|
|
39
|
-
user:
|
|
40
|
-
? 'www-data:www-data'
|
|
41
|
-
: `${os.userInfo().uid}:${os.userInfo().gid}`
|
|
42
|
+
user: options.user
|
|
42
43
|
}
|
|
43
44
|
: {}
|
|
44
45
|
),
|
|
@@ -91,6 +91,7 @@ const prettyStatus = async (ctx) => {
|
|
|
91
91
|
.addLine(`Platform: ${logger.style.code(platform)}`)
|
|
92
92
|
.addLine(`Platform version: ${logger.style.file(platformVersion)}`)
|
|
93
93
|
.addLine(`Platform architecture: ${logger.style.file(getArchSync())}`)
|
|
94
|
+
.addLine(`CGroup version: ${logger.style.file(ctx.cgroupVersion)}`)
|
|
94
95
|
.addEmptyLine()
|
|
95
96
|
.addSeparator('Docker containers status')
|
|
96
97
|
|
package/lib/util/database.js
CHANGED
|
@@ -77,6 +77,41 @@ const updateTableValues = async (
|
|
|
77
77
|
)
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Delete table in **magento** database
|
|
82
|
+
* @param {String} table Table name
|
|
83
|
+
* @param {{ path: string, value: string | number | null }[]} values
|
|
84
|
+
* @param {{ databaseConnection: import('../../typings/context').ListrContext['databaseConnection'], task: { skip(): void } }} param2
|
|
85
|
+
*/
|
|
86
|
+
const deleteTableValues = async (
|
|
87
|
+
table,
|
|
88
|
+
values,
|
|
89
|
+
{ databaseConnection, task }
|
|
90
|
+
) => {
|
|
91
|
+
const [rows] = await databaseConnection.query(`
|
|
92
|
+
SELECT * FROM ${table}
|
|
93
|
+
WHERE ${values.map((p) => `path = '${p.path}'`).join(' OR ')};
|
|
94
|
+
`)
|
|
95
|
+
|
|
96
|
+
if (rows.filter(Boolean).length === 0) {
|
|
97
|
+
task.skip()
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const configsToDelete = rows.filter(({ path }) =>
|
|
102
|
+
values.some((p) => p.path === path)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
for (const config of configsToDelete) {
|
|
106
|
+
await databaseConnection.query(
|
|
107
|
+
`
|
|
108
|
+
DELETE FROM ${table}
|
|
109
|
+
WHERE config_id = ?;
|
|
110
|
+
`,
|
|
111
|
+
[config.config_id]
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
80
115
|
|
|
81
116
|
/**
|
|
82
117
|
* Insert values into table in **magento** database
|
|
@@ -213,6 +248,7 @@ const databaseQuery = async (
|
|
|
213
248
|
module.exports = {
|
|
214
249
|
updateTableValues,
|
|
215
250
|
insertTableValues,
|
|
251
|
+
deleteTableValues,
|
|
216
252
|
isTableExists,
|
|
217
253
|
databaseQuery
|
|
218
254
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Scripts and configuration used by CMA.",
|
|
4
4
|
"homepage": "https://docs.create-magento-app.com/",
|
|
5
5
|
"repository": "github:scandipwa/create-magento-app",
|
|
6
|
-
"version": "2.4.0-alpha.
|
|
6
|
+
"version": "2.4.0-alpha.3",
|
|
7
7
|
"main": "./index.js",
|
|
8
8
|
"types": "./typings/index.d.ts",
|
|
9
9
|
"license": "OSL-3.0",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"@types/node": "^20.14.11",
|
|
60
60
|
"@types/yargs": "^17.0.32"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "13e109c2d3475127df939b7a95bc0140927d4227"
|
|
63
63
|
}
|