pgpm 0.2.0 → 0.2.2
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/README.md +20 -4
- package/commands/docker.d.ts +3 -0
- package/commands/docker.js +194 -0
- package/commands/env.d.ts +4 -0
- package/commands/env.js +124 -0
- package/commands.js +4 -0
- package/esm/commands/docker.js +192 -0
- package/esm/commands/env.js +122 -0
- package/esm/commands.js +4 -0
- package/esm/index.js +2 -0
- package/index.d.ts +2 -0
- package/index.js +5 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -25,14 +25,17 @@ npm install -g pgpm
|
|
|
25
25
|
### Create Your First Project
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
#
|
|
28
|
+
# 1. Create workspace
|
|
29
29
|
pgpm init --workspace
|
|
30
|
-
cd my-
|
|
30
|
+
cd my-app
|
|
31
31
|
|
|
32
|
-
# Create your first module
|
|
32
|
+
# 2. Create your first module
|
|
33
33
|
pgpm init
|
|
34
34
|
|
|
35
|
-
#
|
|
35
|
+
# 3. Add some SQL migrations to sql/ directory
|
|
36
|
+
pgpm add some_change
|
|
37
|
+
|
|
38
|
+
# 4. Deploy to database
|
|
36
39
|
pgpm deploy --createdb
|
|
37
40
|
```
|
|
38
41
|
|
|
@@ -111,6 +114,19 @@ pgpm install
|
|
|
111
114
|
pgpm deploy --createdb
|
|
112
115
|
```
|
|
113
116
|
|
|
117
|
+
### Testing a pgpm module in a workspace
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# 1. Install dependencies
|
|
121
|
+
pgpm install
|
|
122
|
+
|
|
123
|
+
# 2. Enter the packages/<yourmodule>
|
|
124
|
+
cd packages/yourmodule
|
|
125
|
+
|
|
126
|
+
# 3. Test the module in watch mode
|
|
127
|
+
pnpm test:watch
|
|
128
|
+
```
|
|
129
|
+
|
|
114
130
|
### Database Operations
|
|
115
131
|
|
|
116
132
|
#### `pgpm deploy`
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const child_process_1 = require("child_process");
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const dockerUsageText = `
|
|
6
|
+
Docker Command:
|
|
7
|
+
|
|
8
|
+
pgpm docker <subcommand> [OPTIONS]
|
|
9
|
+
|
|
10
|
+
Manage PostgreSQL Docker containers for local development.
|
|
11
|
+
|
|
12
|
+
Subcommands:
|
|
13
|
+
start Start PostgreSQL container
|
|
14
|
+
stop Stop PostgreSQL container
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--help, -h Show this help message
|
|
18
|
+
--name <name> Container name (default: postgres)
|
|
19
|
+
--image <image> Docker image (default: pyramation/pgvector:13.3-alpine)
|
|
20
|
+
--port <port> Host port mapping (default: 5432)
|
|
21
|
+
--user <user> PostgreSQL user (default: postgres)
|
|
22
|
+
--password <pass> PostgreSQL password (default: password)
|
|
23
|
+
--recreate Remove and recreate container on start
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
pgpm docker start Start default PostgreSQL container
|
|
27
|
+
pgpm docker start --port 5433 Start on custom port
|
|
28
|
+
pgpm docker start --recreate Remove and recreate container
|
|
29
|
+
pgpm docker stop Stop PostgreSQL container
|
|
30
|
+
`;
|
|
31
|
+
function run(command, args, options = {}) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const stdio = options.stdio || 'pipe';
|
|
34
|
+
const child = (0, child_process_1.spawn)(command, args, { stdio });
|
|
35
|
+
let stdout = '';
|
|
36
|
+
let stderr = '';
|
|
37
|
+
if (stdio === 'pipe') {
|
|
38
|
+
child.stdout?.on('data', (data) => {
|
|
39
|
+
stdout += data.toString();
|
|
40
|
+
});
|
|
41
|
+
child.stderr?.on('data', (data) => {
|
|
42
|
+
stderr += data.toString();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
child.on('error', (error) => {
|
|
46
|
+
reject(error);
|
|
47
|
+
});
|
|
48
|
+
child.on('close', (code) => {
|
|
49
|
+
resolve({
|
|
50
|
+
code: code ?? 0,
|
|
51
|
+
stdout: stdout.trim(),
|
|
52
|
+
stderr: stderr.trim()
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function checkDockerAvailable() {
|
|
58
|
+
try {
|
|
59
|
+
const result = await run('docker', ['--version']);
|
|
60
|
+
return result.code === 0;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function isContainerRunning(name) {
|
|
67
|
+
try {
|
|
68
|
+
const result = await run('docker', ['inspect', '-f', '{{.State.Running}}', name]);
|
|
69
|
+
if (result.code === 0) {
|
|
70
|
+
return result.stdout.trim() === 'true';
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function containerExists(name) {
|
|
79
|
+
try {
|
|
80
|
+
const result = await run('docker', ['inspect', name]);
|
|
81
|
+
return result.code === 0;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function startContainer(options) {
|
|
88
|
+
const { name, image, port, user, password, recreate } = options;
|
|
89
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
90
|
+
if (!dockerAvailable) {
|
|
91
|
+
await (0, utils_1.cliExitWithError)('Docker is not installed or not available in PATH. Please install Docker first.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const exists = await containerExists(name);
|
|
95
|
+
const running = await isContainerRunning(name);
|
|
96
|
+
if (running === true) {
|
|
97
|
+
console.log(`✅ Container "${name}" is already running`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (recreate && exists) {
|
|
101
|
+
console.log(`🗑️ Removing existing container "${name}"...`);
|
|
102
|
+
const removeResult = await run('docker', ['rm', '-f', name], { stdio: 'inherit' });
|
|
103
|
+
if (removeResult.code !== 0) {
|
|
104
|
+
await (0, utils_1.cliExitWithError)(`Failed to remove container "${name}"`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (exists && running === false) {
|
|
109
|
+
console.log(`🔄 Starting existing container "${name}"...`);
|
|
110
|
+
const startResult = await run('docker', ['start', name], { stdio: 'inherit' });
|
|
111
|
+
if (startResult.code === 0) {
|
|
112
|
+
console.log(`✅ Container "${name}" started successfully`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
await (0, utils_1.cliExitWithError)(`Failed to start container "${name}"`);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.log(`🚀 Creating and starting new container "${name}"...`);
|
|
120
|
+
const runArgs = [
|
|
121
|
+
'run',
|
|
122
|
+
'-d',
|
|
123
|
+
'--name', name,
|
|
124
|
+
'-e', `POSTGRES_USER=${user}`,
|
|
125
|
+
'-e', `POSTGRES_PASSWORD=${password}`,
|
|
126
|
+
'-p', `${port}:5432`,
|
|
127
|
+
image
|
|
128
|
+
];
|
|
129
|
+
const runResult = await run('docker', runArgs, { stdio: 'inherit' });
|
|
130
|
+
if (runResult.code === 0) {
|
|
131
|
+
console.log(`✅ Container "${name}" created and started successfully`);
|
|
132
|
+
console.log(`📌 PostgreSQL is available at localhost:${port}`);
|
|
133
|
+
console.log(`👤 User: ${user}`);
|
|
134
|
+
console.log(`🔑 Password: ${password}`);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
await (0, utils_1.cliExitWithError)(`Failed to create container "${name}". Check if port ${port} is already in use.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function stopContainer(name) {
|
|
141
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
142
|
+
if (!dockerAvailable) {
|
|
143
|
+
await (0, utils_1.cliExitWithError)('Docker is not installed or not available in PATH. Please install Docker first.');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const exists = await containerExists(name);
|
|
147
|
+
if (!exists) {
|
|
148
|
+
console.log(`ℹ️ Container "${name}" not found`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const running = await isContainerRunning(name);
|
|
152
|
+
if (running === false) {
|
|
153
|
+
console.log(`ℹ️ Container "${name}" is already stopped`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
console.log(`🛑 Stopping container "${name}"...`);
|
|
157
|
+
const stopResult = await run('docker', ['stop', name], { stdio: 'inherit' });
|
|
158
|
+
if (stopResult.code === 0) {
|
|
159
|
+
console.log(`✅ Container "${name}" stopped successfully`);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
await (0, utils_1.cliExitWithError)(`Failed to stop container "${name}"`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.default = async (argv, _prompter, _options) => {
|
|
166
|
+
if (argv.help || argv.h) {
|
|
167
|
+
console.log(dockerUsageText);
|
|
168
|
+
process.exit(0);
|
|
169
|
+
}
|
|
170
|
+
const { first: subcommand, newArgv } = (0, utils_1.extractFirst)(argv);
|
|
171
|
+
const args = newArgv;
|
|
172
|
+
if (!subcommand) {
|
|
173
|
+
console.log(dockerUsageText);
|
|
174
|
+
await (0, utils_1.cliExitWithError)('No subcommand provided. Use "start" or "stop".');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const name = args.name || 'postgres';
|
|
178
|
+
const image = args.image || 'pyramation/pgvector:13.3-alpine';
|
|
179
|
+
const port = typeof args.port === 'number' ? args.port : 5432;
|
|
180
|
+
const user = args.user || 'postgres';
|
|
181
|
+
const password = args.password || 'password';
|
|
182
|
+
const recreate = args.recreate === true;
|
|
183
|
+
switch (subcommand) {
|
|
184
|
+
case 'start':
|
|
185
|
+
await startContainer({ name, image, port, user, password, recreate });
|
|
186
|
+
break;
|
|
187
|
+
case 'stop':
|
|
188
|
+
await stopContainer(name);
|
|
189
|
+
break;
|
|
190
|
+
default:
|
|
191
|
+
console.log(dockerUsageText);
|
|
192
|
+
await (0, utils_1.cliExitWithError)(`Unknown subcommand: ${subcommand}. Use "start" or "stop".`);
|
|
193
|
+
}
|
|
194
|
+
};
|
package/commands/env.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const child_process_1 = require("child_process");
|
|
4
|
+
const pg_env_1 = require("pg-env");
|
|
5
|
+
const envUsageText = `
|
|
6
|
+
Environment Command:
|
|
7
|
+
|
|
8
|
+
pgpm env [OPTIONS] [COMMAND...]
|
|
9
|
+
|
|
10
|
+
Manage PostgreSQL environment variables with profile support.
|
|
11
|
+
|
|
12
|
+
Profiles:
|
|
13
|
+
(default) Use local Postgres development profile
|
|
14
|
+
--supabase Use Supabase local development profile
|
|
15
|
+
|
|
16
|
+
Modes:
|
|
17
|
+
No command Print export statements for shell evaluation
|
|
18
|
+
With command Execute command with environment variables applied
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--help, -h Show this help message
|
|
22
|
+
--supabase Use Supabase profile instead of default Postgres
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
pgpm env Print default Postgres env exports
|
|
26
|
+
pgpm env --supabase Print Supabase env exports
|
|
27
|
+
eval "$(pgpm env)" Load default Postgres env into shell
|
|
28
|
+
eval "$(pgpm env --supabase)" Load Supabase env into shell
|
|
29
|
+
pgpm env lql deploy --database db1 Run command with default Postgres env
|
|
30
|
+
pgpm env createdb mydb Run command with default Postgres env
|
|
31
|
+
pgpm env --supabase lql deploy --database db1 Run command with Supabase env
|
|
32
|
+
pgpm env --supabase createdb mydb Run command with Supabase env
|
|
33
|
+
`;
|
|
34
|
+
const SUPABASE_PROFILE = {
|
|
35
|
+
host: 'localhost',
|
|
36
|
+
port: 54322,
|
|
37
|
+
user: 'supabase_admin',
|
|
38
|
+
password: 'postgres',
|
|
39
|
+
database: 'postgres'
|
|
40
|
+
};
|
|
41
|
+
const DEFAULT_PROFILE = {
|
|
42
|
+
...pg_env_1.defaultPgConfig
|
|
43
|
+
};
|
|
44
|
+
function configToEnvVars(config) {
|
|
45
|
+
return {
|
|
46
|
+
PGHOST: config.host,
|
|
47
|
+
PGPORT: String(config.port),
|
|
48
|
+
PGUSER: config.user,
|
|
49
|
+
PGPASSWORD: config.password,
|
|
50
|
+
PGDATABASE: config.database
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function printExports(config) {
|
|
54
|
+
const envVars = configToEnvVars(config);
|
|
55
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
56
|
+
const escapedValue = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
57
|
+
console.log(`export ${key}="${escapedValue}"`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function executeCommand(config, command, args) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const envVars = configToEnvVars(config);
|
|
63
|
+
const env = {
|
|
64
|
+
...process.env,
|
|
65
|
+
...envVars
|
|
66
|
+
};
|
|
67
|
+
const child = (0, child_process_1.spawn)(command, args, {
|
|
68
|
+
env,
|
|
69
|
+
stdio: 'inherit',
|
|
70
|
+
shell: false
|
|
71
|
+
});
|
|
72
|
+
child.on('error', (error) => {
|
|
73
|
+
reject(error);
|
|
74
|
+
});
|
|
75
|
+
child.on('close', (code) => {
|
|
76
|
+
resolve(code ?? 0);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
exports.default = async (argv, _prompter) => {
|
|
81
|
+
if (argv.help || argv.h) {
|
|
82
|
+
console.log(envUsageText);
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
const useSupabase = argv.supabase === true || typeof argv.supabase === 'string';
|
|
86
|
+
const profile = useSupabase ? SUPABASE_PROFILE : DEFAULT_PROFILE;
|
|
87
|
+
const rawArgs = process.argv.slice(2);
|
|
88
|
+
let envIndex = rawArgs.findIndex(arg => arg === 'env');
|
|
89
|
+
if (envIndex === -1) {
|
|
90
|
+
envIndex = 0;
|
|
91
|
+
}
|
|
92
|
+
const argsAfterEnv = rawArgs.slice(envIndex + 1);
|
|
93
|
+
const supabaseIndex = argsAfterEnv.findIndex(arg => arg === '--supabase');
|
|
94
|
+
let commandArgs;
|
|
95
|
+
if (supabaseIndex !== -1) {
|
|
96
|
+
commandArgs = argsAfterEnv.slice(supabaseIndex + 1);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
commandArgs = argsAfterEnv;
|
|
100
|
+
}
|
|
101
|
+
commandArgs = commandArgs.filter(arg => arg !== '--cwd' && !arg.startsWith('--cwd='));
|
|
102
|
+
const cwdIndex = commandArgs.findIndex(arg => arg === '--cwd');
|
|
103
|
+
if (cwdIndex !== -1 && cwdIndex + 1 < commandArgs.length) {
|
|
104
|
+
commandArgs.splice(cwdIndex, 2);
|
|
105
|
+
}
|
|
106
|
+
if (commandArgs.length === 0) {
|
|
107
|
+
printExports(profile);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const [command, ...args] = commandArgs;
|
|
111
|
+
try {
|
|
112
|
+
const exitCode = await executeCommand(profile, command, args);
|
|
113
|
+
process.exit(exitCode);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof Error) {
|
|
117
|
+
console.error(`Error executing command: ${error.message}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.error(`Error executing command: ${String(error)}`);
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
};
|
package/commands.js
CHANGED
|
@@ -10,6 +10,8 @@ const admin_users_1 = __importDefault(require("./commands/admin-users"));
|
|
|
10
10
|
const analyze_1 = __importDefault(require("./commands/analyze"));
|
|
11
11
|
const clear_1 = __importDefault(require("./commands/clear"));
|
|
12
12
|
const deploy_1 = __importDefault(require("./commands/deploy"));
|
|
13
|
+
const docker_1 = __importDefault(require("./commands/docker"));
|
|
14
|
+
const env_1 = __importDefault(require("./commands/env"));
|
|
13
15
|
const export_1 = __importDefault(require("./commands/export"));
|
|
14
16
|
const extension_1 = __importDefault(require("./commands/extension"));
|
|
15
17
|
const init_1 = __importDefault(require("./commands/init"));
|
|
@@ -43,6 +45,8 @@ const createPgpmCommandMap = (skipPgTeardown = false) => {
|
|
|
43
45
|
'admin-users': pgt(admin_users_1.default),
|
|
44
46
|
clear: pgt(clear_1.default),
|
|
45
47
|
deploy: pgt(deploy_1.default),
|
|
48
|
+
docker: docker_1.default,
|
|
49
|
+
env: env_1.default,
|
|
46
50
|
verify: pgt(verify_1.default),
|
|
47
51
|
revert: pgt(revert_1.default),
|
|
48
52
|
remove: pgt(remove_1.default),
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { cliExitWithError, extractFirst } from '../utils';
|
|
3
|
+
const dockerUsageText = `
|
|
4
|
+
Docker Command:
|
|
5
|
+
|
|
6
|
+
pgpm docker <subcommand> [OPTIONS]
|
|
7
|
+
|
|
8
|
+
Manage PostgreSQL Docker containers for local development.
|
|
9
|
+
|
|
10
|
+
Subcommands:
|
|
11
|
+
start Start PostgreSQL container
|
|
12
|
+
stop Stop PostgreSQL container
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--help, -h Show this help message
|
|
16
|
+
--name <name> Container name (default: postgres)
|
|
17
|
+
--image <image> Docker image (default: pyramation/pgvector:13.3-alpine)
|
|
18
|
+
--port <port> Host port mapping (default: 5432)
|
|
19
|
+
--user <user> PostgreSQL user (default: postgres)
|
|
20
|
+
--password <pass> PostgreSQL password (default: password)
|
|
21
|
+
--recreate Remove and recreate container on start
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
pgpm docker start Start default PostgreSQL container
|
|
25
|
+
pgpm docker start --port 5433 Start on custom port
|
|
26
|
+
pgpm docker start --recreate Remove and recreate container
|
|
27
|
+
pgpm docker stop Stop PostgreSQL container
|
|
28
|
+
`;
|
|
29
|
+
function run(command, args, options = {}) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const stdio = options.stdio || 'pipe';
|
|
32
|
+
const child = spawn(command, args, { stdio });
|
|
33
|
+
let stdout = '';
|
|
34
|
+
let stderr = '';
|
|
35
|
+
if (stdio === 'pipe') {
|
|
36
|
+
child.stdout?.on('data', (data) => {
|
|
37
|
+
stdout += data.toString();
|
|
38
|
+
});
|
|
39
|
+
child.stderr?.on('data', (data) => {
|
|
40
|
+
stderr += data.toString();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
child.on('error', (error) => {
|
|
44
|
+
reject(error);
|
|
45
|
+
});
|
|
46
|
+
child.on('close', (code) => {
|
|
47
|
+
resolve({
|
|
48
|
+
code: code ?? 0,
|
|
49
|
+
stdout: stdout.trim(),
|
|
50
|
+
stderr: stderr.trim()
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function checkDockerAvailable() {
|
|
56
|
+
try {
|
|
57
|
+
const result = await run('docker', ['--version']);
|
|
58
|
+
return result.code === 0;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function isContainerRunning(name) {
|
|
65
|
+
try {
|
|
66
|
+
const result = await run('docker', ['inspect', '-f', '{{.State.Running}}', name]);
|
|
67
|
+
if (result.code === 0) {
|
|
68
|
+
return result.stdout.trim() === 'true';
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function containerExists(name) {
|
|
77
|
+
try {
|
|
78
|
+
const result = await run('docker', ['inspect', name]);
|
|
79
|
+
return result.code === 0;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function startContainer(options) {
|
|
86
|
+
const { name, image, port, user, password, recreate } = options;
|
|
87
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
88
|
+
if (!dockerAvailable) {
|
|
89
|
+
await cliExitWithError('Docker is not installed or not available in PATH. Please install Docker first.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const exists = await containerExists(name);
|
|
93
|
+
const running = await isContainerRunning(name);
|
|
94
|
+
if (running === true) {
|
|
95
|
+
console.log(`✅ Container "${name}" is already running`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (recreate && exists) {
|
|
99
|
+
console.log(`🗑️ Removing existing container "${name}"...`);
|
|
100
|
+
const removeResult = await run('docker', ['rm', '-f', name], { stdio: 'inherit' });
|
|
101
|
+
if (removeResult.code !== 0) {
|
|
102
|
+
await cliExitWithError(`Failed to remove container "${name}"`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (exists && running === false) {
|
|
107
|
+
console.log(`🔄 Starting existing container "${name}"...`);
|
|
108
|
+
const startResult = await run('docker', ['start', name], { stdio: 'inherit' });
|
|
109
|
+
if (startResult.code === 0) {
|
|
110
|
+
console.log(`✅ Container "${name}" started successfully`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
await cliExitWithError(`Failed to start container "${name}"`);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
console.log(`🚀 Creating and starting new container "${name}"...`);
|
|
118
|
+
const runArgs = [
|
|
119
|
+
'run',
|
|
120
|
+
'-d',
|
|
121
|
+
'--name', name,
|
|
122
|
+
'-e', `POSTGRES_USER=${user}`,
|
|
123
|
+
'-e', `POSTGRES_PASSWORD=${password}`,
|
|
124
|
+
'-p', `${port}:5432`,
|
|
125
|
+
image
|
|
126
|
+
];
|
|
127
|
+
const runResult = await run('docker', runArgs, { stdio: 'inherit' });
|
|
128
|
+
if (runResult.code === 0) {
|
|
129
|
+
console.log(`✅ Container "${name}" created and started successfully`);
|
|
130
|
+
console.log(`📌 PostgreSQL is available at localhost:${port}`);
|
|
131
|
+
console.log(`👤 User: ${user}`);
|
|
132
|
+
console.log(`🔑 Password: ${password}`);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
await cliExitWithError(`Failed to create container "${name}". Check if port ${port} is already in use.`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function stopContainer(name) {
|
|
139
|
+
const dockerAvailable = await checkDockerAvailable();
|
|
140
|
+
if (!dockerAvailable) {
|
|
141
|
+
await cliExitWithError('Docker is not installed or not available in PATH. Please install Docker first.');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const exists = await containerExists(name);
|
|
145
|
+
if (!exists) {
|
|
146
|
+
console.log(`ℹ️ Container "${name}" not found`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const running = await isContainerRunning(name);
|
|
150
|
+
if (running === false) {
|
|
151
|
+
console.log(`ℹ️ Container "${name}" is already stopped`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
console.log(`🛑 Stopping container "${name}"...`);
|
|
155
|
+
const stopResult = await run('docker', ['stop', name], { stdio: 'inherit' });
|
|
156
|
+
if (stopResult.code === 0) {
|
|
157
|
+
console.log(`✅ Container "${name}" stopped successfully`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
await cliExitWithError(`Failed to stop container "${name}"`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export default async (argv, _prompter, _options) => {
|
|
164
|
+
if (argv.help || argv.h) {
|
|
165
|
+
console.log(dockerUsageText);
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
const { first: subcommand, newArgv } = extractFirst(argv);
|
|
169
|
+
const args = newArgv;
|
|
170
|
+
if (!subcommand) {
|
|
171
|
+
console.log(dockerUsageText);
|
|
172
|
+
await cliExitWithError('No subcommand provided. Use "start" or "stop".');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const name = args.name || 'postgres';
|
|
176
|
+
const image = args.image || 'pyramation/pgvector:13.3-alpine';
|
|
177
|
+
const port = typeof args.port === 'number' ? args.port : 5432;
|
|
178
|
+
const user = args.user || 'postgres';
|
|
179
|
+
const password = args.password || 'password';
|
|
180
|
+
const recreate = args.recreate === true;
|
|
181
|
+
switch (subcommand) {
|
|
182
|
+
case 'start':
|
|
183
|
+
await startContainer({ name, image, port, user, password, recreate });
|
|
184
|
+
break;
|
|
185
|
+
case 'stop':
|
|
186
|
+
await stopContainer(name);
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
console.log(dockerUsageText);
|
|
190
|
+
await cliExitWithError(`Unknown subcommand: ${subcommand}. Use "start" or "stop".`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { defaultPgConfig } from 'pg-env';
|
|
3
|
+
const envUsageText = `
|
|
4
|
+
Environment Command:
|
|
5
|
+
|
|
6
|
+
pgpm env [OPTIONS] [COMMAND...]
|
|
7
|
+
|
|
8
|
+
Manage PostgreSQL environment variables with profile support.
|
|
9
|
+
|
|
10
|
+
Profiles:
|
|
11
|
+
(default) Use local Postgres development profile
|
|
12
|
+
--supabase Use Supabase local development profile
|
|
13
|
+
|
|
14
|
+
Modes:
|
|
15
|
+
No command Print export statements for shell evaluation
|
|
16
|
+
With command Execute command with environment variables applied
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--help, -h Show this help message
|
|
20
|
+
--supabase Use Supabase profile instead of default Postgres
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
pgpm env Print default Postgres env exports
|
|
24
|
+
pgpm env --supabase Print Supabase env exports
|
|
25
|
+
eval "$(pgpm env)" Load default Postgres env into shell
|
|
26
|
+
eval "$(pgpm env --supabase)" Load Supabase env into shell
|
|
27
|
+
pgpm env lql deploy --database db1 Run command with default Postgres env
|
|
28
|
+
pgpm env createdb mydb Run command with default Postgres env
|
|
29
|
+
pgpm env --supabase lql deploy --database db1 Run command with Supabase env
|
|
30
|
+
pgpm env --supabase createdb mydb Run command with Supabase env
|
|
31
|
+
`;
|
|
32
|
+
const SUPABASE_PROFILE = {
|
|
33
|
+
host: 'localhost',
|
|
34
|
+
port: 54322,
|
|
35
|
+
user: 'supabase_admin',
|
|
36
|
+
password: 'postgres',
|
|
37
|
+
database: 'postgres'
|
|
38
|
+
};
|
|
39
|
+
const DEFAULT_PROFILE = {
|
|
40
|
+
...defaultPgConfig
|
|
41
|
+
};
|
|
42
|
+
function configToEnvVars(config) {
|
|
43
|
+
return {
|
|
44
|
+
PGHOST: config.host,
|
|
45
|
+
PGPORT: String(config.port),
|
|
46
|
+
PGUSER: config.user,
|
|
47
|
+
PGPASSWORD: config.password,
|
|
48
|
+
PGDATABASE: config.database
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function printExports(config) {
|
|
52
|
+
const envVars = configToEnvVars(config);
|
|
53
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
54
|
+
const escapedValue = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
55
|
+
console.log(`export ${key}="${escapedValue}"`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function executeCommand(config, command, args) {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const envVars = configToEnvVars(config);
|
|
61
|
+
const env = {
|
|
62
|
+
...process.env,
|
|
63
|
+
...envVars
|
|
64
|
+
};
|
|
65
|
+
const child = spawn(command, args, {
|
|
66
|
+
env,
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
shell: false
|
|
69
|
+
});
|
|
70
|
+
child.on('error', (error) => {
|
|
71
|
+
reject(error);
|
|
72
|
+
});
|
|
73
|
+
child.on('close', (code) => {
|
|
74
|
+
resolve(code ?? 0);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export default async (argv, _prompter) => {
|
|
79
|
+
if (argv.help || argv.h) {
|
|
80
|
+
console.log(envUsageText);
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
const useSupabase = argv.supabase === true || typeof argv.supabase === 'string';
|
|
84
|
+
const profile = useSupabase ? SUPABASE_PROFILE : DEFAULT_PROFILE;
|
|
85
|
+
const rawArgs = process.argv.slice(2);
|
|
86
|
+
let envIndex = rawArgs.findIndex(arg => arg === 'env');
|
|
87
|
+
if (envIndex === -1) {
|
|
88
|
+
envIndex = 0;
|
|
89
|
+
}
|
|
90
|
+
const argsAfterEnv = rawArgs.slice(envIndex + 1);
|
|
91
|
+
const supabaseIndex = argsAfterEnv.findIndex(arg => arg === '--supabase');
|
|
92
|
+
let commandArgs;
|
|
93
|
+
if (supabaseIndex !== -1) {
|
|
94
|
+
commandArgs = argsAfterEnv.slice(supabaseIndex + 1);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
commandArgs = argsAfterEnv;
|
|
98
|
+
}
|
|
99
|
+
commandArgs = commandArgs.filter(arg => arg !== '--cwd' && !arg.startsWith('--cwd='));
|
|
100
|
+
const cwdIndex = commandArgs.findIndex(arg => arg === '--cwd');
|
|
101
|
+
if (cwdIndex !== -1 && cwdIndex + 1 < commandArgs.length) {
|
|
102
|
+
commandArgs.splice(cwdIndex, 2);
|
|
103
|
+
}
|
|
104
|
+
if (commandArgs.length === 0) {
|
|
105
|
+
printExports(profile);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const [command, ...args] = commandArgs;
|
|
109
|
+
try {
|
|
110
|
+
const exitCode = await executeCommand(profile, command, args);
|
|
111
|
+
process.exit(exitCode);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (error instanceof Error) {
|
|
115
|
+
console.error(`Error executing command: ${error.message}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.error(`Error executing command: ${String(error)}`);
|
|
119
|
+
}
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
};
|
package/esm/commands.js
CHANGED
|
@@ -4,6 +4,8 @@ import adminUsers from './commands/admin-users';
|
|
|
4
4
|
import analyze from './commands/analyze';
|
|
5
5
|
import clear from './commands/clear';
|
|
6
6
|
import deploy from './commands/deploy';
|
|
7
|
+
import docker from './commands/docker';
|
|
8
|
+
import env from './commands/env';
|
|
7
9
|
import _export from './commands/export';
|
|
8
10
|
import extension from './commands/extension';
|
|
9
11
|
import init from './commands/init';
|
|
@@ -37,6 +39,8 @@ export const createPgpmCommandMap = (skipPgTeardown = false) => {
|
|
|
37
39
|
'admin-users': pgt(adminUsers),
|
|
38
40
|
clear: pgt(clear),
|
|
39
41
|
deploy: pgt(deploy),
|
|
42
|
+
docker,
|
|
43
|
+
env,
|
|
40
44
|
verify: pgt(verify),
|
|
41
45
|
revert: pgt(revert),
|
|
42
46
|
remove: pgt(remove),
|
package/esm/index.js
CHANGED
|
@@ -9,6 +9,8 @@ export { default as adminUsers } from './commands/admin-users';
|
|
|
9
9
|
export { default as analyze } from './commands/analyze';
|
|
10
10
|
export { default as clear } from './commands/clear';
|
|
11
11
|
export { default as deploy } from './commands/deploy';
|
|
12
|
+
export { default as docker } from './commands/docker';
|
|
13
|
+
export { default as env } from './commands/env';
|
|
12
14
|
export { default as _export } from './commands/export';
|
|
13
15
|
export { default as extension } from './commands/extension';
|
|
14
16
|
export { default as install } from './commands/install';
|
package/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export { default as adminUsers } from './commands/admin-users';
|
|
|
7
7
|
export { default as analyze } from './commands/analyze';
|
|
8
8
|
export { default as clear } from './commands/clear';
|
|
9
9
|
export { default as deploy } from './commands/deploy';
|
|
10
|
+
export { default as docker } from './commands/docker';
|
|
11
|
+
export { default as env } from './commands/env';
|
|
10
12
|
export { default as _export } from './commands/export';
|
|
11
13
|
export { default as extension } from './commands/extension';
|
|
12
14
|
export { default as install } from './commands/install';
|
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
18
18
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.options = exports.verify = exports.tag = exports.revert = exports.renameCmd = exports.remove = exports.plan = exports._package = exports.migrate = exports.kill = exports.install = exports.extension = exports._export = exports.deploy = exports.clear = exports.analyze = exports.adminUsers = exports.add = exports.createPgpmCommandMap = void 0;
|
|
21
|
+
exports.options = exports.verify = exports.tag = exports.revert = exports.renameCmd = exports.remove = exports.plan = exports._package = exports.migrate = exports.kill = exports.install = exports.extension = exports._export = exports.env = exports.docker = exports.deploy = exports.clear = exports.analyze = exports.adminUsers = exports.add = exports.createPgpmCommandMap = void 0;
|
|
22
22
|
const fs_1 = require("fs");
|
|
23
23
|
const inquirerer_1 = require("inquirerer");
|
|
24
24
|
const path_1 = require("path");
|
|
@@ -34,6 +34,10 @@ var clear_1 = require("./commands/clear");
|
|
|
34
34
|
Object.defineProperty(exports, "clear", { enumerable: true, get: function () { return __importDefault(clear_1).default; } });
|
|
35
35
|
var deploy_1 = require("./commands/deploy");
|
|
36
36
|
Object.defineProperty(exports, "deploy", { enumerable: true, get: function () { return __importDefault(deploy_1).default; } });
|
|
37
|
+
var docker_1 = require("./commands/docker");
|
|
38
|
+
Object.defineProperty(exports, "docker", { enumerable: true, get: function () { return __importDefault(docker_1).default; } });
|
|
39
|
+
var env_1 = require("./commands/env");
|
|
40
|
+
Object.defineProperty(exports, "env", { enumerable: true, get: function () { return __importDefault(env_1).default; } });
|
|
37
41
|
var export_1 = require("./commands/export");
|
|
38
42
|
Object.defineProperty(exports, "_export", { enumerable: true, get: function () { return __importDefault(export_1).default; } });
|
|
39
43
|
var extension_1 = require("./commands/extension");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgpm",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"author": "Dan Lynch <pyramation@gmail.com>",
|
|
5
5
|
"description": "PostgreSQL Package Manager - Database migration and package management CLI",
|
|
6
6
|
"main": "index.js",
|
|
@@ -45,16 +45,16 @@
|
|
|
45
45
|
"ts-node": "^10.9.2"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@launchql/core": "^2.15.
|
|
48
|
+
"@launchql/core": "^2.15.1",
|
|
49
49
|
"@launchql/env": "^2.5.0",
|
|
50
|
-
"@launchql/logger": "^1.1.
|
|
50
|
+
"@launchql/logger": "^1.1.5",
|
|
51
51
|
"@launchql/templatizer": "^2.5.0",
|
|
52
52
|
"@launchql/types": "^2.8.0",
|
|
53
53
|
"chalk": "^4.1.0",
|
|
54
54
|
"inquirerer": "^2.0.8",
|
|
55
55
|
"js-yaml": "^4.1.0",
|
|
56
56
|
"minimist": "^1.2.8",
|
|
57
|
-
"pg-cache": "^1.4.
|
|
57
|
+
"pg-cache": "^1.4.1",
|
|
58
58
|
"pg-env": "^1.1.2",
|
|
59
59
|
"shelljs": "^0.9.2"
|
|
60
60
|
},
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"pg",
|
|
71
71
|
"pgsql"
|
|
72
72
|
],
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "e1890f22bf61282f1cced2026a57b161f137753d"
|
|
74
74
|
}
|