spindb 0.5.2 → 0.5.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/README.md +137 -8
- package/cli/commands/connect.ts +8 -4
- package/cli/commands/create.ts +106 -67
- package/cli/commands/deps.ts +19 -4
- package/cli/commands/edit.ts +245 -0
- package/cli/commands/engines.ts +434 -0
- package/cli/commands/info.ts +279 -0
- package/cli/commands/menu.ts +408 -153
- package/cli/commands/restore.ts +10 -24
- package/cli/commands/start.ts +25 -20
- package/cli/commands/url.ts +79 -0
- package/cli/index.ts +9 -3
- package/cli/ui/prompts.ts +8 -6
- package/config/engine-defaults.ts +24 -1
- package/config/os-dependencies.ts +59 -113
- package/config/paths.ts +7 -36
- package/core/binary-manager.ts +19 -6
- package/core/config-manager.ts +17 -5
- package/core/dependency-manager.ts +9 -15
- package/core/error-handler.ts +336 -0
- package/core/platform-service.ts +634 -0
- package/core/port-manager.ts +11 -3
- package/core/process-manager.ts +12 -2
- package/core/start-with-retry.ts +167 -0
- package/core/transaction-manager.ts +170 -0
- package/engines/mysql/binary-detection.ts +177 -100
- package/engines/mysql/index.ts +240 -131
- package/engines/mysql/restore.ts +257 -0
- package/engines/mysql/version-validator.ts +373 -0
- package/{core/postgres-binary-manager.ts → engines/postgresql/binary-manager.ts} +63 -23
- package/engines/postgresql/binary-urls.ts +5 -3
- package/engines/postgresql/index.ts +4 -3
- package/engines/postgresql/restore.ts +54 -5
- package/engines/postgresql/version-validator.ts +262 -0
- package/package.json +6 -2
- package/cli/commands/postgres-tools.ts +0 -216
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SpinDB
|
|
2
2
|
|
|
3
|
-
Spin up local PostgreSQL and MySQL databases without Docker. A lightweight alternative to DBngin.
|
|
3
|
+
Spin up local PostgreSQL and MySQL databases without Docker. A lightweight alternative to DBngin and Postgres.app.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -45,12 +45,17 @@ spindb connect mydb
|
|
|
45
45
|
| `spindb` | Open interactive menu |
|
|
46
46
|
| `spindb create [name]` | Create a new database container |
|
|
47
47
|
| `spindb list` | List all containers |
|
|
48
|
+
| `spindb info [name]` | Show container details (or all containers) |
|
|
48
49
|
| `spindb start [name]` | Start a container |
|
|
49
50
|
| `spindb stop [name]` | Stop a container |
|
|
50
51
|
| `spindb connect [name]` | Connect with psql/mysql shell |
|
|
52
|
+
| `spindb url [name]` | Output connection string |
|
|
53
|
+
| `spindb edit [name]` | Edit container properties (rename, port) |
|
|
51
54
|
| `spindb restore [name] [backup]` | Restore a backup file |
|
|
52
55
|
| `spindb clone [source] [target]` | Clone a container |
|
|
53
56
|
| `spindb delete [name]` | Delete a container |
|
|
57
|
+
| `spindb engines` | List installed database engines |
|
|
58
|
+
| `spindb engines delete` | Delete an installed engine version |
|
|
54
59
|
| `spindb config show` | Show configuration |
|
|
55
60
|
| `spindb config detect` | Auto-detect database tools |
|
|
56
61
|
| `spindb deps check` | Check status of client tools |
|
|
@@ -60,16 +65,27 @@ spindb connect mydb
|
|
|
60
65
|
|
|
61
66
|
### PostgreSQL 🐘
|
|
62
67
|
|
|
63
|
-
- Downloads binaries from [zonky.io](https://github.com/zonkyio/embedded-postgres-binaries)
|
|
68
|
+
- Downloads server binaries from [zonky.io embedded-postgres-binaries](https://github.com/zonkyio/embedded-postgres-binaries)
|
|
64
69
|
- Versions: 14, 15, 16, 17
|
|
65
70
|
- Requires system client tools (psql, pg_dump, pg_restore) for some operations
|
|
66
71
|
|
|
72
|
+
**Why zonky.io?** Zonky.io provides pre-compiled PostgreSQL server binaries for multiple platforms (macOS, Linux) and architectures (x64, ARM64) hosted on Maven Central. This allows SpinDB to download and run PostgreSQL without requiring a full system installation. The binaries are extracted from official PostgreSQL distributions and repackaged for easy embedding in applications.
|
|
73
|
+
|
|
67
74
|
### MySQL 🐬
|
|
68
75
|
|
|
69
76
|
- Uses system-installed MySQL (via Homebrew, apt, etc.)
|
|
70
77
|
- Version determined by system installation
|
|
71
78
|
- Requires: mysqld, mysql, mysqldump, mysqladmin
|
|
72
79
|
|
|
80
|
+
**Linux Note:** On Linux systems, MariaDB is commonly used as a drop-in replacement for MySQL. SpinDB fully supports MariaDB and will automatically detect it. When MariaDB is installed, the `mysql`, `mysqld`, and `mysqldump` commands work the same way. Install with:
|
|
81
|
+
```bash
|
|
82
|
+
# Ubuntu/Debian
|
|
83
|
+
sudo apt install mariadb-server
|
|
84
|
+
|
|
85
|
+
# Arch
|
|
86
|
+
sudo pacman -S mariadb
|
|
87
|
+
```
|
|
88
|
+
|
|
73
89
|
## How It Works
|
|
74
90
|
|
|
75
91
|
Data is stored in `~/.spindb/`:
|
|
@@ -109,12 +125,14 @@ spindb deps install --engine postgresql
|
|
|
109
125
|
spindb deps install --engine mysql
|
|
110
126
|
```
|
|
111
127
|
|
|
128
|
+
**Note:** On Linux, package managers (apt, pacman, dnf) require `sudo` privileges. You may be prompted for your password when installing dependencies.
|
|
129
|
+
|
|
112
130
|
### Manual Installation
|
|
113
131
|
|
|
114
132
|
#### PostgreSQL
|
|
115
133
|
|
|
116
134
|
```bash
|
|
117
|
-
# macOS (Homebrew)
|
|
135
|
+
# macOS (Homebrew) - use the latest PostgreSQL version (currently 17)
|
|
118
136
|
brew install postgresql@17
|
|
119
137
|
brew link --overwrite postgresql@17
|
|
120
138
|
|
|
@@ -194,15 +212,59 @@ mysql -u root -h 127.0.0.1 -P 3306 mydb
|
|
|
194
212
|
|
|
195
213
|
### Manage installed engines
|
|
196
214
|
|
|
197
|
-
|
|
215
|
+
View installed engines with disk usage (PostgreSQL) and system detection (MySQL):
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
spindb engines
|
|
219
|
+
```
|
|
198
220
|
|
|
199
221
|
```
|
|
200
|
-
ENGINE
|
|
222
|
+
ENGINE VERSION SOURCE SIZE
|
|
201
223
|
────────────────────────────────────────────────────────
|
|
202
|
-
postgresql
|
|
203
|
-
postgresql
|
|
224
|
+
🐘 postgresql 17.7 darwin-arm64 45.2 MB
|
|
225
|
+
🐘 postgresql 16.8 darwin-arm64 44.8 MB
|
|
226
|
+
🐬 mysql 8.0.35 system (system-installed)
|
|
204
227
|
────────────────────────────────────────────────────────
|
|
205
|
-
|
|
228
|
+
|
|
229
|
+
PostgreSQL: 2 version(s), 90.0 MB
|
|
230
|
+
MySQL: system-installed at /opt/homebrew/bin/mysqld
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Delete unused PostgreSQL versions to free disk space:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
spindb engines delete postgresql 16
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Container info and connection strings
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# View all container details
|
|
243
|
+
spindb info
|
|
244
|
+
|
|
245
|
+
# View specific container
|
|
246
|
+
spindb info mydb
|
|
247
|
+
|
|
248
|
+
# Get connection string for scripting
|
|
249
|
+
spindb url mydb
|
|
250
|
+
export DATABASE_URL=$(spindb url mydb)
|
|
251
|
+
psql $(spindb url mydb)
|
|
252
|
+
|
|
253
|
+
# Copy connection string to clipboard
|
|
254
|
+
spindb url mydb --copy
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Edit containers
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Rename a container (must be stopped)
|
|
261
|
+
spindb edit mydb --name newname
|
|
262
|
+
|
|
263
|
+
# Change port
|
|
264
|
+
spindb edit mydb --port 5433
|
|
265
|
+
|
|
266
|
+
# Interactive mode
|
|
267
|
+
spindb edit mydb
|
|
206
268
|
```
|
|
207
269
|
|
|
208
270
|
## Running Tests
|
|
@@ -251,6 +313,73 @@ cat ~/.spindb/containers/mysql/mydb/mysql.log
|
|
|
251
313
|
rm -rf ~/.spindb
|
|
252
314
|
```
|
|
253
315
|
|
|
316
|
+
## Project Structure
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
spindb/
|
|
320
|
+
├── bin.ts # Entry point (#!/usr/bin/env tsx)
|
|
321
|
+
├── cli/
|
|
322
|
+
│ ├── index.ts # Commander setup, routes to commands
|
|
323
|
+
│ ├── commands/ # CLI commands
|
|
324
|
+
│ │ ├── menu.ts # Interactive arrow-key menu
|
|
325
|
+
│ │ ├── create.ts # Create container command
|
|
326
|
+
│ │ ├── delete.ts # Delete container command
|
|
327
|
+
│ │ └── ... # Other commands
|
|
328
|
+
│ └── ui/
|
|
329
|
+
│ ├── prompts.ts # Inquirer prompts
|
|
330
|
+
│ ├── spinner.ts # Ora spinner helpers
|
|
331
|
+
│ └── theme.ts # Chalk color theme
|
|
332
|
+
├── core/
|
|
333
|
+
│ ├── binary-manager.ts # Downloads PostgreSQL from zonky.io
|
|
334
|
+
│ ├── config-manager.ts # Manages ~/.spindb/config.json
|
|
335
|
+
│ ├── container-manager.ts # CRUD for containers
|
|
336
|
+
│ ├── port-manager.ts # Port availability checking
|
|
337
|
+
│ ├── process-manager.ts # Process start/stop wrapper
|
|
338
|
+
│ ├── dependency-manager.ts # Client tool detection
|
|
339
|
+
│ ├── error-handler.ts # Centralized error handling
|
|
340
|
+
│ └── transaction-manager.ts # Rollback support for operations
|
|
341
|
+
├── config/
|
|
342
|
+
│ ├── paths.ts # ~/.spindb/ path definitions
|
|
343
|
+
│ ├── defaults.ts # Default values, platform mappings
|
|
344
|
+
│ └── os-dependencies.ts # OS-specific dependency definitions
|
|
345
|
+
├── engines/
|
|
346
|
+
│ ├── base-engine.ts # Abstract base class
|
|
347
|
+
│ ├── index.ts # Engine registry
|
|
348
|
+
│ ├── postgresql/
|
|
349
|
+
│ │ ├── index.ts # PostgreSQL engine implementation
|
|
350
|
+
│ │ ├── binary-urls.ts # Zonky.io URL builder
|
|
351
|
+
│ │ ├── restore.ts # Backup detection and restore
|
|
352
|
+
│ │ └── version-validator.ts # Version compatibility checks
|
|
353
|
+
│ └── mysql/
|
|
354
|
+
│ ├── index.ts # MySQL engine implementation
|
|
355
|
+
│ ├── binary-detection.ts # MySQL binary path detection
|
|
356
|
+
│ ├── restore.ts # Backup detection and restore
|
|
357
|
+
│ └── version-validator.ts # Version compatibility checks
|
|
358
|
+
├── types/
|
|
359
|
+
│ └── index.ts # TypeScript interfaces
|
|
360
|
+
└── tests/
|
|
361
|
+
├── unit/ # Unit tests
|
|
362
|
+
├── integration/ # Integration tests
|
|
363
|
+
└── fixtures/ # Test data
|
|
364
|
+
├── postgresql/
|
|
365
|
+
│ └── seeds/
|
|
366
|
+
└── mysql/
|
|
367
|
+
└── seeds/
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Contributing
|
|
371
|
+
|
|
372
|
+
### Version Updates
|
|
373
|
+
|
|
374
|
+
SpinDB uses versioned PostgreSQL packages from Homebrew (e.g., `postgresql@17`). When new major versions are released:
|
|
375
|
+
|
|
376
|
+
1. Check [PostgreSQL releases](https://www.postgresql.org/docs/release/) and [Homebrew formulae](https://formulae.brew.sh/formula/postgresql)
|
|
377
|
+
2. Update `config/engine-defaults.ts`:
|
|
378
|
+
- Change `latestVersion` to the new version
|
|
379
|
+
- Add the new version to `supportedVersions`
|
|
380
|
+
|
|
381
|
+
See `CLAUDE.md` for detailed maintenance instructions.
|
|
382
|
+
|
|
254
383
|
## License
|
|
255
384
|
|
|
256
385
|
MIT
|
package/cli/commands/connect.ts
CHANGED
|
@@ -55,7 +55,8 @@ export const connectCommand = new Command('connect')
|
|
|
55
55
|
const engineDefaults = getEngineDefaults(engineName)
|
|
56
56
|
|
|
57
57
|
// Default database: container's database or superuser
|
|
58
|
-
const database =
|
|
58
|
+
const database =
|
|
59
|
+
options.database ?? config.database ?? engineDefaults.superuser
|
|
59
60
|
|
|
60
61
|
// Check if running
|
|
61
62
|
const running = await processManager.isRunning(containerName, {
|
|
@@ -83,9 +84,12 @@ export const connectCommand = new Command('connect')
|
|
|
83
84
|
// MySQL: mysql -h 127.0.0.1 -P port -u root database
|
|
84
85
|
clientCmd = 'mysql'
|
|
85
86
|
clientArgs = [
|
|
86
|
-
'-h',
|
|
87
|
-
'
|
|
88
|
-
'-
|
|
87
|
+
'-h',
|
|
88
|
+
'127.0.0.1',
|
|
89
|
+
'-P',
|
|
90
|
+
String(config.port),
|
|
91
|
+
'-u',
|
|
92
|
+
engineDefaults.superuser,
|
|
89
93
|
database,
|
|
90
94
|
]
|
|
91
95
|
} else {
|
package/cli/commands/create.ts
CHANGED
|
@@ -16,9 +16,10 @@ import { createSpinner } from '../ui/spinner'
|
|
|
16
16
|
import { header, error, connectionBox } from '../ui/theme'
|
|
17
17
|
import { tmpdir } from 'os'
|
|
18
18
|
import { join } from 'path'
|
|
19
|
-
import { spawn } from 'child_process'
|
|
20
|
-
import { platform } from 'os'
|
|
21
19
|
import { getMissingDependencies } from '../../core/dependency-manager'
|
|
20
|
+
import { platformService } from '../../core/platform-service'
|
|
21
|
+
import { startWithRetry } from '../../core/start-with-retry'
|
|
22
|
+
import { TransactionManager } from '../../core/transaction-manager'
|
|
22
23
|
import type { EngineName } from '../../types'
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -244,28 +245,50 @@ export const createCommand = new Command('create')
|
|
|
244
245
|
containerName = await promptContainerName()
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
// Create transaction manager for rollback support
|
|
249
|
+
const tx = new TransactionManager()
|
|
250
|
+
|
|
247
251
|
// Create container
|
|
248
252
|
const createSpinnerInstance = createSpinner('Creating container...')
|
|
249
253
|
createSpinnerInstance.start()
|
|
250
254
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
try {
|
|
256
|
+
await containerManager.create(containerName, {
|
|
257
|
+
engine: dbEngine.name as EngineName,
|
|
258
|
+
version,
|
|
259
|
+
port,
|
|
260
|
+
database,
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// Register rollback action for container deletion
|
|
264
|
+
tx.addRollback({
|
|
265
|
+
description: `Delete container "${containerName}"`,
|
|
266
|
+
execute: async () => {
|
|
267
|
+
await containerManager.delete(containerName, { force: true })
|
|
268
|
+
},
|
|
269
|
+
})
|
|
257
270
|
|
|
258
|
-
|
|
271
|
+
createSpinnerInstance.succeed('Container created')
|
|
272
|
+
} catch (err) {
|
|
273
|
+
createSpinnerInstance.fail('Failed to create container')
|
|
274
|
+
throw err
|
|
275
|
+
}
|
|
259
276
|
|
|
260
277
|
// Initialize database cluster
|
|
261
278
|
const initSpinner = createSpinner('Initializing database cluster...')
|
|
262
279
|
initSpinner.start()
|
|
263
280
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
281
|
+
try {
|
|
282
|
+
await dbEngine.initDataDir(containerName, version, {
|
|
283
|
+
superuser: engineDefaults.superuser,
|
|
284
|
+
})
|
|
285
|
+
// Note: initDataDir is covered by the container delete rollback
|
|
286
|
+
initSpinner.succeed('Database cluster initialized')
|
|
287
|
+
} catch (err) {
|
|
288
|
+
initSpinner.fail('Failed to initialize database cluster')
|
|
289
|
+
await tx.rollback()
|
|
290
|
+
throw err
|
|
291
|
+
}
|
|
269
292
|
|
|
270
293
|
// Determine if we should start the container
|
|
271
294
|
// If --from is specified, we must start to restore
|
|
@@ -281,10 +304,7 @@ export const createCommand = new Command('create')
|
|
|
281
304
|
} else {
|
|
282
305
|
// Ask the user
|
|
283
306
|
console.log()
|
|
284
|
-
shouldStart = await promptConfirm(
|
|
285
|
-
`Start ${containerName} now?`,
|
|
286
|
-
true,
|
|
287
|
-
)
|
|
307
|
+
shouldStart = await promptConfirm(`Start ${containerName} now?`, true)
|
|
288
308
|
}
|
|
289
309
|
|
|
290
310
|
// Get container config for starting and restoration
|
|
@@ -292,34 +312,63 @@ export const createCommand = new Command('create')
|
|
|
292
312
|
|
|
293
313
|
// Start container if requested
|
|
294
314
|
if (shouldStart && config) {
|
|
295
|
-
// Check port availability before starting
|
|
296
|
-
const portAvailable = await portManager.isPortAvailable(config.port)
|
|
297
|
-
if (!portAvailable) {
|
|
298
|
-
// Find a new available port
|
|
299
|
-
const { port: newPort } = await portManager.findAvailablePort({
|
|
300
|
-
portRange: engineDefaults.portRange,
|
|
301
|
-
})
|
|
302
|
-
console.log(
|
|
303
|
-
chalk.yellow(
|
|
304
|
-
` ⚠ Port ${config.port} is in use, switching to port ${newPort}`,
|
|
305
|
-
),
|
|
306
|
-
)
|
|
307
|
-
config.port = newPort
|
|
308
|
-
port = newPort
|
|
309
|
-
await containerManager.updateConfig(containerName, { port: newPort })
|
|
310
|
-
}
|
|
311
|
-
|
|
312
315
|
const startSpinner = createSpinner(
|
|
313
316
|
`Starting ${dbEngine.displayName}...`,
|
|
314
317
|
)
|
|
315
318
|
startSpinner.start()
|
|
316
319
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
try {
|
|
321
|
+
// Use startWithRetry to handle port race conditions
|
|
322
|
+
const result = await startWithRetry({
|
|
323
|
+
engine: dbEngine,
|
|
324
|
+
config,
|
|
325
|
+
onPortChange: (oldPort, newPort) => {
|
|
326
|
+
startSpinner.text = `Port ${oldPort} was in use, retrying with port ${newPort}...`
|
|
327
|
+
port = newPort
|
|
328
|
+
},
|
|
329
|
+
})
|
|
321
330
|
|
|
322
|
-
|
|
331
|
+
if (!result.success) {
|
|
332
|
+
startSpinner.fail(`Failed to start ${dbEngine.displayName}`)
|
|
333
|
+
await tx.rollback()
|
|
334
|
+
if (result.error) {
|
|
335
|
+
throw result.error
|
|
336
|
+
}
|
|
337
|
+
throw new Error('Failed to start container')
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Register rollback action for stopping the container
|
|
341
|
+
tx.addRollback({
|
|
342
|
+
description: `Stop container "${containerName}"`,
|
|
343
|
+
execute: async () => {
|
|
344
|
+
try {
|
|
345
|
+
await dbEngine.stop(config)
|
|
346
|
+
} catch {
|
|
347
|
+
// Ignore stop errors during rollback
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
await containerManager.updateConfig(containerName, {
|
|
353
|
+
status: 'running',
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
if (result.retriesUsed > 0) {
|
|
357
|
+
startSpinner.warn(
|
|
358
|
+
`${dbEngine.displayName} started on port ${result.finalPort} (original port was in use)`,
|
|
359
|
+
)
|
|
360
|
+
} else {
|
|
361
|
+
startSpinner.succeed(`${dbEngine.displayName} started`)
|
|
362
|
+
}
|
|
363
|
+
} catch (err) {
|
|
364
|
+
if (!startSpinner.isSpinning) {
|
|
365
|
+
// Error was already handled above
|
|
366
|
+
} else {
|
|
367
|
+
startSpinner.fail(`Failed to start ${dbEngine.displayName}`)
|
|
368
|
+
}
|
|
369
|
+
await tx.rollback()
|
|
370
|
+
throw err
|
|
371
|
+
}
|
|
323
372
|
|
|
324
373
|
// Create the user's database (if different from default)
|
|
325
374
|
const defaultDb = engineDefaults.superuser // postgres or root
|
|
@@ -329,9 +378,14 @@ export const createCommand = new Command('create')
|
|
|
329
378
|
)
|
|
330
379
|
dbSpinner.start()
|
|
331
380
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
381
|
+
try {
|
|
382
|
+
await dbEngine.createDatabase(config, database)
|
|
383
|
+
dbSpinner.succeed(`Database "${database}" created`)
|
|
384
|
+
} catch (err) {
|
|
385
|
+
dbSpinner.fail(`Failed to create database "${database}"`)
|
|
386
|
+
await tx.rollback()
|
|
387
|
+
throw err
|
|
388
|
+
}
|
|
335
389
|
}
|
|
336
390
|
}
|
|
337
391
|
|
|
@@ -431,13 +485,18 @@ export const createCommand = new Command('create')
|
|
|
431
485
|
}
|
|
432
486
|
}
|
|
433
487
|
|
|
488
|
+
// Commit the transaction - all operations succeeded
|
|
489
|
+
tx.commit()
|
|
490
|
+
|
|
434
491
|
// Show success message
|
|
435
492
|
const finalConfig = await containerManager.getConfig(containerName)
|
|
436
493
|
if (finalConfig) {
|
|
437
494
|
const connectionString = dbEngine.getConnectionString(finalConfig)
|
|
438
495
|
|
|
439
496
|
console.log()
|
|
440
|
-
console.log(
|
|
497
|
+
console.log(
|
|
498
|
+
connectionBox(containerName, connectionString, finalConfig.port),
|
|
499
|
+
)
|
|
441
500
|
console.log()
|
|
442
501
|
|
|
443
502
|
if (shouldStart) {
|
|
@@ -445,30 +504,10 @@ export const createCommand = new Command('create')
|
|
|
445
504
|
console.log(chalk.cyan(` spindb connect ${containerName}`))
|
|
446
505
|
|
|
447
506
|
// Copy connection string to clipboard
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
platform() === 'darwin' ? [] : ['-selection', 'clipboard']
|
|
452
|
-
|
|
453
|
-
await new Promise<void>((resolve, reject) => {
|
|
454
|
-
const proc = spawn(cmd, args, {
|
|
455
|
-
stdio: ['pipe', 'inherit', 'inherit'],
|
|
456
|
-
})
|
|
457
|
-
proc.stdin?.write(connectionString)
|
|
458
|
-
proc.stdin?.end()
|
|
459
|
-
proc.on('close', (code) => {
|
|
460
|
-
if (code === 0) resolve()
|
|
461
|
-
else
|
|
462
|
-
reject(
|
|
463
|
-
new Error(`Clipboard command exited with code ${code}`),
|
|
464
|
-
)
|
|
465
|
-
})
|
|
466
|
-
proc.on('error', reject)
|
|
467
|
-
})
|
|
468
|
-
|
|
507
|
+
const copied =
|
|
508
|
+
await platformService.copyToClipboard(connectionString)
|
|
509
|
+
if (copied) {
|
|
469
510
|
console.log(chalk.gray(' Connection string copied to clipboard'))
|
|
470
|
-
} catch {
|
|
471
|
-
// Ignore clipboard errors
|
|
472
511
|
}
|
|
473
512
|
} else {
|
|
474
513
|
console.log(chalk.gray(' Start the container:'))
|
package/cli/commands/deps.ts
CHANGED
|
@@ -188,7 +188,11 @@ depsCommand
|
|
|
188
188
|
|
|
189
189
|
if (succeeded.length > 0) {
|
|
190
190
|
console.log()
|
|
191
|
-
console.log(
|
|
191
|
+
console.log(
|
|
192
|
+
success(
|
|
193
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
194
|
+
),
|
|
195
|
+
)
|
|
192
196
|
}
|
|
193
197
|
} else if (options.engine) {
|
|
194
198
|
// Install dependencies for specific engine
|
|
@@ -254,7 +258,11 @@ depsCommand
|
|
|
254
258
|
|
|
255
259
|
if (succeeded.length > 0) {
|
|
256
260
|
console.log()
|
|
257
|
-
console.log(
|
|
261
|
+
console.log(
|
|
262
|
+
success(
|
|
263
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
264
|
+
),
|
|
265
|
+
)
|
|
258
266
|
}
|
|
259
267
|
} else {
|
|
260
268
|
// Default: install PostgreSQL dependencies (most common use case)
|
|
@@ -278,7 +286,10 @@ depsCommand
|
|
|
278
286
|
const spinner = createSpinner('Installing PostgreSQL dependencies...')
|
|
279
287
|
spinner.start()
|
|
280
288
|
|
|
281
|
-
const results = await installEngineDependencies(
|
|
289
|
+
const results = await installEngineDependencies(
|
|
290
|
+
'postgresql',
|
|
291
|
+
packageManager,
|
|
292
|
+
)
|
|
282
293
|
|
|
283
294
|
const succeeded = results.filter((r) => r.success)
|
|
284
295
|
const failed = results.filter((r) => !r.success)
|
|
@@ -295,7 +306,11 @@ depsCommand
|
|
|
295
306
|
|
|
296
307
|
if (succeeded.length > 0) {
|
|
297
308
|
console.log()
|
|
298
|
-
console.log(
|
|
309
|
+
console.log(
|
|
310
|
+
success(
|
|
311
|
+
`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`,
|
|
312
|
+
),
|
|
313
|
+
)
|
|
299
314
|
}
|
|
300
315
|
}
|
|
301
316
|
})
|