spindb 0.9.0 â 0.9.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 +7 -0
- package/cli/commands/backup.ts +13 -11
- package/cli/commands/clone.ts +18 -8
- package/cli/commands/config.ts +29 -29
- package/cli/commands/connect.ts +51 -39
- package/cli/commands/create.ts +120 -43
- package/cli/commands/delete.ts +8 -8
- package/cli/commands/deps.ts +17 -15
- package/cli/commands/doctor.ts +16 -15
- package/cli/commands/edit.ts +115 -60
- package/cli/commands/engines.ts +50 -17
- package/cli/commands/info.ts +12 -8
- package/cli/commands/list.ts +34 -19
- package/cli/commands/logs.ts +24 -14
- package/cli/commands/menu/backup-handlers.ts +72 -49
- package/cli/commands/menu/container-handlers.ts +140 -80
- package/cli/commands/menu/engine-handlers.ts +145 -11
- package/cli/commands/menu/index.ts +4 -4
- package/cli/commands/menu/shell-handlers.ts +34 -31
- package/cli/commands/menu/sql-handlers.ts +22 -16
- package/cli/commands/menu/update-handlers.ts +19 -17
- package/cli/commands/restore.ts +105 -43
- package/cli/commands/run.ts +20 -18
- package/cli/commands/self-update.ts +5 -5
- package/cli/commands/start.ts +11 -9
- package/cli/commands/stop.ts +9 -9
- package/cli/commands/url.ts +12 -9
- package/cli/helpers.ts +49 -4
- package/cli/ui/prompts.ts +21 -8
- package/cli/ui/spinner.ts +4 -4
- package/cli/ui/theme.ts +4 -4
- package/core/binary-manager.ts +5 -1
- package/core/container-manager.ts +81 -30
- package/core/error-handler.ts +31 -0
- package/core/platform-service.ts +3 -3
- package/core/port-manager.ts +2 -0
- package/core/process-manager.ts +25 -3
- package/core/start-with-retry.ts +6 -6
- package/core/transaction-manager.ts +6 -6
- package/engines/mysql/backup.ts +53 -36
- package/engines/mysql/index.ts +59 -16
- package/engines/mysql/restore.ts +4 -4
- package/engines/mysql/version-validator.ts +2 -2
- package/engines/postgresql/binary-manager.ts +17 -17
- package/engines/postgresql/index.ts +13 -2
- package/engines/postgresql/restore.ts +2 -2
- package/engines/postgresql/version-validator.ts +2 -2
- package/engines/sqlite/index.ts +31 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,6 +227,9 @@ spindb create mydb --port 5433 # Custom port
|
|
|
227
227
|
spindb create mydb --database my_app # Custom database name
|
|
228
228
|
spindb create mydb --no-start # Create without starting
|
|
229
229
|
|
|
230
|
+
# Create, start, and connect in one command
|
|
231
|
+
spindb create mydb --start --connect
|
|
232
|
+
|
|
230
233
|
# SQLite with custom path
|
|
231
234
|
spindb create mydb --engine sqlite --path ./data/app.sqlite
|
|
232
235
|
```
|
|
@@ -250,7 +253,9 @@ spindb create mydb --from "postgresql://user:pass@host:5432/production"
|
|
|
250
253
|
| `--path` | File path for SQLite databases |
|
|
251
254
|
| `--max-connections` | Maximum database connections (default: 200) |
|
|
252
255
|
| `--from` | Restore from backup file or connection string |
|
|
256
|
+
| `--start` | Start container after creation (skip prompt) |
|
|
253
257
|
| `--no-start` | Create without starting |
|
|
258
|
+
| `--connect` | Open a shell connection after creation |
|
|
254
259
|
|
|
255
260
|
</details>
|
|
256
261
|
|
|
@@ -400,10 +405,12 @@ ENGINE VERSION SOURCE SIZE
|
|
|
400
405
|
ð postgresql 17.7 darwin-arm64 45.2 MB
|
|
401
406
|
ð postgresql 16.8 darwin-arm64 44.8 MB
|
|
402
407
|
ðŽ mysql 8.0.35 system (system-installed)
|
|
408
|
+
ðŠķ sqlite 3.43.2 system (system-installed)
|
|
403
409
|
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
|
|
404
410
|
|
|
405
411
|
PostgreSQL: 2 version(s), 90.0 MB
|
|
406
412
|
MySQL: system-installed at /opt/homebrew/bin/mysqld
|
|
413
|
+
SQLite: system-installed at /usr/bin/sqlite3
|
|
407
414
|
```
|
|
408
415
|
|
|
409
416
|
#### `deps` - Manage client tools
|
package/cli/commands/backup.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
promptInstallDependencies,
|
|
13
13
|
} from '../ui/prompts'
|
|
14
14
|
import { createSpinner } from '../ui/spinner'
|
|
15
|
-
import {
|
|
15
|
+
import { uiSuccess, uiError, uiWarning, formatBytes } from '../ui/theme'
|
|
16
16
|
import { getMissingDependencies } from '../../core/dependency-manager'
|
|
17
17
|
|
|
18
18
|
function generateTimestamp(): string {
|
|
@@ -70,11 +70,13 @@ export const backupCommand = new Command('backup')
|
|
|
70
70
|
if (running.length === 0) {
|
|
71
71
|
if (containers.length === 0) {
|
|
72
72
|
console.log(
|
|
73
|
-
|
|
73
|
+
uiWarning(
|
|
74
|
+
'No containers found. Create one with: spindb create',
|
|
75
|
+
),
|
|
74
76
|
)
|
|
75
77
|
} else {
|
|
76
78
|
console.log(
|
|
77
|
-
|
|
79
|
+
uiWarning(
|
|
78
80
|
'No running containers. Start one first with: spindb start',
|
|
79
81
|
),
|
|
80
82
|
)
|
|
@@ -92,7 +94,7 @@ export const backupCommand = new Command('backup')
|
|
|
92
94
|
|
|
93
95
|
const config = await containerManager.getConfig(containerName)
|
|
94
96
|
if (!config) {
|
|
95
|
-
console.error(
|
|
97
|
+
console.error(uiError(`Container "${containerName}" not found`))
|
|
96
98
|
process.exit(1)
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -103,7 +105,7 @@ export const backupCommand = new Command('backup')
|
|
|
103
105
|
})
|
|
104
106
|
if (!running) {
|
|
105
107
|
console.error(
|
|
106
|
-
|
|
108
|
+
uiError(
|
|
107
109
|
`Container "${containerName}" is not running. Start it first.`,
|
|
108
110
|
),
|
|
109
111
|
)
|
|
@@ -133,7 +135,7 @@ export const backupCommand = new Command('backup')
|
|
|
133
135
|
missingDeps = await getMissingDependencies(config.engine)
|
|
134
136
|
if (missingDeps.length > 0) {
|
|
135
137
|
console.error(
|
|
136
|
-
|
|
138
|
+
uiError(
|
|
137
139
|
`Still missing tools: ${missingDeps.map((d) => d.name).join(', ')}`,
|
|
138
140
|
),
|
|
139
141
|
)
|
|
@@ -169,7 +171,7 @@ export const backupCommand = new Command('backup')
|
|
|
169
171
|
format = 'dump'
|
|
170
172
|
} else if (options.format) {
|
|
171
173
|
if (options.format !== 'sql' && options.format !== 'dump') {
|
|
172
|
-
console.error(
|
|
174
|
+
console.error(uiError('Format must be "sql" or "dump"'))
|
|
173
175
|
process.exit(1)
|
|
174
176
|
}
|
|
175
177
|
format = options.format as 'sql' | 'dump'
|
|
@@ -204,7 +206,7 @@ export const backupCommand = new Command('backup')
|
|
|
204
206
|
backupSpinner.succeed('Backup created successfully')
|
|
205
207
|
|
|
206
208
|
console.log()
|
|
207
|
-
console.log(
|
|
209
|
+
console.log(uiSuccess('Backup complete'))
|
|
208
210
|
console.log()
|
|
209
211
|
console.log(chalk.gray(' File:'), chalk.cyan(result.path))
|
|
210
212
|
console.log(
|
|
@@ -213,8 +215,8 @@ export const backupCommand = new Command('backup')
|
|
|
213
215
|
)
|
|
214
216
|
console.log(chalk.gray(' Format:'), chalk.white(result.format))
|
|
215
217
|
console.log()
|
|
216
|
-
} catch (
|
|
217
|
-
const e =
|
|
218
|
+
} catch (error) {
|
|
219
|
+
const e = error as Error
|
|
218
220
|
|
|
219
221
|
const missingToolPatterns = ['pg_dump not found', 'mysqldump not found']
|
|
220
222
|
|
|
@@ -233,7 +235,7 @@ export const backupCommand = new Command('backup')
|
|
|
233
235
|
process.exit(1)
|
|
234
236
|
}
|
|
235
237
|
|
|
236
|
-
console.error(
|
|
238
|
+
console.error(uiError(e.message))
|
|
237
239
|
process.exit(1)
|
|
238
240
|
}
|
|
239
241
|
},
|
package/cli/commands/clone.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { processManager } from '../../core/process-manager'
|
|
|
5
5
|
import { getEngine } from '../../engines'
|
|
6
6
|
import { promptContainerSelect, promptContainerName } from '../ui/prompts'
|
|
7
7
|
import { createSpinner } from '../ui/spinner'
|
|
8
|
-
import {
|
|
8
|
+
import { uiError, uiWarning, connectionBox } from '../ui/theme'
|
|
9
9
|
|
|
10
10
|
export const cloneCommand = new Command('clone')
|
|
11
11
|
.description('Clone a container with all its data')
|
|
@@ -22,14 +22,14 @@ export const cloneCommand = new Command('clone')
|
|
|
22
22
|
|
|
23
23
|
if (containers.length === 0) {
|
|
24
24
|
console.log(
|
|
25
|
-
|
|
25
|
+
uiWarning('No containers found. Create one with: spindb create'),
|
|
26
26
|
)
|
|
27
27
|
return
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (stopped.length === 0) {
|
|
31
31
|
console.log(
|
|
32
|
-
|
|
32
|
+
uiWarning(
|
|
33
33
|
'All containers are running. Stop a container first to clone it.',
|
|
34
34
|
),
|
|
35
35
|
)
|
|
@@ -51,7 +51,7 @@ export const cloneCommand = new Command('clone')
|
|
|
51
51
|
|
|
52
52
|
const sourceConfig = await containerManager.getConfig(sourceName)
|
|
53
53
|
if (!sourceConfig) {
|
|
54
|
-
console.error(
|
|
54
|
+
console.error(uiError(`Container "${sourceName}" not found`))
|
|
55
55
|
process.exit(1)
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -60,7 +60,7 @@ export const cloneCommand = new Command('clone')
|
|
|
60
60
|
})
|
|
61
61
|
if (running) {
|
|
62
62
|
console.error(
|
|
63
|
-
|
|
63
|
+
uiError(
|
|
64
64
|
`Container "${sourceName}" is running. Stop it first to clone.`,
|
|
65
65
|
),
|
|
66
66
|
)
|
|
@@ -71,6 +71,16 @@ export const cloneCommand = new Command('clone')
|
|
|
71
71
|
targetName = await promptContainerName(`${sourceName}-copy`)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// Check if target container already exists
|
|
75
|
+
if (
|
|
76
|
+
await containerManager.exists(targetName, {
|
|
77
|
+
engine: sourceConfig.engine,
|
|
78
|
+
})
|
|
79
|
+
) {
|
|
80
|
+
console.error(uiError(`Container "${targetName}" already exists`))
|
|
81
|
+
process.exit(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
const cloneSpinner = createSpinner(
|
|
75
85
|
`Cloning ${sourceName} to ${targetName}...`,
|
|
76
86
|
)
|
|
@@ -89,9 +99,9 @@ export const cloneCommand = new Command('clone')
|
|
|
89
99
|
console.log(chalk.gray(' Start the cloned container:'))
|
|
90
100
|
console.log(chalk.cyan(` spindb start ${targetName}`))
|
|
91
101
|
console.log()
|
|
92
|
-
} catch (
|
|
93
|
-
const e =
|
|
94
|
-
console.error(
|
|
102
|
+
} catch (error) {
|
|
103
|
+
const e = error as Error
|
|
104
|
+
console.error(uiError(e.message))
|
|
95
105
|
process.exit(1)
|
|
96
106
|
}
|
|
97
107
|
})
|
package/cli/commands/config.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ALL_TOOLS,
|
|
10
10
|
} from '../../core/config-manager'
|
|
11
11
|
import { updateManager } from '../../core/update-manager'
|
|
12
|
-
import {
|
|
12
|
+
import { uiError, uiSuccess, header, uiInfo } from '../ui/theme'
|
|
13
13
|
import { createSpinner } from '../ui/spinner'
|
|
14
14
|
import type { BinaryTool } from '../../types'
|
|
15
15
|
|
|
@@ -95,9 +95,9 @@ export const configCommand = new Command('config')
|
|
|
95
95
|
)
|
|
96
96
|
console.log()
|
|
97
97
|
}
|
|
98
|
-
} catch (
|
|
99
|
-
const e =
|
|
100
|
-
console.error(
|
|
98
|
+
} catch (error) {
|
|
99
|
+
const e = error as Error
|
|
100
|
+
console.error(uiError(e.message))
|
|
101
101
|
process.exit(1)
|
|
102
102
|
}
|
|
103
103
|
}),
|
|
@@ -208,9 +208,9 @@ export const configCommand = new Command('config')
|
|
|
208
208
|
}
|
|
209
209
|
console.log()
|
|
210
210
|
}
|
|
211
|
-
} catch (
|
|
212
|
-
const e =
|
|
213
|
-
console.error(
|
|
211
|
+
} catch (error) {
|
|
212
|
+
const e = error as Error
|
|
213
|
+
console.error(uiError(e.message))
|
|
214
214
|
process.exit(1)
|
|
215
215
|
}
|
|
216
216
|
}),
|
|
@@ -224,14 +224,14 @@ export const configCommand = new Command('config')
|
|
|
224
224
|
try {
|
|
225
225
|
// Validate tool name
|
|
226
226
|
if (!ALL_TOOLS.includes(tool as BinaryTool)) {
|
|
227
|
-
console.error(
|
|
227
|
+
console.error(uiError(`Invalid tool: ${tool}`))
|
|
228
228
|
console.log(chalk.gray(` Valid tools: ${ALL_TOOLS.join(', ')}`))
|
|
229
229
|
process.exit(1)
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
// Validate path exists
|
|
233
233
|
if (!existsSync(path)) {
|
|
234
|
-
console.error(
|
|
234
|
+
console.error(uiError(`File not found: ${path}`))
|
|
235
235
|
process.exit(1)
|
|
236
236
|
}
|
|
237
237
|
|
|
@@ -240,10 +240,10 @@ export const configCommand = new Command('config')
|
|
|
240
240
|
const config = await configManager.getBinaryConfig(tool as BinaryTool)
|
|
241
241
|
const versionLabel = config?.version ? ` (v${config.version})` : ''
|
|
242
242
|
|
|
243
|
-
console.log(
|
|
244
|
-
} catch (
|
|
245
|
-
const e =
|
|
246
|
-
console.error(
|
|
243
|
+
console.log(uiSuccess(`Set ${tool} to: ${path}${versionLabel}`))
|
|
244
|
+
} catch (error) {
|
|
245
|
+
const e = error as Error
|
|
246
|
+
console.error(uiError(e.message))
|
|
247
247
|
process.exit(1)
|
|
248
248
|
}
|
|
249
249
|
}),
|
|
@@ -256,16 +256,16 @@ export const configCommand = new Command('config')
|
|
|
256
256
|
try {
|
|
257
257
|
// Validate tool name
|
|
258
258
|
if (!ALL_TOOLS.includes(tool as BinaryTool)) {
|
|
259
|
-
console.error(
|
|
259
|
+
console.error(uiError(`Invalid tool: ${tool}`))
|
|
260
260
|
console.log(chalk.gray(` Valid tools: ${ALL_TOOLS.join(', ')}`))
|
|
261
261
|
process.exit(1)
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
await configManager.clearBinaryPath(tool as BinaryTool)
|
|
265
|
-
console.log(
|
|
266
|
-
} catch (
|
|
267
|
-
const e =
|
|
268
|
-
console.error(
|
|
265
|
+
console.log(uiSuccess(`Removed ${tool} configuration`))
|
|
266
|
+
} catch (error) {
|
|
267
|
+
const e = error as Error
|
|
268
|
+
console.error(uiError(e.message))
|
|
269
269
|
process.exit(1)
|
|
270
270
|
}
|
|
271
271
|
}),
|
|
@@ -278,7 +278,7 @@ export const configCommand = new Command('config')
|
|
|
278
278
|
try {
|
|
279
279
|
// Validate tool name
|
|
280
280
|
if (!ALL_TOOLS.includes(tool as BinaryTool)) {
|
|
281
|
-
console.error(
|
|
281
|
+
console.error(uiError(`Invalid tool: ${tool}`))
|
|
282
282
|
console.log(chalk.gray(` Valid tools: ${ALL_TOOLS.join(', ')}`))
|
|
283
283
|
process.exit(1)
|
|
284
284
|
}
|
|
@@ -287,15 +287,15 @@ export const configCommand = new Command('config')
|
|
|
287
287
|
if (path) {
|
|
288
288
|
console.log(path)
|
|
289
289
|
} else {
|
|
290
|
-
console.error(
|
|
290
|
+
console.error(uiError(`${tool} not found`))
|
|
291
291
|
console.log(
|
|
292
292
|
chalk.gray(` Run 'spindb config detect' to auto-detect tools`),
|
|
293
293
|
)
|
|
294
294
|
process.exit(1)
|
|
295
295
|
}
|
|
296
|
-
} catch (
|
|
297
|
-
const e =
|
|
298
|
-
console.error(
|
|
296
|
+
} catch (error) {
|
|
297
|
+
const e = error as Error
|
|
298
|
+
console.error(uiError(e.message))
|
|
299
299
|
process.exit(1)
|
|
300
300
|
}
|
|
301
301
|
}),
|
|
@@ -328,7 +328,7 @@ export const configCommand = new Command('config')
|
|
|
328
328
|
}
|
|
329
329
|
|
|
330
330
|
if (state !== 'on' && state !== 'off') {
|
|
331
|
-
console.error(
|
|
331
|
+
console.error(uiError('Invalid state. Use "on" or "off"'))
|
|
332
332
|
process.exit(1)
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -336,18 +336,18 @@ export const configCommand = new Command('config')
|
|
|
336
336
|
await updateManager.setAutoCheckEnabled(enabled)
|
|
337
337
|
|
|
338
338
|
if (enabled) {
|
|
339
|
-
console.log(
|
|
339
|
+
console.log(uiSuccess('Update checks enabled on startup'))
|
|
340
340
|
} else {
|
|
341
|
-
console.log(
|
|
341
|
+
console.log(uiInfo('Update checks disabled on startup'))
|
|
342
342
|
console.log(
|
|
343
343
|
chalk.gray(
|
|
344
344
|
' You can still manually check with: spindb version --check',
|
|
345
345
|
),
|
|
346
346
|
)
|
|
347
347
|
}
|
|
348
|
-
} catch (
|
|
349
|
-
const e =
|
|
350
|
-
console.error(
|
|
348
|
+
} catch (error) {
|
|
349
|
+
const e = error as Error
|
|
350
|
+
console.error(uiError(e.message))
|
|
351
351
|
process.exit(1)
|
|
352
352
|
}
|
|
353
353
|
}),
|
package/cli/commands/connect.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import { getEngine } from '../../engines'
|
|
23
23
|
import { getEngineDefaults } from '../../config/defaults'
|
|
24
24
|
import { promptContainerSelect } from '../ui/prompts'
|
|
25
|
-
import {
|
|
25
|
+
import { uiError, uiWarning, uiInfo, uiSuccess } from '../ui/theme'
|
|
26
26
|
import { Engine } from '../../types'
|
|
27
27
|
|
|
28
28
|
export const connectCommand = new Command('connect')
|
|
@@ -78,11 +78,13 @@ export const connectCommand = new Command('connect')
|
|
|
78
78
|
if (connectable.length === 0) {
|
|
79
79
|
if (containers.length === 0) {
|
|
80
80
|
console.log(
|
|
81
|
-
|
|
81
|
+
uiWarning(
|
|
82
|
+
'No containers found. Create one with: spindb create',
|
|
83
|
+
),
|
|
82
84
|
)
|
|
83
85
|
} else {
|
|
84
86
|
console.log(
|
|
85
|
-
|
|
87
|
+
uiWarning(
|
|
86
88
|
'No running containers. Start one first with: spindb start',
|
|
87
89
|
),
|
|
88
90
|
)
|
|
@@ -100,7 +102,7 @@ export const connectCommand = new Command('connect')
|
|
|
100
102
|
|
|
101
103
|
const config = await containerManager.getConfig(containerName)
|
|
102
104
|
if (!config) {
|
|
103
|
-
console.error(
|
|
105
|
+
console.error(uiError(`Container "${containerName}" not found`))
|
|
104
106
|
process.exit(1)
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -114,9 +116,7 @@ export const connectCommand = new Command('connect')
|
|
|
114
116
|
if (engineName === Engine.SQLite) {
|
|
115
117
|
if (!existsSync(config.database)) {
|
|
116
118
|
console.error(
|
|
117
|
-
|
|
118
|
-
`SQLite database file not found: ${config.database}`,
|
|
119
|
-
),
|
|
119
|
+
uiError(`SQLite database file not found: ${config.database}`),
|
|
120
120
|
)
|
|
121
121
|
process.exit(1)
|
|
122
122
|
}
|
|
@@ -127,7 +127,7 @@ export const connectCommand = new Command('connect')
|
|
|
127
127
|
})
|
|
128
128
|
if (!running) {
|
|
129
129
|
console.error(
|
|
130
|
-
|
|
130
|
+
uiError(
|
|
131
131
|
`Container "${containerName}" is not running. Start it first.`,
|
|
132
132
|
),
|
|
133
133
|
)
|
|
@@ -145,17 +145,17 @@ export const connectCommand = new Command('connect')
|
|
|
145
145
|
if (!usqlInstalled) {
|
|
146
146
|
if (options.installTui) {
|
|
147
147
|
console.log(
|
|
148
|
-
|
|
148
|
+
uiInfo('Installing usql for enhanced shell experience...'),
|
|
149
149
|
)
|
|
150
150
|
const pm = await detectPackageManager()
|
|
151
151
|
if (pm) {
|
|
152
152
|
const result = await installUsql(pm)
|
|
153
153
|
if (result.success) {
|
|
154
|
-
console.log(
|
|
154
|
+
console.log(uiSuccess('usql installed successfully!'))
|
|
155
155
|
console.log()
|
|
156
156
|
} else {
|
|
157
157
|
console.error(
|
|
158
|
-
|
|
158
|
+
uiError(`Failed to install usql: ${result.error}`),
|
|
159
159
|
)
|
|
160
160
|
console.log()
|
|
161
161
|
console.log(chalk.gray('Manual installation:'))
|
|
@@ -165,7 +165,7 @@ export const connectCommand = new Command('connect')
|
|
|
165
165
|
process.exit(1)
|
|
166
166
|
}
|
|
167
167
|
} else {
|
|
168
|
-
console.error(
|
|
168
|
+
console.error(uiError('No supported package manager found'))
|
|
169
169
|
console.log()
|
|
170
170
|
console.log(chalk.gray('Manual installation:'))
|
|
171
171
|
for (const instruction of getUsqlManualInstructions()) {
|
|
@@ -174,7 +174,7 @@ export const connectCommand = new Command('connect')
|
|
|
174
174
|
process.exit(1)
|
|
175
175
|
}
|
|
176
176
|
} else {
|
|
177
|
-
console.error(
|
|
177
|
+
console.error(uiError('usql is not installed'))
|
|
178
178
|
console.log()
|
|
179
179
|
console.log(
|
|
180
180
|
chalk.gray('Install usql for enhanced shell experience:'),
|
|
@@ -194,7 +194,7 @@ export const connectCommand = new Command('connect')
|
|
|
194
194
|
if (usePgcli) {
|
|
195
195
|
if (engineName !== 'postgresql') {
|
|
196
196
|
console.error(
|
|
197
|
-
|
|
197
|
+
uiError('pgcli is only available for PostgreSQL containers'),
|
|
198
198
|
)
|
|
199
199
|
console.log(chalk.gray('For MySQL, use: spindb connect --mycli'))
|
|
200
200
|
process.exit(1)
|
|
@@ -205,17 +205,17 @@ export const connectCommand = new Command('connect')
|
|
|
205
205
|
if (!pgcliInstalled) {
|
|
206
206
|
if (options.installPgcli) {
|
|
207
207
|
console.log(
|
|
208
|
-
|
|
208
|
+
uiInfo('Installing pgcli for enhanced PostgreSQL shell...'),
|
|
209
209
|
)
|
|
210
210
|
const pm = await detectPackageManager()
|
|
211
211
|
if (pm) {
|
|
212
212
|
const result = await installPgcli(pm)
|
|
213
213
|
if (result.success) {
|
|
214
|
-
console.log(
|
|
214
|
+
console.log(uiSuccess('pgcli installed successfully!'))
|
|
215
215
|
console.log()
|
|
216
216
|
} else {
|
|
217
217
|
console.error(
|
|
218
|
-
|
|
218
|
+
uiError(`Failed to install pgcli: ${result.error}`),
|
|
219
219
|
)
|
|
220
220
|
console.log()
|
|
221
221
|
console.log(chalk.gray('Manual installation:'))
|
|
@@ -225,7 +225,7 @@ export const connectCommand = new Command('connect')
|
|
|
225
225
|
process.exit(1)
|
|
226
226
|
}
|
|
227
227
|
} else {
|
|
228
|
-
console.error(
|
|
228
|
+
console.error(uiError('No supported package manager found'))
|
|
229
229
|
console.log()
|
|
230
230
|
console.log(chalk.gray('Manual installation:'))
|
|
231
231
|
for (const instruction of getPgcliManualInstructions()) {
|
|
@@ -234,7 +234,7 @@ export const connectCommand = new Command('connect')
|
|
|
234
234
|
process.exit(1)
|
|
235
235
|
}
|
|
236
236
|
} else {
|
|
237
|
-
console.error(
|
|
237
|
+
console.error(uiError('pgcli is not installed'))
|
|
238
238
|
console.log()
|
|
239
239
|
console.log(
|
|
240
240
|
chalk.gray('Install pgcli for enhanced PostgreSQL shell:'),
|
|
@@ -253,7 +253,9 @@ export const connectCommand = new Command('connect')
|
|
|
253
253
|
const useMycli = options.mycli || options.installMycli
|
|
254
254
|
if (useMycli) {
|
|
255
255
|
if (engineName !== 'mysql') {
|
|
256
|
-
console.error(
|
|
256
|
+
console.error(
|
|
257
|
+
uiError('mycli is only available for MySQL containers'),
|
|
258
|
+
)
|
|
257
259
|
console.log(
|
|
258
260
|
chalk.gray('For PostgreSQL, use: spindb connect --pgcli'),
|
|
259
261
|
)
|
|
@@ -264,16 +266,18 @@ export const connectCommand = new Command('connect')
|
|
|
264
266
|
|
|
265
267
|
if (!mycliInstalled) {
|
|
266
268
|
if (options.installMycli) {
|
|
267
|
-
console.log(
|
|
269
|
+
console.log(
|
|
270
|
+
uiInfo('Installing mycli for enhanced MySQL shell...'),
|
|
271
|
+
)
|
|
268
272
|
const pm = await detectPackageManager()
|
|
269
273
|
if (pm) {
|
|
270
274
|
const result = await installMycli(pm)
|
|
271
275
|
if (result.success) {
|
|
272
|
-
console.log(
|
|
276
|
+
console.log(uiSuccess('mycli installed successfully!'))
|
|
273
277
|
console.log()
|
|
274
278
|
} else {
|
|
275
279
|
console.error(
|
|
276
|
-
|
|
280
|
+
uiError(`Failed to install mycli: ${result.error}`),
|
|
277
281
|
)
|
|
278
282
|
console.log()
|
|
279
283
|
console.log(chalk.gray('Manual installation:'))
|
|
@@ -283,7 +287,7 @@ export const connectCommand = new Command('connect')
|
|
|
283
287
|
process.exit(1)
|
|
284
288
|
}
|
|
285
289
|
} else {
|
|
286
|
-
console.error(
|
|
290
|
+
console.error(uiError('No supported package manager found'))
|
|
287
291
|
console.log()
|
|
288
292
|
console.log(chalk.gray('Manual installation:'))
|
|
289
293
|
for (const instruction of getMycliManualInstructions()) {
|
|
@@ -292,7 +296,7 @@ export const connectCommand = new Command('connect')
|
|
|
292
296
|
process.exit(1)
|
|
293
297
|
}
|
|
294
298
|
} else {
|
|
295
|
-
console.error(
|
|
299
|
+
console.error(uiError('mycli is not installed'))
|
|
296
300
|
console.log()
|
|
297
301
|
console.log(chalk.gray('Install mycli for enhanced MySQL shell:'))
|
|
298
302
|
console.log(chalk.cyan(' spindb connect --install-mycli'))
|
|
@@ -309,9 +313,13 @@ export const connectCommand = new Command('connect')
|
|
|
309
313
|
const useLitecli = options.litecli || options.installLitecli
|
|
310
314
|
if (useLitecli) {
|
|
311
315
|
if (engineName !== Engine.SQLite) {
|
|
312
|
-
console.error(
|
|
316
|
+
console.error(
|
|
317
|
+
uiError('litecli is only available for SQLite containers'),
|
|
318
|
+
)
|
|
313
319
|
if (engineName === 'postgresql') {
|
|
314
|
-
console.log(
|
|
320
|
+
console.log(
|
|
321
|
+
chalk.gray('For PostgreSQL, use: spindb connect --pgcli'),
|
|
322
|
+
)
|
|
315
323
|
} else if (engineName === 'mysql') {
|
|
316
324
|
console.log(chalk.gray('For MySQL, use: spindb connect --mycli'))
|
|
317
325
|
}
|
|
@@ -322,16 +330,18 @@ export const connectCommand = new Command('connect')
|
|
|
322
330
|
|
|
323
331
|
if (!litecliInstalled) {
|
|
324
332
|
if (options.installLitecli) {
|
|
325
|
-
console.log(
|
|
333
|
+
console.log(
|
|
334
|
+
uiInfo('Installing litecli for enhanced SQLite shell...'),
|
|
335
|
+
)
|
|
326
336
|
const pm = await detectPackageManager()
|
|
327
337
|
if (pm) {
|
|
328
338
|
const result = await installLitecli(pm)
|
|
329
339
|
if (result.success) {
|
|
330
|
-
console.log(
|
|
340
|
+
console.log(uiSuccess('litecli installed successfully!'))
|
|
331
341
|
console.log()
|
|
332
342
|
} else {
|
|
333
343
|
console.error(
|
|
334
|
-
|
|
344
|
+
uiError(`Failed to install litecli: ${result.error}`),
|
|
335
345
|
)
|
|
336
346
|
console.log()
|
|
337
347
|
console.log(chalk.gray('Manual installation:'))
|
|
@@ -341,7 +351,7 @@ export const connectCommand = new Command('connect')
|
|
|
341
351
|
process.exit(1)
|
|
342
352
|
}
|
|
343
353
|
} else {
|
|
344
|
-
console.error(
|
|
354
|
+
console.error(uiError('No supported package manager found'))
|
|
345
355
|
console.log()
|
|
346
356
|
console.log(chalk.gray('Manual installation:'))
|
|
347
357
|
for (const instruction of getLitecliManualInstructions()) {
|
|
@@ -350,9 +360,11 @@ export const connectCommand = new Command('connect')
|
|
|
350
360
|
process.exit(1)
|
|
351
361
|
}
|
|
352
362
|
} else {
|
|
353
|
-
console.error(
|
|
363
|
+
console.error(uiError('litecli is not installed'))
|
|
354
364
|
console.log()
|
|
355
|
-
console.log(
|
|
365
|
+
console.log(
|
|
366
|
+
chalk.gray('Install litecli for enhanced SQLite shell:'),
|
|
367
|
+
)
|
|
356
368
|
console.log(chalk.cyan(' spindb connect --install-litecli'))
|
|
357
369
|
console.log()
|
|
358
370
|
console.log(chalk.gray('Or install manually:'))
|
|
@@ -364,7 +376,7 @@ export const connectCommand = new Command('connect')
|
|
|
364
376
|
}
|
|
365
377
|
}
|
|
366
378
|
|
|
367
|
-
console.log(
|
|
379
|
+
console.log(uiInfo(`Connecting to ${containerName}:${database}...`))
|
|
368
380
|
console.log()
|
|
369
381
|
|
|
370
382
|
let clientCmd: string
|
|
@@ -415,7 +427,7 @@ export const connectCommand = new Command('connect')
|
|
|
415
427
|
|
|
416
428
|
clientProcess.on('error', (err: NodeJS.ErrnoException) => {
|
|
417
429
|
if (err.code === 'ENOENT') {
|
|
418
|
-
console.log(
|
|
430
|
+
console.log(uiWarning(`${clientCmd} not found on your system.`))
|
|
419
431
|
console.log()
|
|
420
432
|
console.log(
|
|
421
433
|
chalk.gray(' Install client tools or connect manually:'),
|
|
@@ -451,16 +463,16 @@ export const connectCommand = new Command('connect')
|
|
|
451
463
|
}
|
|
452
464
|
console.log()
|
|
453
465
|
} else {
|
|
454
|
-
console.error(
|
|
466
|
+
console.error(uiError(err.message))
|
|
455
467
|
}
|
|
456
468
|
})
|
|
457
469
|
|
|
458
470
|
await new Promise<void>((resolve) => {
|
|
459
471
|
clientProcess.on('close', () => resolve())
|
|
460
472
|
})
|
|
461
|
-
} catch (
|
|
462
|
-
const e =
|
|
463
|
-
console.error(
|
|
473
|
+
} catch (error) {
|
|
474
|
+
const e = error as Error
|
|
475
|
+
console.error(uiError(e.message))
|
|
464
476
|
process.exit(1)
|
|
465
477
|
}
|
|
466
478
|
},
|