spindb 0.3.6 → 0.4.1
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 +62 -8
- package/cli/commands/create.ts +275 -1
- package/cli/commands/deps.ts +326 -0
- package/cli/commands/menu.ts +387 -29
- package/cli/commands/restore.ts +173 -16
- package/cli/index.ts +2 -0
- package/cli/ui/prompts.ts +133 -0
- package/config/os-dependencies.ts +358 -0
- package/config/paths.ts +39 -1
- package/core/dependency-manager.ts +429 -0
- package/core/postgres-binary-manager.ts +44 -28
- package/engines/base-engine.ts +9 -0
- package/engines/postgresql/index.ts +53 -0
- package/package.json +2 -2
- package/types/index.ts +7 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { header, success, warning, error } from '../ui/theme'
|
|
4
|
+
import { createSpinner } from '../ui/spinner'
|
|
5
|
+
import {
|
|
6
|
+
detectPackageManager,
|
|
7
|
+
checkEngineDependencies,
|
|
8
|
+
getMissingDependencies,
|
|
9
|
+
getAllMissingDependencies,
|
|
10
|
+
installEngineDependencies,
|
|
11
|
+
installAllDependencies,
|
|
12
|
+
getManualInstallInstructions,
|
|
13
|
+
getCurrentPlatform,
|
|
14
|
+
type DependencyStatus,
|
|
15
|
+
} from '../../core/dependency-manager'
|
|
16
|
+
import {
|
|
17
|
+
engineDependencies,
|
|
18
|
+
getEngineDependencies,
|
|
19
|
+
} from '../../config/os-dependencies'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format dependency status for display
|
|
23
|
+
*/
|
|
24
|
+
function formatStatus(status: DependencyStatus): string {
|
|
25
|
+
const { dependency, installed, path, version } = status
|
|
26
|
+
|
|
27
|
+
if (installed) {
|
|
28
|
+
const versionStr = version ? ` (${version})` : ''
|
|
29
|
+
const pathStr = path ? chalk.gray(` → ${path}`) : ''
|
|
30
|
+
return ` ${chalk.green('✓')} ${dependency.name}${versionStr}${pathStr}`
|
|
31
|
+
} else {
|
|
32
|
+
return ` ${chalk.red('✗')} ${dependency.name} ${chalk.gray('- not installed')}`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const depsCommand = new Command('deps').description(
|
|
37
|
+
'Manage OS-level database client dependencies',
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// deps check
|
|
42
|
+
// =============================================================================
|
|
43
|
+
|
|
44
|
+
depsCommand
|
|
45
|
+
.command('check')
|
|
46
|
+
.description('Check status of database client tools')
|
|
47
|
+
.option('-e, --engine <engine>', 'Check dependencies for a specific engine')
|
|
48
|
+
.option('-a, --all', 'Check all dependencies for all engines')
|
|
49
|
+
.action(async (options: { engine?: string; all?: boolean }) => {
|
|
50
|
+
console.log(header('Dependency Status'))
|
|
51
|
+
console.log()
|
|
52
|
+
|
|
53
|
+
// Detect package manager
|
|
54
|
+
const packageManager = await detectPackageManager()
|
|
55
|
+
if (packageManager) {
|
|
56
|
+
console.log(` Package Manager: ${chalk.cyan(packageManager.name)}`)
|
|
57
|
+
} else {
|
|
58
|
+
console.log(` Package Manager: ${chalk.yellow('Not detected')}`)
|
|
59
|
+
}
|
|
60
|
+
console.log()
|
|
61
|
+
|
|
62
|
+
if (options.all || (!options.engine && !options.all)) {
|
|
63
|
+
// Check all engines
|
|
64
|
+
for (const engineConfig of engineDependencies) {
|
|
65
|
+
console.log(chalk.bold(`${engineConfig.displayName}:`))
|
|
66
|
+
|
|
67
|
+
const statuses = await checkEngineDependencies(engineConfig.engine)
|
|
68
|
+
for (const status of statuses) {
|
|
69
|
+
console.log(formatStatus(status))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const installed = statuses.filter((s) => s.installed).length
|
|
73
|
+
const total = statuses.length
|
|
74
|
+
if (installed === total) {
|
|
75
|
+
console.log(chalk.green(` All ${total} dependencies installed`))
|
|
76
|
+
} else {
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.yellow(` ${installed}/${total} dependencies installed`),
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
console.log()
|
|
82
|
+
}
|
|
83
|
+
} else if (options.engine) {
|
|
84
|
+
// Check specific engine
|
|
85
|
+
const engineConfig = getEngineDependencies(options.engine)
|
|
86
|
+
if (!engineConfig) {
|
|
87
|
+
console.error(error(`Unknown engine: ${options.engine}`))
|
|
88
|
+
console.log(
|
|
89
|
+
chalk.gray(
|
|
90
|
+
` Available engines: ${engineDependencies.map((e) => e.engine).join(', ')}`,
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
process.exit(1)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(chalk.bold(`${engineConfig.displayName}:`))
|
|
97
|
+
|
|
98
|
+
const statuses = await checkEngineDependencies(options.engine)
|
|
99
|
+
for (const status of statuses) {
|
|
100
|
+
console.log(formatStatus(status))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const installed = statuses.filter((s) => s.installed).length
|
|
104
|
+
const total = statuses.length
|
|
105
|
+
console.log()
|
|
106
|
+
if (installed === total) {
|
|
107
|
+
console.log(success(`All ${total} dependencies installed`))
|
|
108
|
+
} else {
|
|
109
|
+
console.log(warning(`${installed}/${total} dependencies installed`))
|
|
110
|
+
console.log()
|
|
111
|
+
console.log(
|
|
112
|
+
chalk.gray(` Run: spindb deps install --engine ${options.engine}`),
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// deps install
|
|
120
|
+
// =============================================================================
|
|
121
|
+
|
|
122
|
+
depsCommand
|
|
123
|
+
.command('install')
|
|
124
|
+
.description('Install missing database client tools')
|
|
125
|
+
.option(
|
|
126
|
+
'-e, --engine <engine>',
|
|
127
|
+
'Install dependencies for a specific engine (e.g., postgresql, mysql)',
|
|
128
|
+
)
|
|
129
|
+
.option('-a, --all', 'Install all missing dependencies for all engines')
|
|
130
|
+
.action(async (options: { engine?: string; all?: boolean }) => {
|
|
131
|
+
// Detect package manager first
|
|
132
|
+
const packageManager = await detectPackageManager()
|
|
133
|
+
|
|
134
|
+
if (!packageManager) {
|
|
135
|
+
console.log(error('No supported package manager detected'))
|
|
136
|
+
console.log()
|
|
137
|
+
|
|
138
|
+
const platform = getCurrentPlatform()
|
|
139
|
+
if (platform === 'darwin') {
|
|
140
|
+
console.log(chalk.gray(' macOS: Install Homebrew first:'))
|
|
141
|
+
console.log(
|
|
142
|
+
chalk.cyan(
|
|
143
|
+
' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
} else {
|
|
147
|
+
console.log(
|
|
148
|
+
chalk.gray(' Supported package managers: apt, yum, dnf, pacman'),
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
process.exit(1)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(header('Installing Dependencies'))
|
|
155
|
+
console.log()
|
|
156
|
+
console.log(` Using: ${chalk.cyan(packageManager.name)}`)
|
|
157
|
+
console.log()
|
|
158
|
+
|
|
159
|
+
if (options.all) {
|
|
160
|
+
// Install all missing dependencies
|
|
161
|
+
const missing = await getAllMissingDependencies()
|
|
162
|
+
|
|
163
|
+
if (missing.length === 0) {
|
|
164
|
+
console.log(success('All dependencies are already installed'))
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(` Missing: ${missing.map((d) => d.name).join(', ')}`)
|
|
169
|
+
console.log()
|
|
170
|
+
|
|
171
|
+
const spinner = createSpinner('Installing dependencies...')
|
|
172
|
+
spinner.start()
|
|
173
|
+
|
|
174
|
+
const results = await installAllDependencies(packageManager)
|
|
175
|
+
|
|
176
|
+
const succeeded = results.filter((r) => r.success)
|
|
177
|
+
const failed = results.filter((r) => !r.success)
|
|
178
|
+
|
|
179
|
+
if (failed.length === 0) {
|
|
180
|
+
spinner.succeed('All dependencies installed successfully')
|
|
181
|
+
} else {
|
|
182
|
+
spinner.warn('Some dependencies failed to install')
|
|
183
|
+
console.log()
|
|
184
|
+
for (const f of failed) {
|
|
185
|
+
console.log(error(` ${f.dependency.name}: ${f.error}`))
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (succeeded.length > 0) {
|
|
190
|
+
console.log()
|
|
191
|
+
console.log(success(`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`))
|
|
192
|
+
}
|
|
193
|
+
} else if (options.engine) {
|
|
194
|
+
// Install dependencies for specific engine
|
|
195
|
+
const engineConfig = getEngineDependencies(options.engine)
|
|
196
|
+
if (!engineConfig) {
|
|
197
|
+
console.error(error(`Unknown engine: ${options.engine}`))
|
|
198
|
+
console.log(
|
|
199
|
+
chalk.gray(
|
|
200
|
+
` Available engines: ${engineDependencies.map((e) => e.engine).join(', ')}`,
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
process.exit(1)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const missing = await getMissingDependencies(options.engine)
|
|
207
|
+
|
|
208
|
+
if (missing.length === 0) {
|
|
209
|
+
console.log(
|
|
210
|
+
success(`All ${engineConfig.displayName} dependencies are installed`),
|
|
211
|
+
)
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(` Engine: ${chalk.cyan(engineConfig.displayName)}`)
|
|
216
|
+
console.log(` Missing: ${missing.map((d) => d.name).join(', ')}`)
|
|
217
|
+
console.log()
|
|
218
|
+
|
|
219
|
+
const spinner = createSpinner(
|
|
220
|
+
`Installing ${engineConfig.displayName} dependencies...`,
|
|
221
|
+
)
|
|
222
|
+
spinner.start()
|
|
223
|
+
|
|
224
|
+
const results = await installEngineDependencies(
|
|
225
|
+
options.engine,
|
|
226
|
+
packageManager,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
const succeeded = results.filter((r) => r.success)
|
|
230
|
+
const failed = results.filter((r) => !r.success)
|
|
231
|
+
|
|
232
|
+
if (failed.length === 0) {
|
|
233
|
+
spinner.succeed(
|
|
234
|
+
`${engineConfig.displayName} dependencies installed successfully`,
|
|
235
|
+
)
|
|
236
|
+
} else {
|
|
237
|
+
spinner.warn('Some dependencies failed to install')
|
|
238
|
+
console.log()
|
|
239
|
+
for (const f of failed) {
|
|
240
|
+
console.log(error(` ${f.dependency.name}: ${f.error}`))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Show manual instructions
|
|
244
|
+
console.log()
|
|
245
|
+
console.log(chalk.gray(' Manual installation:'))
|
|
246
|
+
const instructions = getManualInstallInstructions(
|
|
247
|
+
missing[0],
|
|
248
|
+
getCurrentPlatform(),
|
|
249
|
+
)
|
|
250
|
+
for (const instruction of instructions) {
|
|
251
|
+
console.log(chalk.gray(` ${instruction}`))
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (succeeded.length > 0) {
|
|
256
|
+
console.log()
|
|
257
|
+
console.log(success(`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`))
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
// Default: install PostgreSQL dependencies (most common use case)
|
|
261
|
+
console.log(
|
|
262
|
+
chalk.gray(
|
|
263
|
+
' No engine specified, defaulting to PostgreSQL. Use --all for all engines.',
|
|
264
|
+
),
|
|
265
|
+
)
|
|
266
|
+
console.log()
|
|
267
|
+
|
|
268
|
+
const missing = await getMissingDependencies('postgresql')
|
|
269
|
+
|
|
270
|
+
if (missing.length === 0) {
|
|
271
|
+
console.log(success('All PostgreSQL dependencies are installed'))
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
console.log(` Missing: ${missing.map((d) => d.name).join(', ')}`)
|
|
276
|
+
console.log()
|
|
277
|
+
|
|
278
|
+
const spinner = createSpinner('Installing PostgreSQL dependencies...')
|
|
279
|
+
spinner.start()
|
|
280
|
+
|
|
281
|
+
const results = await installEngineDependencies('postgresql', packageManager)
|
|
282
|
+
|
|
283
|
+
const succeeded = results.filter((r) => r.success)
|
|
284
|
+
const failed = results.filter((r) => !r.success)
|
|
285
|
+
|
|
286
|
+
if (failed.length === 0) {
|
|
287
|
+
spinner.succeed('PostgreSQL dependencies installed successfully')
|
|
288
|
+
} else {
|
|
289
|
+
spinner.warn('Some dependencies failed to install')
|
|
290
|
+
console.log()
|
|
291
|
+
for (const f of failed) {
|
|
292
|
+
console.log(error(` ${f.dependency.name}: ${f.error}`))
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (succeeded.length > 0) {
|
|
297
|
+
console.log()
|
|
298
|
+
console.log(success(`Installed: ${succeeded.map((r) => r.dependency.name).join(', ')}`))
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
// =============================================================================
|
|
304
|
+
// deps list
|
|
305
|
+
// =============================================================================
|
|
306
|
+
|
|
307
|
+
depsCommand
|
|
308
|
+
.command('list')
|
|
309
|
+
.description('List all supported dependencies')
|
|
310
|
+
.action(async () => {
|
|
311
|
+
console.log(header('Supported Dependencies'))
|
|
312
|
+
console.log()
|
|
313
|
+
|
|
314
|
+
for (const engineConfig of engineDependencies) {
|
|
315
|
+
console.log(chalk.bold(`${engineConfig.displayName}:`))
|
|
316
|
+
|
|
317
|
+
for (const dep of engineConfig.dependencies) {
|
|
318
|
+
console.log(` ${chalk.cyan(dep.name)} - ${dep.description}`)
|
|
319
|
+
}
|
|
320
|
+
console.log()
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
console.log(chalk.gray('Use: spindb deps check'))
|
|
324
|
+
console.log(chalk.gray(' spindb deps install --engine <engine>'))
|
|
325
|
+
console.log(chalk.gray(' spindb deps install --all'))
|
|
326
|
+
})
|