pgpm 4.11.1 → 4.13.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/commands/docker.js +160 -11
- package/commands/env.js +36 -22
- package/esm/commands/docker.js +160 -11
- package/esm/commands/env.js +36 -22
- package/esm/utils/display.js +2 -2
- package/package.json +2 -2
- package/utils/display.d.ts +1 -1
- package/utils/display.js +2 -2
package/commands/docker.js
CHANGED
|
@@ -7,29 +7,55 @@ Docker Command:
|
|
|
7
7
|
|
|
8
8
|
pgpm docker <subcommand> [OPTIONS]
|
|
9
9
|
|
|
10
|
-
Manage
|
|
10
|
+
Manage Docker containers for local development.
|
|
11
|
+
PostgreSQL is always started by default. Additional services can be
|
|
12
|
+
included with the --include flag.
|
|
11
13
|
|
|
12
14
|
Subcommands:
|
|
13
|
-
start Start
|
|
14
|
-
stop Stop
|
|
15
|
+
start Start containers
|
|
16
|
+
stop Stop containers
|
|
17
|
+
ls List available services and their status
|
|
15
18
|
|
|
16
|
-
Options:
|
|
17
|
-
--help, -h Show this help message
|
|
19
|
+
PostgreSQL Options:
|
|
18
20
|
--name <name> Container name (default: postgres)
|
|
19
21
|
--image <image> Docker image (default: constructiveio/postgres-plus:18)
|
|
20
22
|
--port <port> Host port mapping (default: 5432)
|
|
21
23
|
--user <user> PostgreSQL user (default: postgres)
|
|
22
24
|
--password <pass> PostgreSQL password (default: password)
|
|
23
25
|
--shm-size <size> Shared memory size for container (default: 2g)
|
|
24
|
-
|
|
26
|
+
|
|
27
|
+
General Options:
|
|
28
|
+
--help, -h Show this help message
|
|
29
|
+
--recreate Remove and recreate containers on start
|
|
30
|
+
--include <svc> Include additional service (can be repeated)
|
|
31
|
+
|
|
32
|
+
Available Additional Services:
|
|
33
|
+
minio MinIO S3-compatible object storage (port 9000)
|
|
25
34
|
|
|
26
35
|
Examples:
|
|
27
|
-
pgpm docker start Start
|
|
36
|
+
pgpm docker start Start PostgreSQL only
|
|
37
|
+
pgpm docker start --include minio Start PostgreSQL + MinIO
|
|
28
38
|
pgpm docker start --port 5433 Start on custom port
|
|
29
39
|
pgpm docker start --shm-size 4g Start with 4GB shared memory
|
|
30
|
-
pgpm docker start --recreate Remove and recreate
|
|
31
|
-
pgpm docker
|
|
40
|
+
pgpm docker start --recreate Remove and recreate containers
|
|
41
|
+
pgpm docker start --recreate --include minio Recreate PostgreSQL + MinIO
|
|
42
|
+
pgpm docker stop Stop PostgreSQL
|
|
43
|
+
pgpm docker stop --include minio Stop PostgreSQL + MinIO
|
|
44
|
+
pgpm docker ls List services and status
|
|
32
45
|
`;
|
|
46
|
+
const ADDITIONAL_SERVICES = {
|
|
47
|
+
minio: {
|
|
48
|
+
name: 'minio',
|
|
49
|
+
image: 'minio/minio',
|
|
50
|
+
ports: [{ host: 9000, container: 9000 }],
|
|
51
|
+
env: {
|
|
52
|
+
MINIO_ACCESS_KEY: 'minioadmin',
|
|
53
|
+
MINIO_SECRET_KEY: 'minioadmin',
|
|
54
|
+
},
|
|
55
|
+
command: ['server', '/data'],
|
|
56
|
+
volumes: [{ name: 'minio-data', containerPath: '/data' }],
|
|
57
|
+
},
|
|
58
|
+
};
|
|
33
59
|
function run(command, args, options = {}) {
|
|
34
60
|
return new Promise((resolve, reject) => {
|
|
35
61
|
const stdio = options.stdio || 'pipe';
|
|
@@ -165,6 +191,118 @@ async function stopContainer(name) {
|
|
|
165
191
|
await (0, inquirerer_1.cliExitWithError)(`Failed to stop container "${name}"`);
|
|
166
192
|
}
|
|
167
193
|
}
|
|
194
|
+
async function startService(service, recreate) {
|
|
195
|
+
const { name, image, ports, env: serviceEnv, command } = service;
|
|
196
|
+
const exists = await containerExists(name);
|
|
197
|
+
const running = await isContainerRunning(name);
|
|
198
|
+
if (running === true) {
|
|
199
|
+
console.log(`✅ Container "${name}" is already running`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (recreate && exists) {
|
|
203
|
+
console.log(`🗑️ Removing existing container "${name}"...`);
|
|
204
|
+
const removeResult = await run('docker', ['rm', '-f', name], { stdio: 'inherit' });
|
|
205
|
+
if (removeResult.code !== 0) {
|
|
206
|
+
await (0, inquirerer_1.cliExitWithError)(`Failed to remove container "${name}"`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (exists && running === false) {
|
|
211
|
+
console.log(`🔄 Starting existing container "${name}"...`);
|
|
212
|
+
const startResult = await run('docker', ['start', name], { stdio: 'inherit' });
|
|
213
|
+
if (startResult.code === 0) {
|
|
214
|
+
console.log(`✅ Container "${name}" started successfully`);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
await (0, inquirerer_1.cliExitWithError)(`Failed to start container "${name}"`);
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
console.log(`🚀 Creating and starting new container "${name}"...`);
|
|
222
|
+
const runArgs = [
|
|
223
|
+
'run',
|
|
224
|
+
'-d',
|
|
225
|
+
'--name', name,
|
|
226
|
+
];
|
|
227
|
+
for (const [key, value] of Object.entries(serviceEnv)) {
|
|
228
|
+
runArgs.push('-e', `${key}=${value}`);
|
|
229
|
+
}
|
|
230
|
+
for (const portMapping of ports) {
|
|
231
|
+
runArgs.push('-p', `${portMapping.host}:${portMapping.container}`);
|
|
232
|
+
}
|
|
233
|
+
if (service.volumes) {
|
|
234
|
+
for (const vol of service.volumes) {
|
|
235
|
+
runArgs.push('-v', `${vol.name}:${vol.containerPath}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
runArgs.push(image);
|
|
239
|
+
if (command) {
|
|
240
|
+
runArgs.push(...command);
|
|
241
|
+
}
|
|
242
|
+
const runResult = await run('docker', runArgs, { stdio: 'inherit' });
|
|
243
|
+
if (runResult.code === 0) {
|
|
244
|
+
console.log(`✅ Container "${name}" created and started successfully`);
|
|
245
|
+
const portInfo = ports.map(p => `localhost:${p.host}`).join(', ');
|
|
246
|
+
console.log(`📌 ${name} is available at ${portInfo}`);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
const portInfo = ports.map(p => String(p.host)).join(', ');
|
|
250
|
+
await (0, inquirerer_1.cliExitWithError)(`Failed to create container "${name}". Check if port ${portInfo} is already in use.`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function stopService(service) {
|
|
254
|
+
await stopContainer(service.name);
|
|
255
|
+
}
|
|
256
|
+
function parseInclude(args) {
|
|
257
|
+
const include = args.include;
|
|
258
|
+
if (!include)
|
|
259
|
+
return [];
|
|
260
|
+
if (Array.isArray(include))
|
|
261
|
+
return include;
|
|
262
|
+
if (typeof include === 'string')
|
|
263
|
+
return [include];
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
function resolveIncludedServices(includeNames) {
|
|
267
|
+
const services = [];
|
|
268
|
+
for (const name of includeNames) {
|
|
269
|
+
const service = ADDITIONAL_SERVICES[name];
|
|
270
|
+
if (!service) {
|
|
271
|
+
console.warn(`⚠️ Unknown service: "${name}". Available: ${Object.keys(ADDITIONAL_SERVICES).join(', ')}`);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
services.push(service);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return services;
|
|
278
|
+
}
|
|
279
|
+
async function listServices() {
|
|
280
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
281
|
+
console.log('\nAvailable services:\n');
|
|
282
|
+
console.log(' Primary:');
|
|
283
|
+
if (dockerAvailable) {
|
|
284
|
+
const pgRunning = await isContainerRunning('postgres');
|
|
285
|
+
const pgStatus = pgRunning === true ? '\x1b[32mrunning\x1b[0m' : pgRunning === false ? '\x1b[33mstopped\x1b[0m' : '\x1b[90mnot created\x1b[0m';
|
|
286
|
+
console.log(` postgres constructiveio/postgres-plus:18 ${pgStatus}`);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
console.log(' postgres constructiveio/postgres-plus:18 \x1b[90m(docker not available)\x1b[0m');
|
|
290
|
+
}
|
|
291
|
+
console.log('\n Additional (use --include <name>):');
|
|
292
|
+
for (const [key, service] of Object.entries(ADDITIONAL_SERVICES)) {
|
|
293
|
+
if (dockerAvailable) {
|
|
294
|
+
const running = await isContainerRunning(service.name);
|
|
295
|
+
const status = running === true ? '\x1b[32mrunning\x1b[0m' : running === false ? '\x1b[33mstopped\x1b[0m' : '\x1b[90mnot created\x1b[0m';
|
|
296
|
+
const portInfo = service.ports.map(p => String(p.host)).join(', ');
|
|
297
|
+
console.log(` ${key.padEnd(12)}${service.image.padEnd(36)}${status} port ${portInfo}`);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
const portInfo = service.ports.map(p => String(p.host)).join(', ');
|
|
301
|
+
console.log(` ${key.padEnd(12)}${service.image.padEnd(36)}\x1b[90m(docker not available)\x1b[0m port ${portInfo}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
console.log('');
|
|
305
|
+
}
|
|
168
306
|
exports.default = async (argv, _prompter, _options) => {
|
|
169
307
|
if (argv.help || argv.h) {
|
|
170
308
|
console.log(dockerUsageText);
|
|
@@ -174,7 +312,7 @@ exports.default = async (argv, _prompter, _options) => {
|
|
|
174
312
|
const args = newArgv;
|
|
175
313
|
if (!subcommand) {
|
|
176
314
|
console.log(dockerUsageText);
|
|
177
|
-
await (0, inquirerer_1.cliExitWithError)('No subcommand provided. Use "start" or "
|
|
315
|
+
await (0, inquirerer_1.cliExitWithError)('No subcommand provided. Use "start", "stop", or "ls".');
|
|
178
316
|
return;
|
|
179
317
|
}
|
|
180
318
|
const name = args.name || 'postgres';
|
|
@@ -184,15 +322,26 @@ exports.default = async (argv, _prompter, _options) => {
|
|
|
184
322
|
const password = args.password || 'password';
|
|
185
323
|
const shmSize = args['shm-size'] || args.shmSize || '2g';
|
|
186
324
|
const recreate = args.recreate === true;
|
|
325
|
+
const includeNames = parseInclude(args);
|
|
326
|
+
const includedServices = resolveIncludedServices(includeNames);
|
|
187
327
|
switch (subcommand) {
|
|
188
328
|
case 'start':
|
|
189
329
|
await startContainer({ name, image, port, user, password, shmSize, recreate });
|
|
330
|
+
for (const service of includedServices) {
|
|
331
|
+
await startService(service, recreate);
|
|
332
|
+
}
|
|
190
333
|
break;
|
|
191
334
|
case 'stop':
|
|
192
335
|
await stopContainer(name);
|
|
336
|
+
for (const service of includedServices) {
|
|
337
|
+
await stopService(service);
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
case 'ls':
|
|
341
|
+
await listServices();
|
|
193
342
|
break;
|
|
194
343
|
default:
|
|
195
344
|
console.log(dockerUsageText);
|
|
196
|
-
await (0, inquirerer_1.cliExitWithError)(`Unknown subcommand: ${subcommand}. Use "start" or "
|
|
345
|
+
await (0, inquirerer_1.cliExitWithError)(`Unknown subcommand: ${subcommand}. Use "start", "stop", or "ls".`);
|
|
197
346
|
}
|
|
198
347
|
};
|
package/commands/env.js
CHANGED
|
@@ -7,12 +7,15 @@ Environment Command:
|
|
|
7
7
|
|
|
8
8
|
pgpm env [OPTIONS] [COMMAND...]
|
|
9
9
|
|
|
10
|
-
Manage
|
|
10
|
+
Manage environment variables for local development with profile support.
|
|
11
11
|
|
|
12
|
-
Profiles:
|
|
12
|
+
Database Profiles:
|
|
13
13
|
(default) Use local Postgres development profile
|
|
14
14
|
--supabase Use Supabase local development profile
|
|
15
15
|
|
|
16
|
+
Additional Services:
|
|
17
|
+
--minio Include MinIO/S3 environment variables
|
|
18
|
+
|
|
16
19
|
Modes:
|
|
17
20
|
No command Print export statements for shell evaluation
|
|
18
21
|
With command Execute command with environment variables applied
|
|
@@ -20,16 +23,18 @@ Modes:
|
|
|
20
23
|
Options:
|
|
21
24
|
--help, -h Show this help message
|
|
22
25
|
--supabase Use Supabase profile instead of default Postgres
|
|
26
|
+
--minio Include CDN_ENDPOINT, AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION
|
|
23
27
|
|
|
24
28
|
Examples:
|
|
25
29
|
pgpm env Print default Postgres env exports
|
|
26
30
|
pgpm env --supabase Print Supabase env exports
|
|
31
|
+
pgpm env --minio Print Postgres + MinIO env exports
|
|
32
|
+
pgpm env --supabase --minio Print Supabase + MinIO env exports
|
|
27
33
|
eval "$(pgpm env)" Load default Postgres env into shell
|
|
28
|
-
eval "$(pgpm env --
|
|
34
|
+
eval "$(pgpm env --minio)" Load Postgres + MinIO env into shell
|
|
35
|
+
eval "$(pgpm env --supabase --minio)" Load Supabase + MinIO env into shell
|
|
29
36
|
pgpm env pgpm deploy --database db1 Run command with default Postgres env
|
|
30
|
-
pgpm env
|
|
31
|
-
pgpm env --supabase pgpm deploy --database db1 Run command with Supabase env
|
|
32
|
-
pgpm env --supabase createdb mydb Run command with Supabase env
|
|
37
|
+
pgpm env --minio pgpm deploy --database db1 Run command with Postgres + MinIO env
|
|
33
38
|
`;
|
|
34
39
|
const SUPABASE_PROFILE = {
|
|
35
40
|
host: 'localhost',
|
|
@@ -41,24 +46,37 @@ const SUPABASE_PROFILE = {
|
|
|
41
46
|
const DEFAULT_PROFILE = {
|
|
42
47
|
...pg_env_1.defaultPgConfig
|
|
43
48
|
};
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
const MINIO_PROFILE = {
|
|
50
|
+
endpoint: 'http://localhost:9000',
|
|
51
|
+
accessKey: 'minioadmin',
|
|
52
|
+
secretKey: 'minioadmin',
|
|
53
|
+
region: 'us-east-1',
|
|
54
|
+
};
|
|
55
|
+
function configToEnvVars(config, minio) {
|
|
56
|
+
const vars = {
|
|
46
57
|
PGHOST: config.host,
|
|
47
58
|
PGPORT: String(config.port),
|
|
48
59
|
PGUSER: config.user,
|
|
49
60
|
PGPASSWORD: config.password,
|
|
50
61
|
PGDATABASE: config.database
|
|
51
62
|
};
|
|
63
|
+
if (minio) {
|
|
64
|
+
vars.CDN_ENDPOINT = minio.endpoint;
|
|
65
|
+
vars.AWS_ACCESS_KEY = minio.accessKey;
|
|
66
|
+
vars.AWS_SECRET_KEY = minio.secretKey;
|
|
67
|
+
vars.AWS_REGION = minio.region;
|
|
68
|
+
}
|
|
69
|
+
return vars;
|
|
52
70
|
}
|
|
53
|
-
function printExports(config) {
|
|
54
|
-
const envVars = configToEnvVars(config);
|
|
71
|
+
function printExports(config, minio) {
|
|
72
|
+
const envVars = configToEnvVars(config, minio);
|
|
55
73
|
for (const [key, value] of Object.entries(envVars)) {
|
|
56
74
|
console.log(`export ${key}=${value}`);
|
|
57
75
|
}
|
|
58
76
|
}
|
|
59
|
-
function executeCommand(config, command, args) {
|
|
77
|
+
function executeCommand(config, command, args, minio) {
|
|
60
78
|
return new Promise((resolve, reject) => {
|
|
61
|
-
const envVars = configToEnvVars(config);
|
|
79
|
+
const envVars = configToEnvVars(config, minio);
|
|
62
80
|
const env = {
|
|
63
81
|
...process.env,
|
|
64
82
|
...envVars
|
|
@@ -82,33 +100,29 @@ exports.default = async (argv, _prompter) => {
|
|
|
82
100
|
process.exit(0);
|
|
83
101
|
}
|
|
84
102
|
const useSupabase = argv.supabase === true || typeof argv.supabase === 'string';
|
|
103
|
+
const useMinio = argv.minio === true || typeof argv.minio === 'string';
|
|
85
104
|
const profile = useSupabase ? SUPABASE_PROFILE : DEFAULT_PROFILE;
|
|
105
|
+
const minioProfile = useMinio ? MINIO_PROFILE : undefined;
|
|
106
|
+
const knownFlags = ['--supabase', '--minio'];
|
|
86
107
|
const rawArgs = process.argv.slice(2);
|
|
87
108
|
let envIndex = rawArgs.findIndex(arg => arg === 'env');
|
|
88
109
|
if (envIndex === -1) {
|
|
89
110
|
envIndex = 0;
|
|
90
111
|
}
|
|
91
112
|
const argsAfterEnv = rawArgs.slice(envIndex + 1);
|
|
92
|
-
|
|
93
|
-
let commandArgs;
|
|
94
|
-
if (supabaseIndex !== -1) {
|
|
95
|
-
commandArgs = argsAfterEnv.slice(supabaseIndex + 1);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
commandArgs = argsAfterEnv;
|
|
99
|
-
}
|
|
113
|
+
let commandArgs = argsAfterEnv.filter(arg => !knownFlags.includes(arg));
|
|
100
114
|
commandArgs = commandArgs.filter(arg => arg !== '--cwd' && !arg.startsWith('--cwd='));
|
|
101
115
|
const cwdIndex = commandArgs.findIndex(arg => arg === '--cwd');
|
|
102
116
|
if (cwdIndex !== -1 && cwdIndex + 1 < commandArgs.length) {
|
|
103
117
|
commandArgs.splice(cwdIndex, 2);
|
|
104
118
|
}
|
|
105
119
|
if (commandArgs.length === 0) {
|
|
106
|
-
printExports(profile);
|
|
120
|
+
printExports(profile, minioProfile);
|
|
107
121
|
return;
|
|
108
122
|
}
|
|
109
123
|
const [command, ...args] = commandArgs;
|
|
110
124
|
try {
|
|
111
|
-
const exitCode = await executeCommand(profile, command, args);
|
|
125
|
+
const exitCode = await executeCommand(profile, command, args, minioProfile);
|
|
112
126
|
process.exit(exitCode);
|
|
113
127
|
}
|
|
114
128
|
catch (error) {
|
package/esm/commands/docker.js
CHANGED
|
@@ -5,29 +5,55 @@ Docker Command:
|
|
|
5
5
|
|
|
6
6
|
pgpm docker <subcommand> [OPTIONS]
|
|
7
7
|
|
|
8
|
-
Manage
|
|
8
|
+
Manage Docker containers for local development.
|
|
9
|
+
PostgreSQL is always started by default. Additional services can be
|
|
10
|
+
included with the --include flag.
|
|
9
11
|
|
|
10
12
|
Subcommands:
|
|
11
|
-
start Start
|
|
12
|
-
stop Stop
|
|
13
|
+
start Start containers
|
|
14
|
+
stop Stop containers
|
|
15
|
+
ls List available services and their status
|
|
13
16
|
|
|
14
|
-
Options:
|
|
15
|
-
--help, -h Show this help message
|
|
17
|
+
PostgreSQL Options:
|
|
16
18
|
--name <name> Container name (default: postgres)
|
|
17
19
|
--image <image> Docker image (default: constructiveio/postgres-plus:18)
|
|
18
20
|
--port <port> Host port mapping (default: 5432)
|
|
19
21
|
--user <user> PostgreSQL user (default: postgres)
|
|
20
22
|
--password <pass> PostgreSQL password (default: password)
|
|
21
23
|
--shm-size <size> Shared memory size for container (default: 2g)
|
|
22
|
-
|
|
24
|
+
|
|
25
|
+
General Options:
|
|
26
|
+
--help, -h Show this help message
|
|
27
|
+
--recreate Remove and recreate containers on start
|
|
28
|
+
--include <svc> Include additional service (can be repeated)
|
|
29
|
+
|
|
30
|
+
Available Additional Services:
|
|
31
|
+
minio MinIO S3-compatible object storage (port 9000)
|
|
23
32
|
|
|
24
33
|
Examples:
|
|
25
|
-
pgpm docker start Start
|
|
34
|
+
pgpm docker start Start PostgreSQL only
|
|
35
|
+
pgpm docker start --include minio Start PostgreSQL + MinIO
|
|
26
36
|
pgpm docker start --port 5433 Start on custom port
|
|
27
37
|
pgpm docker start --shm-size 4g Start with 4GB shared memory
|
|
28
|
-
pgpm docker start --recreate Remove and recreate
|
|
29
|
-
pgpm docker
|
|
38
|
+
pgpm docker start --recreate Remove and recreate containers
|
|
39
|
+
pgpm docker start --recreate --include minio Recreate PostgreSQL + MinIO
|
|
40
|
+
pgpm docker stop Stop PostgreSQL
|
|
41
|
+
pgpm docker stop --include minio Stop PostgreSQL + MinIO
|
|
42
|
+
pgpm docker ls List services and status
|
|
30
43
|
`;
|
|
44
|
+
const ADDITIONAL_SERVICES = {
|
|
45
|
+
minio: {
|
|
46
|
+
name: 'minio',
|
|
47
|
+
image: 'minio/minio',
|
|
48
|
+
ports: [{ host: 9000, container: 9000 }],
|
|
49
|
+
env: {
|
|
50
|
+
MINIO_ACCESS_KEY: 'minioadmin',
|
|
51
|
+
MINIO_SECRET_KEY: 'minioadmin',
|
|
52
|
+
},
|
|
53
|
+
command: ['server', '/data'],
|
|
54
|
+
volumes: [{ name: 'minio-data', containerPath: '/data' }],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
31
57
|
function run(command, args, options = {}) {
|
|
32
58
|
return new Promise((resolve, reject) => {
|
|
33
59
|
const stdio = options.stdio || 'pipe';
|
|
@@ -163,6 +189,118 @@ async function stopContainer(name) {
|
|
|
163
189
|
await cliExitWithError(`Failed to stop container "${name}"`);
|
|
164
190
|
}
|
|
165
191
|
}
|
|
192
|
+
async function startService(service, recreate) {
|
|
193
|
+
const { name, image, ports, env: serviceEnv, command } = service;
|
|
194
|
+
const exists = await containerExists(name);
|
|
195
|
+
const running = await isContainerRunning(name);
|
|
196
|
+
if (running === true) {
|
|
197
|
+
console.log(`✅ Container "${name}" is already running`);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (recreate && exists) {
|
|
201
|
+
console.log(`🗑️ Removing existing container "${name}"...`);
|
|
202
|
+
const removeResult = await run('docker', ['rm', '-f', name], { stdio: 'inherit' });
|
|
203
|
+
if (removeResult.code !== 0) {
|
|
204
|
+
await cliExitWithError(`Failed to remove container "${name}"`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (exists && running === false) {
|
|
209
|
+
console.log(`🔄 Starting existing container "${name}"...`);
|
|
210
|
+
const startResult = await run('docker', ['start', name], { stdio: 'inherit' });
|
|
211
|
+
if (startResult.code === 0) {
|
|
212
|
+
console.log(`✅ Container "${name}" started successfully`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
await cliExitWithError(`Failed to start container "${name}"`);
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
console.log(`🚀 Creating and starting new container "${name}"...`);
|
|
220
|
+
const runArgs = [
|
|
221
|
+
'run',
|
|
222
|
+
'-d',
|
|
223
|
+
'--name', name,
|
|
224
|
+
];
|
|
225
|
+
for (const [key, value] of Object.entries(serviceEnv)) {
|
|
226
|
+
runArgs.push('-e', `${key}=${value}`);
|
|
227
|
+
}
|
|
228
|
+
for (const portMapping of ports) {
|
|
229
|
+
runArgs.push('-p', `${portMapping.host}:${portMapping.container}`);
|
|
230
|
+
}
|
|
231
|
+
if (service.volumes) {
|
|
232
|
+
for (const vol of service.volumes) {
|
|
233
|
+
runArgs.push('-v', `${vol.name}:${vol.containerPath}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
runArgs.push(image);
|
|
237
|
+
if (command) {
|
|
238
|
+
runArgs.push(...command);
|
|
239
|
+
}
|
|
240
|
+
const runResult = await run('docker', runArgs, { stdio: 'inherit' });
|
|
241
|
+
if (runResult.code === 0) {
|
|
242
|
+
console.log(`✅ Container "${name}" created and started successfully`);
|
|
243
|
+
const portInfo = ports.map(p => `localhost:${p.host}`).join(', ');
|
|
244
|
+
console.log(`📌 ${name} is available at ${portInfo}`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const portInfo = ports.map(p => String(p.host)).join(', ');
|
|
248
|
+
await cliExitWithError(`Failed to create container "${name}". Check if port ${portInfo} is already in use.`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function stopService(service) {
|
|
252
|
+
await stopContainer(service.name);
|
|
253
|
+
}
|
|
254
|
+
function parseInclude(args) {
|
|
255
|
+
const include = args.include;
|
|
256
|
+
if (!include)
|
|
257
|
+
return [];
|
|
258
|
+
if (Array.isArray(include))
|
|
259
|
+
return include;
|
|
260
|
+
if (typeof include === 'string')
|
|
261
|
+
return [include];
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
function resolveIncludedServices(includeNames) {
|
|
265
|
+
const services = [];
|
|
266
|
+
for (const name of includeNames) {
|
|
267
|
+
const service = ADDITIONAL_SERVICES[name];
|
|
268
|
+
if (!service) {
|
|
269
|
+
console.warn(`⚠️ Unknown service: "${name}". Available: ${Object.keys(ADDITIONAL_SERVICES).join(', ')}`);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
services.push(service);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return services;
|
|
276
|
+
}
|
|
277
|
+
async function listServices() {
|
|
278
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
279
|
+
console.log('\nAvailable services:\n');
|
|
280
|
+
console.log(' Primary:');
|
|
281
|
+
if (dockerAvailable) {
|
|
282
|
+
const pgRunning = await isContainerRunning('postgres');
|
|
283
|
+
const pgStatus = pgRunning === true ? '\x1b[32mrunning\x1b[0m' : pgRunning === false ? '\x1b[33mstopped\x1b[0m' : '\x1b[90mnot created\x1b[0m';
|
|
284
|
+
console.log(` postgres constructiveio/postgres-plus:18 ${pgStatus}`);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
console.log(' postgres constructiveio/postgres-plus:18 \x1b[90m(docker not available)\x1b[0m');
|
|
288
|
+
}
|
|
289
|
+
console.log('\n Additional (use --include <name>):');
|
|
290
|
+
for (const [key, service] of Object.entries(ADDITIONAL_SERVICES)) {
|
|
291
|
+
if (dockerAvailable) {
|
|
292
|
+
const running = await isContainerRunning(service.name);
|
|
293
|
+
const status = running === true ? '\x1b[32mrunning\x1b[0m' : running === false ? '\x1b[33mstopped\x1b[0m' : '\x1b[90mnot created\x1b[0m';
|
|
294
|
+
const portInfo = service.ports.map(p => String(p.host)).join(', ');
|
|
295
|
+
console.log(` ${key.padEnd(12)}${service.image.padEnd(36)}${status} port ${portInfo}`);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
const portInfo = service.ports.map(p => String(p.host)).join(', ');
|
|
299
|
+
console.log(` ${key.padEnd(12)}${service.image.padEnd(36)}\x1b[90m(docker not available)\x1b[0m port ${portInfo}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
console.log('');
|
|
303
|
+
}
|
|
166
304
|
export default async (argv, _prompter, _options) => {
|
|
167
305
|
if (argv.help || argv.h) {
|
|
168
306
|
console.log(dockerUsageText);
|
|
@@ -172,7 +310,7 @@ export default async (argv, _prompter, _options) => {
|
|
|
172
310
|
const args = newArgv;
|
|
173
311
|
if (!subcommand) {
|
|
174
312
|
console.log(dockerUsageText);
|
|
175
|
-
await cliExitWithError('No subcommand provided. Use "start" or "
|
|
313
|
+
await cliExitWithError('No subcommand provided. Use "start", "stop", or "ls".');
|
|
176
314
|
return;
|
|
177
315
|
}
|
|
178
316
|
const name = args.name || 'postgres';
|
|
@@ -182,15 +320,26 @@ export default async (argv, _prompter, _options) => {
|
|
|
182
320
|
const password = args.password || 'password';
|
|
183
321
|
const shmSize = args['shm-size'] || args.shmSize || '2g';
|
|
184
322
|
const recreate = args.recreate === true;
|
|
323
|
+
const includeNames = parseInclude(args);
|
|
324
|
+
const includedServices = resolveIncludedServices(includeNames);
|
|
185
325
|
switch (subcommand) {
|
|
186
326
|
case 'start':
|
|
187
327
|
await startContainer({ name, image, port, user, password, shmSize, recreate });
|
|
328
|
+
for (const service of includedServices) {
|
|
329
|
+
await startService(service, recreate);
|
|
330
|
+
}
|
|
188
331
|
break;
|
|
189
332
|
case 'stop':
|
|
190
333
|
await stopContainer(name);
|
|
334
|
+
for (const service of includedServices) {
|
|
335
|
+
await stopService(service);
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
case 'ls':
|
|
339
|
+
await listServices();
|
|
191
340
|
break;
|
|
192
341
|
default:
|
|
193
342
|
console.log(dockerUsageText);
|
|
194
|
-
await cliExitWithError(`Unknown subcommand: ${subcommand}. Use "start" or "
|
|
343
|
+
await cliExitWithError(`Unknown subcommand: ${subcommand}. Use "start", "stop", or "ls".`);
|
|
195
344
|
}
|
|
196
345
|
};
|
package/esm/commands/env.js
CHANGED
|
@@ -5,12 +5,15 @@ Environment Command:
|
|
|
5
5
|
|
|
6
6
|
pgpm env [OPTIONS] [COMMAND...]
|
|
7
7
|
|
|
8
|
-
Manage
|
|
8
|
+
Manage environment variables for local development with profile support.
|
|
9
9
|
|
|
10
|
-
Profiles:
|
|
10
|
+
Database Profiles:
|
|
11
11
|
(default) Use local Postgres development profile
|
|
12
12
|
--supabase Use Supabase local development profile
|
|
13
13
|
|
|
14
|
+
Additional Services:
|
|
15
|
+
--minio Include MinIO/S3 environment variables
|
|
16
|
+
|
|
14
17
|
Modes:
|
|
15
18
|
No command Print export statements for shell evaluation
|
|
16
19
|
With command Execute command with environment variables applied
|
|
@@ -18,16 +21,18 @@ Modes:
|
|
|
18
21
|
Options:
|
|
19
22
|
--help, -h Show this help message
|
|
20
23
|
--supabase Use Supabase profile instead of default Postgres
|
|
24
|
+
--minio Include CDN_ENDPOINT, AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION
|
|
21
25
|
|
|
22
26
|
Examples:
|
|
23
27
|
pgpm env Print default Postgres env exports
|
|
24
28
|
pgpm env --supabase Print Supabase env exports
|
|
29
|
+
pgpm env --minio Print Postgres + MinIO env exports
|
|
30
|
+
pgpm env --supabase --minio Print Supabase + MinIO env exports
|
|
25
31
|
eval "$(pgpm env)" Load default Postgres env into shell
|
|
26
|
-
eval "$(pgpm env --
|
|
32
|
+
eval "$(pgpm env --minio)" Load Postgres + MinIO env into shell
|
|
33
|
+
eval "$(pgpm env --supabase --minio)" Load Supabase + MinIO env into shell
|
|
27
34
|
pgpm env pgpm deploy --database db1 Run command with default Postgres env
|
|
28
|
-
pgpm env
|
|
29
|
-
pgpm env --supabase pgpm deploy --database db1 Run command with Supabase env
|
|
30
|
-
pgpm env --supabase createdb mydb Run command with Supabase env
|
|
35
|
+
pgpm env --minio pgpm deploy --database db1 Run command with Postgres + MinIO env
|
|
31
36
|
`;
|
|
32
37
|
const SUPABASE_PROFILE = {
|
|
33
38
|
host: 'localhost',
|
|
@@ -39,24 +44,37 @@ const SUPABASE_PROFILE = {
|
|
|
39
44
|
const DEFAULT_PROFILE = {
|
|
40
45
|
...defaultPgConfig
|
|
41
46
|
};
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
const MINIO_PROFILE = {
|
|
48
|
+
endpoint: 'http://localhost:9000',
|
|
49
|
+
accessKey: 'minioadmin',
|
|
50
|
+
secretKey: 'minioadmin',
|
|
51
|
+
region: 'us-east-1',
|
|
52
|
+
};
|
|
53
|
+
function configToEnvVars(config, minio) {
|
|
54
|
+
const vars = {
|
|
44
55
|
PGHOST: config.host,
|
|
45
56
|
PGPORT: String(config.port),
|
|
46
57
|
PGUSER: config.user,
|
|
47
58
|
PGPASSWORD: config.password,
|
|
48
59
|
PGDATABASE: config.database
|
|
49
60
|
};
|
|
61
|
+
if (minio) {
|
|
62
|
+
vars.CDN_ENDPOINT = minio.endpoint;
|
|
63
|
+
vars.AWS_ACCESS_KEY = minio.accessKey;
|
|
64
|
+
vars.AWS_SECRET_KEY = minio.secretKey;
|
|
65
|
+
vars.AWS_REGION = minio.region;
|
|
66
|
+
}
|
|
67
|
+
return vars;
|
|
50
68
|
}
|
|
51
|
-
function printExports(config) {
|
|
52
|
-
const envVars = configToEnvVars(config);
|
|
69
|
+
function printExports(config, minio) {
|
|
70
|
+
const envVars = configToEnvVars(config, minio);
|
|
53
71
|
for (const [key, value] of Object.entries(envVars)) {
|
|
54
72
|
console.log(`export ${key}=${value}`);
|
|
55
73
|
}
|
|
56
74
|
}
|
|
57
|
-
function executeCommand(config, command, args) {
|
|
75
|
+
function executeCommand(config, command, args, minio) {
|
|
58
76
|
return new Promise((resolve, reject) => {
|
|
59
|
-
const envVars = configToEnvVars(config);
|
|
77
|
+
const envVars = configToEnvVars(config, minio);
|
|
60
78
|
const env = {
|
|
61
79
|
...process.env,
|
|
62
80
|
...envVars
|
|
@@ -80,33 +98,29 @@ export default async (argv, _prompter) => {
|
|
|
80
98
|
process.exit(0);
|
|
81
99
|
}
|
|
82
100
|
const useSupabase = argv.supabase === true || typeof argv.supabase === 'string';
|
|
101
|
+
const useMinio = argv.minio === true || typeof argv.minio === 'string';
|
|
83
102
|
const profile = useSupabase ? SUPABASE_PROFILE : DEFAULT_PROFILE;
|
|
103
|
+
const minioProfile = useMinio ? MINIO_PROFILE : undefined;
|
|
104
|
+
const knownFlags = ['--supabase', '--minio'];
|
|
84
105
|
const rawArgs = process.argv.slice(2);
|
|
85
106
|
let envIndex = rawArgs.findIndex(arg => arg === 'env');
|
|
86
107
|
if (envIndex === -1) {
|
|
87
108
|
envIndex = 0;
|
|
88
109
|
}
|
|
89
110
|
const argsAfterEnv = rawArgs.slice(envIndex + 1);
|
|
90
|
-
|
|
91
|
-
let commandArgs;
|
|
92
|
-
if (supabaseIndex !== -1) {
|
|
93
|
-
commandArgs = argsAfterEnv.slice(supabaseIndex + 1);
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
commandArgs = argsAfterEnv;
|
|
97
|
-
}
|
|
111
|
+
let commandArgs = argsAfterEnv.filter(arg => !knownFlags.includes(arg));
|
|
98
112
|
commandArgs = commandArgs.filter(arg => arg !== '--cwd' && !arg.startsWith('--cwd='));
|
|
99
113
|
const cwdIndex = commandArgs.findIndex(arg => arg === '--cwd');
|
|
100
114
|
if (cwdIndex !== -1 && cwdIndex + 1 < commandArgs.length) {
|
|
101
115
|
commandArgs.splice(cwdIndex, 2);
|
|
102
116
|
}
|
|
103
117
|
if (commandArgs.length === 0) {
|
|
104
|
-
printExports(profile);
|
|
118
|
+
printExports(profile, minioProfile);
|
|
105
119
|
return;
|
|
106
120
|
}
|
|
107
121
|
const [command, ...args] = commandArgs;
|
|
108
122
|
try {
|
|
109
|
-
const exitCode = await executeCommand(profile, command, args);
|
|
123
|
+
const exitCode = await executeCommand(profile, command, args, minioProfile);
|
|
110
124
|
process.exit(exitCode);
|
|
111
125
|
}
|
|
112
126
|
catch (error) {
|
package/esm/utils/display.js
CHANGED
|
@@ -39,8 +39,8 @@ export const usageText = `
|
|
|
39
39
|
deps Show change dependencies
|
|
40
40
|
|
|
41
41
|
Development Tools:
|
|
42
|
-
docker Manage
|
|
43
|
-
env Manage
|
|
42
|
+
docker Manage Docker containers (start/stop/ls, --include for additional services)
|
|
43
|
+
env Manage environment variables (--supabase, --minio)
|
|
44
44
|
test-packages Run integration tests on workspace packages
|
|
45
45
|
|
|
46
46
|
Global Options:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgpm",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "PostgreSQL Package Manager - Database migration and package management CLI",
|
|
6
6
|
"main": "index.js",
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"pg",
|
|
77
77
|
"pgsql"
|
|
78
78
|
],
|
|
79
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "0409a02b8af8c76fe607910a23cdb1a8e2d859d7"
|
|
80
80
|
}
|
package/utils/display.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage
|
|
1
|
+
export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage Docker containers (start/stop/ls, --include for additional services)\n env Manage environment variables (--supabase, --minio)\n test-packages Run integration tests on workspace packages\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n\n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n\n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
|
package/utils/display.js
CHANGED
|
@@ -42,8 +42,8 @@ exports.usageText = `
|
|
|
42
42
|
deps Show change dependencies
|
|
43
43
|
|
|
44
44
|
Development Tools:
|
|
45
|
-
docker Manage
|
|
46
|
-
env Manage
|
|
45
|
+
docker Manage Docker containers (start/stop/ls, --include for additional services)
|
|
46
|
+
env Manage environment variables (--supabase, --minio)
|
|
47
47
|
test-packages Run integration tests on workspace packages
|
|
48
48
|
|
|
49
49
|
Global Options:
|