@bostonuniversity/buwp-local 0.1.0
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/.buwp-local.examplejson +27 -0
- package/.buwp-local.json +27 -0
- package/IMPLEMENTATION_SUMMARY.md +385 -0
- package/MULTI_PROJECT_GUIDE.md +929 -0
- package/PROJECT_OVERVIEW.md +307 -0
- package/QUICK_REFERENCE.md +234 -0
- package/ROADMAP.md +362 -0
- package/SHARED_ENVIRONMENT_EXAMPLES.md +578 -0
- package/USAGE.md +258 -0
- package/bin/buwp-local.js +95 -0
- package/bostonuniversity-buwp-local-0.1.0.tgz +0 -0
- package/docker-compose.yml +106 -0
- package/lib/commands/config.js +131 -0
- package/lib/commands/destroy.js +96 -0
- package/lib/commands/logs.js +66 -0
- package/lib/commands/start.js +98 -0
- package/lib/commands/stop.js +62 -0
- package/lib/compose-generator.js +279 -0
- package/lib/config.js +292 -0
- package/lib/index.js +23 -0
- package/macos-keychain-notes.md +11 -0
- package/package.json +35 -0
- package/readme.md +3 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs command - View logs from the WordPress environment
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const { loadConfig } = require('../config');
|
|
10
|
+
|
|
11
|
+
async function logsCommand(options) {
|
|
12
|
+
console.log(chalk.blue('š Viewing logs...\n'));
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const projectPath = process.cwd();
|
|
16
|
+
const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
|
|
17
|
+
|
|
18
|
+
// Check if docker-compose.yml exists
|
|
19
|
+
if (!fs.existsSync(composePath)) {
|
|
20
|
+
console.log(chalk.yellow('ā ļø No running environment found.'));
|
|
21
|
+
console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Load config to get project name
|
|
26
|
+
const config = loadConfig(projectPath);
|
|
27
|
+
const projectName = config.projectName || 'buwp-local';
|
|
28
|
+
|
|
29
|
+
// Check if Docker is running
|
|
30
|
+
try {
|
|
31
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error(chalk.red('ā Docker is not running.'));
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Build docker compose logs command
|
|
38
|
+
const composeDir = path.dirname(composePath);
|
|
39
|
+
let command = `docker compose -p ${projectName} -f ${composePath} logs`;
|
|
40
|
+
|
|
41
|
+
if (options.follow) {
|
|
42
|
+
command += ' -f';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (options.service) {
|
|
46
|
+
command += ` ${options.service}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Execute logs command
|
|
50
|
+
try {
|
|
51
|
+
execSync(command, {
|
|
52
|
+
cwd: composeDir,
|
|
53
|
+
stdio: 'inherit'
|
|
54
|
+
});
|
|
55
|
+
} catch (err) {
|
|
56
|
+
// User likely pressed Ctrl+C to exit, which is expected
|
|
57
|
+
console.log(chalk.gray('\nLogs closed.\n'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error(chalk.red('\nā Error:'), err.message);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = logsCommand;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Start command - Starts the local WordPress environment
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { loadConfig, validateConfig } = require('../config');
|
|
9
|
+
const { generateComposeFile } = require('../compose-generator');
|
|
10
|
+
|
|
11
|
+
async function startCommand(options) {
|
|
12
|
+
console.log(chalk.blue('š Starting BU WordPress local environment...\n'));
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Load configuration
|
|
16
|
+
const projectPath = process.cwd();
|
|
17
|
+
let config = loadConfig(projectPath);
|
|
18
|
+
|
|
19
|
+
// Apply command-line options
|
|
20
|
+
if (options.xdebug) {
|
|
21
|
+
config.env = config.env || {};
|
|
22
|
+
config.env.XDEBUG = true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (options.s3 === false) {
|
|
26
|
+
config.services.s3proxy = false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (options.redis === false) {
|
|
30
|
+
config.services.redis = false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Validate configuration
|
|
34
|
+
console.log(chalk.gray('Validating configuration...'));
|
|
35
|
+
const validation = validateConfig(config);
|
|
36
|
+
|
|
37
|
+
if (!validation.valid) {
|
|
38
|
+
console.error(chalk.red('\nā Configuration validation failed:'));
|
|
39
|
+
validation.errors.forEach(error => {
|
|
40
|
+
console.error(chalk.red(` - ${error}`));
|
|
41
|
+
});
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Generate docker-compose.yml
|
|
46
|
+
console.log(chalk.gray('Generating docker-compose.yml...'));
|
|
47
|
+
const composePath = generateComposeFile(config, projectPath);
|
|
48
|
+
console.log(chalk.green(`ā Generated ${composePath}\n`));
|
|
49
|
+
|
|
50
|
+
// Check if Docker is running
|
|
51
|
+
try {
|
|
52
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(chalk.red('ā Docker is not running. Please start Docker Desktop and try again.'));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Start Docker Compose
|
|
59
|
+
console.log(chalk.gray('Starting Docker containers...\n'));
|
|
60
|
+
const composeDir = path.dirname(composePath);
|
|
61
|
+
const projectName = config.projectName || 'buwp-local';
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
execSync(
|
|
65
|
+
`docker compose -p ${projectName} -f ${composePath} up -d`,
|
|
66
|
+
{
|
|
67
|
+
cwd: composeDir,
|
|
68
|
+
stdio: 'inherit'
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error(chalk.red('\nā Failed to start Docker containers'));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Success message
|
|
77
|
+
console.log(chalk.green('\nā
Environment started successfully!\n'));
|
|
78
|
+
console.log(chalk.cyan(`Project: ${projectName}`));
|
|
79
|
+
console.log(chalk.cyan('Access your site at:'));
|
|
80
|
+
console.log(chalk.white(` http://${config.hostname}`));
|
|
81
|
+
console.log(chalk.white(` https://${config.hostname}\n`));
|
|
82
|
+
|
|
83
|
+
console.log(chalk.gray('Useful commands:'));
|
|
84
|
+
console.log(chalk.white(' buwp-local logs - View logs'));
|
|
85
|
+
console.log(chalk.white(' buwp-local stop - Stop environment'));
|
|
86
|
+
console.log(chalk.white(' buwp-local destroy - Remove environment\n'));
|
|
87
|
+
|
|
88
|
+
// Reminder about /etc/hosts
|
|
89
|
+
console.log(chalk.yellow('ā ļø Remember to add this to your /etc/hosts file:'));
|
|
90
|
+
console.log(chalk.white(` 127.0.0.1 ${config.hostname}\n`));
|
|
91
|
+
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error(chalk.red('\nā Error:'), err.message);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = startCommand;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop command - Stops the local WordPress environment
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const { loadConfig } = require('../config');
|
|
10
|
+
|
|
11
|
+
async function stopCommand() {
|
|
12
|
+
console.log(chalk.blue('š Stopping BU WordPress local environment...\n'));
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const projectPath = process.cwd();
|
|
16
|
+
const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
|
|
17
|
+
|
|
18
|
+
// Check if docker-compose.yml exists
|
|
19
|
+
if (!fs.existsSync(composePath)) {
|
|
20
|
+
console.log(chalk.yellow('ā ļø No running environment found.'));
|
|
21
|
+
console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Load config to get project name
|
|
26
|
+
const config = loadConfig(projectPath);
|
|
27
|
+
const projectName = config.projectName || 'buwp-local';
|
|
28
|
+
|
|
29
|
+
// Check if Docker is running
|
|
30
|
+
try {
|
|
31
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error(chalk.red('ā Docker is not running.'));
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Stop Docker Compose
|
|
38
|
+
const composeDir = path.dirname(composePath);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
execSync(
|
|
42
|
+
`docker compose -p ${projectName} -f ${composePath} stop`,
|
|
43
|
+
{
|
|
44
|
+
cwd: composeDir,
|
|
45
|
+
stdio: 'inherit'
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error(chalk.red('\nā Failed to stop Docker containers'));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(chalk.green('\nā
Environment stopped successfully!\n'));
|
|
54
|
+
console.log(chalk.gray('Use "buwp-local start" to start it again.\n'));
|
|
55
|
+
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(chalk.red('\nā Error:'), err.message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = stopCommand;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker Compose file generator
|
|
3
|
+
* Generates docker-compose.yml from configuration using js-yaml
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const yaml = require('js-yaml');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate docker-compose configuration from buwp-local config
|
|
13
|
+
* @param {object} config - buwp-local configuration
|
|
14
|
+
* @returns {object} Docker Compose configuration object
|
|
15
|
+
*/
|
|
16
|
+
function generateComposeConfig(config) {
|
|
17
|
+
// Use project name for unique volume naming
|
|
18
|
+
const projectName = config.projectName || 'buwp-local';
|
|
19
|
+
const dbVolumeName = `${projectName}_db_data`;
|
|
20
|
+
const wpVolumeName = `${projectName}_wp_build`;
|
|
21
|
+
|
|
22
|
+
const composeConfig = {
|
|
23
|
+
services: {},
|
|
24
|
+
networks: {
|
|
25
|
+
'wp-network': {
|
|
26
|
+
driver: 'bridge'
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
volumes: {
|
|
30
|
+
[dbVolumeName]: null,
|
|
31
|
+
[wpVolumeName]: null
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Database service
|
|
36
|
+
composeConfig.services.db = generateDbService(config, dbVolumeName);
|
|
37
|
+
|
|
38
|
+
// WordPress service
|
|
39
|
+
composeConfig.services.wordpress = generateWordPressService(config, wpVolumeName);
|
|
40
|
+
|
|
41
|
+
// S3 proxy service (if enabled)
|
|
42
|
+
if (config.services.s3proxy) {
|
|
43
|
+
composeConfig.services.s3proxy = generateS3ProxyService(config);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Redis service (if enabled)
|
|
47
|
+
if (config.services.redis) {
|
|
48
|
+
composeConfig.services.redis = generateRedisService(config);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return composeConfig;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate database service configuration
|
|
56
|
+
* @param {object} config - buwp-local configuration
|
|
57
|
+
* @param {string} dbVolumeName - Name of the database volume
|
|
58
|
+
* @returns {object} Database service config
|
|
59
|
+
*/
|
|
60
|
+
function generateDbService(config, dbVolumeName) {
|
|
61
|
+
const dbPassword = config.db?.password || 'password';
|
|
62
|
+
const rootPassword = config.db?.rootPassword || 'rootpassword';
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
image: 'mariadb:latest',
|
|
66
|
+
restart: 'always',
|
|
67
|
+
volumes: [`${dbVolumeName}:/var/lib/mysql`],
|
|
68
|
+
environment: {
|
|
69
|
+
MYSQL_DATABASE: 'wordpress',
|
|
70
|
+
MYSQL_USER: 'wordpress',
|
|
71
|
+
MYSQL_PASSWORD: dbPassword,
|
|
72
|
+
MYSQL_ROOT_PASSWORD: rootPassword
|
|
73
|
+
},
|
|
74
|
+
ports: [`${config.ports.db}:3306`],
|
|
75
|
+
networks: ['wp-network']
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Generate WordPress service configuration
|
|
81
|
+
* @param {object} config - buwp-local configuration
|
|
82
|
+
* @param {string} wpVolumeName - Name of the WordPress volume
|
|
83
|
+
* @returns {object} WordPress service config
|
|
84
|
+
*/
|
|
85
|
+
function generateWordPressService(config, wpVolumeName) {
|
|
86
|
+
const depends_on = ['db'];
|
|
87
|
+
|
|
88
|
+
if (config.services.s3proxy) depends_on.push('s3proxy');
|
|
89
|
+
if (config.services.redis) depends_on.push('redis');
|
|
90
|
+
|
|
91
|
+
// Build environment variables
|
|
92
|
+
const environment = {
|
|
93
|
+
WORDPRESS_DB_HOST: 'db:3306',
|
|
94
|
+
WORDPRESS_DB_USER: 'wordpress',
|
|
95
|
+
WORDPRESS_DB_PASSWORD: config.db?.password || 'password',
|
|
96
|
+
WORDPRESS_DB_NAME: 'wordpress',
|
|
97
|
+
WORDPRESS_DEBUG: config.env?.WP_DEBUG || '0',
|
|
98
|
+
SERVER_NAME: config.hostname,
|
|
99
|
+
HTTP_HOST: config.hostname,
|
|
100
|
+
MULTISITE: config.multisite ? 'true' : 'false',
|
|
101
|
+
XDEBUG: config.env?.XDEBUG || 'false',
|
|
102
|
+
WP_CLI_ALLOW_ROOT: 'true',
|
|
103
|
+
TZ: 'America/New_York'
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Add Shibboleth config if enabled
|
|
107
|
+
if (config.services.shibboleth) {
|
|
108
|
+
environment.SP_ENTITY_ID = config.shibboleth?.entityId || '';
|
|
109
|
+
environment.IDP_ENTITY_ID = config.shibboleth?.idpEntityId || '';
|
|
110
|
+
environment.SHIB_IDP_LOGOUT = config.shibboleth?.idpLogout || '';
|
|
111
|
+
environment.SHIB_SP_KEY = config.shibboleth?.spKey || '';
|
|
112
|
+
environment.SHIB_SP_CERT = config.shibboleth?.spCert || '';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Add S3 config if enabled
|
|
116
|
+
if (config.services.s3proxy) {
|
|
117
|
+
environment.S3PROXY_HOST = 'http://s3proxy:8080';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Add Redis config if enabled
|
|
121
|
+
if (config.services.redis) {
|
|
122
|
+
environment.REDIS_HOST = 'redis';
|
|
123
|
+
environment.REDIS_PORT = '6379';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Build WordPress config extra
|
|
127
|
+
let wpConfigExtra = '';
|
|
128
|
+
|
|
129
|
+
if (config.multisite) {
|
|
130
|
+
wpConfigExtra += "define('MULTISITE', true);\n";
|
|
131
|
+
wpConfigExtra += "define('SUBDOMAIN_INSTALL', false);\n";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (config.services.s3proxy && config.s3) {
|
|
135
|
+
wpConfigExtra += `define('S3_UPLOADS_BUCKET', '${config.s3.bucket || ''}');\n`;
|
|
136
|
+
wpConfigExtra += `define('S3_UPLOADS_REGION', '${config.s3.region || 'us-east-1'}');\n`;
|
|
137
|
+
wpConfigExtra += `define('S3_UPLOADS_KEY', '${config.s3.accessKeyId || ''}');\n`;
|
|
138
|
+
wpConfigExtra += `define('S3_UPLOADS_SECRET', '${config.s3.secretAccessKey || ''}');\n`;
|
|
139
|
+
wpConfigExtra += `define('ACCESS_RULES_TABLE', '${config.s3.accessRulesTable || ''}');\n`;
|
|
140
|
+
wpConfigExtra += "define('S3_UPLOADS_OBJECT_ACL', null);\n";
|
|
141
|
+
wpConfigExtra += "define('S3_UPLOADS_AUTOENABLE', true);\n";
|
|
142
|
+
wpConfigExtra += "define('S3_UPLOADS_DISABLE_REPLACE_UPLOAD_URL', true);\n";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Add BU_INCLUDES_PATH definition; this seems bad and should be unwound, but various things depend on it right now.
|
|
146
|
+
wpConfigExtra += `define( 'BU_INCLUDES_PATH', '/var/www/html/bu-includes' );\n`;
|
|
147
|
+
|
|
148
|
+
// Add custom env vars
|
|
149
|
+
Object.entries(config.env || {}).forEach(([key, value]) => {
|
|
150
|
+
if (!environment[key]) {
|
|
151
|
+
environment[key] = String(value);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (wpConfigExtra) {
|
|
156
|
+
environment.WORDPRESS_CONFIG_EXTRA = wpConfigExtra;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Build volumes array
|
|
160
|
+
const volumes = [`${wpVolumeName}:/var/www/html`];
|
|
161
|
+
|
|
162
|
+
// Add custom mappings
|
|
163
|
+
if (config.mappings && Array.isArray(config.mappings)) {
|
|
164
|
+
config.mappings.forEach(mapping => {
|
|
165
|
+
const localPath = path.resolve(mapping.local);
|
|
166
|
+
volumes.push(`${localPath}:${mapping.container}`);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
image: config.image,
|
|
172
|
+
depends_on,
|
|
173
|
+
restart: 'always',
|
|
174
|
+
ports: [
|
|
175
|
+
`${config.ports.http}:80`,
|
|
176
|
+
`${config.ports.https}:443`
|
|
177
|
+
],
|
|
178
|
+
hostname: config.hostname,
|
|
179
|
+
environment,
|
|
180
|
+
volumes,
|
|
181
|
+
networks: ['wp-network']
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Generate S3 proxy service configuration
|
|
187
|
+
* @param {object} config - buwp-local configuration
|
|
188
|
+
* @returns {object} S3 proxy service config
|
|
189
|
+
*/
|
|
190
|
+
function generateS3ProxyService(config) {
|
|
191
|
+
const region = config.olap?.region || config.s3?.region || 'us-east-1';
|
|
192
|
+
const olapName = config.olap?.name || '';
|
|
193
|
+
const olapAcctNbr = config.olap?.accountNumber || '';
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
image: 'public.ecr.aws/bostonuniversity-nonprod/aws-sigv4-proxy',
|
|
197
|
+
restart: 'always',
|
|
198
|
+
command: [
|
|
199
|
+
'-v',
|
|
200
|
+
'--name',
|
|
201
|
+
's3-object-lambda',
|
|
202
|
+
'--region',
|
|
203
|
+
region,
|
|
204
|
+
'--no-verify-ssl',
|
|
205
|
+
'--host',
|
|
206
|
+
`${olapName}-${olapAcctNbr}.s3-object-lambda.${region}.amazonaws.com`
|
|
207
|
+
],
|
|
208
|
+
environment: {
|
|
209
|
+
healthcheck_path: '/s3proxy-healthcheck',
|
|
210
|
+
AWS_ACCESS_KEY_ID: config.s3?.accessKeyId || '',
|
|
211
|
+
AWS_SECRET_ACCESS_KEY: config.s3?.secretAccessKey || '',
|
|
212
|
+
REGION: region
|
|
213
|
+
},
|
|
214
|
+
networks: ['wp-network']
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Generate Redis service configuration
|
|
220
|
+
* @param {object} config - buwp-local configuration
|
|
221
|
+
* @returns {object} Redis service config
|
|
222
|
+
*/
|
|
223
|
+
function generateRedisService(config) {
|
|
224
|
+
return {
|
|
225
|
+
image: 'redis:alpine',
|
|
226
|
+
restart: 'always',
|
|
227
|
+
ports: [`${config.ports.redis}:6379`],
|
|
228
|
+
networks: ['wp-network']
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Write docker-compose.yml file
|
|
234
|
+
* @param {object} composeConfig - Docker Compose configuration
|
|
235
|
+
* @param {string} outputPath - Path to write docker-compose.yml
|
|
236
|
+
* @returns {string} Path to written file
|
|
237
|
+
*/
|
|
238
|
+
function writeComposeFile(composeConfig, outputPath) {
|
|
239
|
+
const yamlContent = yaml.dump(composeConfig, {
|
|
240
|
+
indent: 2,
|
|
241
|
+
lineWidth: -1,
|
|
242
|
+
noRefs: true
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const fileContent = `# Generated by buwp-local
|
|
246
|
+
# Do not edit this file directly - it will be overwritten
|
|
247
|
+
# Edit .buwp-local.json instead
|
|
248
|
+
|
|
249
|
+
${yamlContent}`;
|
|
250
|
+
|
|
251
|
+
fs.writeFileSync(outputPath, fileContent, 'utf8');
|
|
252
|
+
|
|
253
|
+
return outputPath;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Generate and write docker-compose.yml from config
|
|
258
|
+
* @param {object} config - buwp-local configuration
|
|
259
|
+
* @param {string} projectPath - Project directory path
|
|
260
|
+
* @returns {string} Path to generated docker-compose.yml
|
|
261
|
+
*/
|
|
262
|
+
function generateComposeFile(config, projectPath = process.cwd()) {
|
|
263
|
+
// Create .buwp-local directory if it doesn't exist
|
|
264
|
+
const stateDir = path.join(projectPath, '.buwp-local');
|
|
265
|
+
if (!fs.existsSync(stateDir)) {
|
|
266
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const composePath = path.join(stateDir, 'docker-compose.yml');
|
|
270
|
+
const composeConfig = generateComposeConfig(config);
|
|
271
|
+
|
|
272
|
+
return writeComposeFile(composeConfig, composePath);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = {
|
|
276
|
+
generateComposeConfig,
|
|
277
|
+
generateComposeFile,
|
|
278
|
+
writeComposeFile
|
|
279
|
+
};
|