spindb 0.4.1 → 0.5.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 +77 -100
- package/cli/commands/clone.ts +3 -1
- package/cli/commands/connect.ts +50 -24
- package/cli/commands/create.ts +237 -156
- package/cli/commands/delete.ts +3 -1
- package/cli/commands/list.ts +14 -3
- package/cli/commands/menu.ts +103 -46
- package/cli/commands/restore.ts +56 -19
- package/cli/commands/start.ts +30 -4
- package/cli/commands/stop.ts +3 -1
- package/cli/ui/prompts.ts +94 -31
- package/config/defaults.ts +40 -15
- package/config/engine-defaults.ts +84 -0
- package/config/os-dependencies.ts +68 -19
- package/config/paths.ts +77 -22
- package/core/binary-manager.ts +30 -5
- package/core/container-manager.ts +124 -60
- package/core/port-manager.ts +42 -31
- package/core/process-manager.ts +14 -6
- package/engines/index.ts +7 -2
- package/engines/mysql/binary-detection.ts +248 -0
- package/engines/mysql/index.ts +699 -0
- package/engines/postgresql/index.ts +13 -6
- package/package.json +4 -2
- package/types/index.ts +29 -5
package/cli/ui/prompts.ts
CHANGED
|
@@ -2,12 +2,13 @@ import inquirer from 'inquirer'
|
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import ora from 'ora'
|
|
4
4
|
import { listEngines, getEngine } from '../../engines'
|
|
5
|
-
import { defaults } from '../../config/defaults'
|
|
5
|
+
import { defaults, getEngineDefaults } from '../../config/defaults'
|
|
6
6
|
import { installPostgresBinaries } from '../../core/postgres-binary-manager'
|
|
7
7
|
import {
|
|
8
8
|
detectPackageManager,
|
|
9
9
|
getManualInstallInstructions,
|
|
10
10
|
getCurrentPlatform,
|
|
11
|
+
installEngineDependencies,
|
|
11
12
|
} from '../../core/dependency-manager'
|
|
12
13
|
import { getEngineDependencies } from '../../config/os-dependencies'
|
|
13
14
|
import type { ContainerConfig } from '../../types'
|
|
@@ -36,25 +37,26 @@ export async function promptContainerName(
|
|
|
36
37
|
return name
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Engine icons for display
|
|
42
|
+
*/
|
|
43
|
+
const engineIcons: Record<string, string> = {
|
|
44
|
+
postgresql: '🐘',
|
|
45
|
+
mysql: '🐬',
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* Prompt for database engine selection
|
|
41
50
|
*/
|
|
42
51
|
export async function promptEngine(): Promise<string> {
|
|
43
52
|
const engines = listEngines()
|
|
44
53
|
|
|
45
|
-
// Build choices from available engines
|
|
46
|
-
const choices =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})),
|
|
52
|
-
{
|
|
53
|
-
name: chalk.gray('🐬 MySQL (coming soon)'),
|
|
54
|
-
value: 'mysql',
|
|
55
|
-
disabled: 'Coming soon',
|
|
56
|
-
},
|
|
57
|
-
]
|
|
54
|
+
// Build choices from available engines
|
|
55
|
+
const choices = engines.map((e) => ({
|
|
56
|
+
name: `${engineIcons[e.name] || '🗄️'} ${e.displayName} ${chalk.gray(`(versions: ${e.supportedVersions.join(', ')})`)}`,
|
|
57
|
+
value: e.name,
|
|
58
|
+
short: e.displayName,
|
|
59
|
+
}))
|
|
58
60
|
|
|
59
61
|
const { engine } = await inquirer.prompt<{ engine: string }>([
|
|
60
62
|
{
|
|
@@ -69,8 +71,8 @@ export async function promptEngine(): Promise<string> {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
/**
|
|
72
|
-
* Prompt for
|
|
73
|
-
* Two-step selection: first major version, then specific minor version
|
|
74
|
+
* Prompt for database version
|
|
75
|
+
* Two-step selection: first major version, then specific minor version (if available)
|
|
74
76
|
*/
|
|
75
77
|
export async function promptVersion(engineName: string): Promise<string> {
|
|
76
78
|
const engine = getEngine(engineName)
|
|
@@ -112,13 +114,13 @@ export async function promptVersion(engineName: string): Promise<string> {
|
|
|
112
114
|
const countLabel =
|
|
113
115
|
versionCount > 0 ? chalk.gray(`(${versionCount} versions)`) : ''
|
|
114
116
|
const label = isLatestMajor
|
|
115
|
-
?
|
|
116
|
-
:
|
|
117
|
+
? `${engine.displayName} ${major} ${countLabel} ${chalk.green('← latest')}`
|
|
118
|
+
: `${engine.displayName} ${major} ${countLabel}`
|
|
117
119
|
|
|
118
120
|
majorChoices.push({
|
|
119
121
|
name: label,
|
|
120
122
|
value: major,
|
|
121
|
-
short:
|
|
123
|
+
short: `${engine.displayName} ${major}`,
|
|
122
124
|
})
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -150,7 +152,7 @@ export async function promptVersion(engineName: string): Promise<string> {
|
|
|
150
152
|
{
|
|
151
153
|
type: 'list',
|
|
152
154
|
name: 'version',
|
|
153
|
-
message: `Select
|
|
155
|
+
message: `Select ${engine.displayName} ${majorVersion} version:`,
|
|
154
156
|
choices: minorChoices,
|
|
155
157
|
default: minorVersions[0], // Default to latest
|
|
156
158
|
},
|
|
@@ -225,7 +227,7 @@ export async function promptContainerSelect(
|
|
|
225
227
|
name: 'container',
|
|
226
228
|
message,
|
|
227
229
|
choices: containers.map((c) => ({
|
|
228
|
-
name: `${c.name} ${chalk.gray(`(${c.engine} ${c.version}, port ${c.port})`)} ${
|
|
230
|
+
name: `${c.name} ${chalk.gray(`(${engineIcons[c.engine] || '🗄️'} ${c.engine} ${c.version}, port ${c.port})`)} ${
|
|
229
231
|
c.status === 'running'
|
|
230
232
|
? chalk.green('● running')
|
|
231
233
|
: chalk.gray('○ stopped')
|
|
@@ -279,16 +281,17 @@ export type CreateOptions = {
|
|
|
279
281
|
/**
|
|
280
282
|
* Full interactive create flow
|
|
281
283
|
*/
|
|
282
|
-
export async function promptCreateOptions(
|
|
283
|
-
defaultPort: number = defaults.port,
|
|
284
|
-
): Promise<CreateOptions> {
|
|
284
|
+
export async function promptCreateOptions(): Promise<CreateOptions> {
|
|
285
285
|
console.log(chalk.cyan('\n 🗄️ Create New Database Container\n'))
|
|
286
286
|
|
|
287
287
|
const engine = await promptEngine()
|
|
288
288
|
const version = await promptVersion(engine)
|
|
289
289
|
const name = await promptContainerName()
|
|
290
290
|
const database = await promptDatabaseName(name) // Default to container name
|
|
291
|
-
|
|
291
|
+
|
|
292
|
+
// Get engine-specific default port
|
|
293
|
+
const engineDefaults = getEngineDefaults(engine)
|
|
294
|
+
const port = await promptPort(engineDefaults.defaultPort)
|
|
292
295
|
|
|
293
296
|
return { name, engine, version, port, database }
|
|
294
297
|
}
|
|
@@ -393,8 +396,7 @@ export async function promptInstallDependencies(
|
|
|
393
396
|
|
|
394
397
|
console.log()
|
|
395
398
|
|
|
396
|
-
//
|
|
397
|
-
// Future engines will need their own install functions
|
|
399
|
+
// PostgreSQL has its own install function with extra logic
|
|
398
400
|
if (engine === 'postgresql') {
|
|
399
401
|
const success = await installPostgresBinaries()
|
|
400
402
|
|
|
@@ -410,11 +412,72 @@ export async function promptInstallDependencies(
|
|
|
410
412
|
return success
|
|
411
413
|
}
|
|
412
414
|
|
|
413
|
-
// For other engines,
|
|
415
|
+
// For other engines (MySQL, etc.), use the generic installer
|
|
414
416
|
console.log(
|
|
415
|
-
chalk.
|
|
417
|
+
chalk.cyan(` Installing ${engineName} with ${packageManager.name}...`),
|
|
416
418
|
)
|
|
417
|
-
console.log(chalk.gray('
|
|
419
|
+
console.log(chalk.gray(' You may be prompted for your password.'))
|
|
418
420
|
console.log()
|
|
419
|
-
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
const results = await installEngineDependencies(engine, packageManager)
|
|
424
|
+
const allSuccess = results.every((r) => r.success)
|
|
425
|
+
|
|
426
|
+
if (allSuccess) {
|
|
427
|
+
console.log()
|
|
428
|
+
console.log(
|
|
429
|
+
chalk.green(` ${engineName} tools installed successfully!`),
|
|
430
|
+
)
|
|
431
|
+
console.log(chalk.gray(' Continuing with your operation...'))
|
|
432
|
+
console.log()
|
|
433
|
+
return true
|
|
434
|
+
} else {
|
|
435
|
+
const failed = results.filter((r) => !r.success)
|
|
436
|
+
console.log()
|
|
437
|
+
console.log(chalk.red(' Some installations failed:'))
|
|
438
|
+
for (const f of failed) {
|
|
439
|
+
console.log(chalk.red(` ${f.dependency.name}: ${f.error}`))
|
|
440
|
+
}
|
|
441
|
+
console.log()
|
|
442
|
+
|
|
443
|
+
// Show manual install instructions
|
|
444
|
+
if (engineDeps) {
|
|
445
|
+
const instructions = getManualInstallInstructions(
|
|
446
|
+
engineDeps.dependencies[0],
|
|
447
|
+
platform,
|
|
448
|
+
)
|
|
449
|
+
if (instructions.length > 0) {
|
|
450
|
+
console.log(chalk.gray(' To install manually:'))
|
|
451
|
+
for (const instruction of instructions) {
|
|
452
|
+
console.log(chalk.gray(` ${instruction}`))
|
|
453
|
+
}
|
|
454
|
+
console.log()
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return false
|
|
459
|
+
}
|
|
460
|
+
} catch (err) {
|
|
461
|
+
const e = err as Error
|
|
462
|
+
console.log()
|
|
463
|
+
console.log(chalk.red(` Installation failed: ${e.message}`))
|
|
464
|
+
console.log()
|
|
465
|
+
|
|
466
|
+
// Show manual install instructions on error
|
|
467
|
+
if (engineDeps) {
|
|
468
|
+
const instructions = getManualInstallInstructions(
|
|
469
|
+
engineDeps.dependencies[0],
|
|
470
|
+
platform,
|
|
471
|
+
)
|
|
472
|
+
if (instructions.length > 0) {
|
|
473
|
+
console.log(chalk.gray(' To install manually:'))
|
|
474
|
+
for (const instruction of instructions) {
|
|
475
|
+
console.log(chalk.gray(` ${instruction}`))
|
|
476
|
+
}
|
|
477
|
+
console.log()
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return false
|
|
482
|
+
}
|
|
420
483
|
}
|
package/config/defaults.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
engineDefaults,
|
|
3
|
+
getEngineDefaults,
|
|
4
|
+
isEngineSupported,
|
|
5
|
+
getSupportedEngines,
|
|
6
|
+
type EngineDefaults,
|
|
7
|
+
} from './engine-defaults'
|
|
8
|
+
|
|
9
|
+
// Re-export engine-related functions and types
|
|
10
|
+
export {
|
|
11
|
+
engineDefaults,
|
|
12
|
+
getEngineDefaults,
|
|
13
|
+
isEngineSupported,
|
|
14
|
+
getSupportedEngines,
|
|
15
|
+
type EngineDefaults,
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
export type PlatformMappings = {
|
|
2
19
|
[key: string]: string
|
|
3
20
|
}
|
|
@@ -7,42 +24,50 @@ export type PortRange = {
|
|
|
7
24
|
end: number
|
|
8
25
|
}
|
|
9
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Legacy Defaults type - kept for backward compatibility
|
|
29
|
+
* New code should use getEngineDefaults(engine) instead
|
|
30
|
+
*/
|
|
10
31
|
export type Defaults = {
|
|
32
|
+
/** @deprecated Use getEngineDefaults(engine).defaultVersion instead */
|
|
11
33
|
postgresVersion: string
|
|
12
34
|
port: number
|
|
13
35
|
portRange: PortRange
|
|
14
36
|
engine: string
|
|
37
|
+
/** @deprecated Use getEngineDefaults(engine).supportedVersions instead */
|
|
15
38
|
supportedPostgresVersions: string[]
|
|
16
39
|
superuser: string
|
|
17
40
|
platformMappings: PlatformMappings
|
|
18
41
|
}
|
|
19
42
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
// Get PostgreSQL defaults from engine-defaults
|
|
44
|
+
const pgDefaults = engineDefaults.postgresql
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Default configuration values
|
|
48
|
+
* For backward compatibility, this defaults to PostgreSQL settings.
|
|
49
|
+
* New code should use getEngineDefaults(engine) for engine-specific defaults.
|
|
50
|
+
*/
|
|
23
51
|
export const defaults: Defaults = {
|
|
24
|
-
// Default PostgreSQL version
|
|
25
|
-
postgresVersion:
|
|
52
|
+
// Default PostgreSQL version (from engine defaults)
|
|
53
|
+
postgresVersion: pgDefaults.defaultVersion,
|
|
26
54
|
|
|
27
55
|
// Default port (standard PostgreSQL port)
|
|
28
|
-
port:
|
|
56
|
+
port: pgDefaults.defaultPort,
|
|
29
57
|
|
|
30
58
|
// Port range to scan if default is busy
|
|
31
|
-
portRange:
|
|
32
|
-
start: 5432,
|
|
33
|
-
end: 5500,
|
|
34
|
-
},
|
|
59
|
+
portRange: pgDefaults.portRange,
|
|
35
60
|
|
|
36
61
|
// Default engine
|
|
37
62
|
engine: 'postgresql',
|
|
38
63
|
|
|
39
|
-
// Supported PostgreSQL versions
|
|
40
|
-
supportedPostgresVersions:
|
|
64
|
+
// Supported PostgreSQL versions (from engine defaults)
|
|
65
|
+
supportedPostgresVersions: pgDefaults.supportedVersions,
|
|
41
66
|
|
|
42
|
-
// Default superuser
|
|
43
|
-
superuser:
|
|
67
|
+
// Default superuser (from engine defaults)
|
|
68
|
+
superuser: pgDefaults.superuser,
|
|
44
69
|
|
|
45
|
-
// Platform mappings for zonky.io binaries
|
|
70
|
+
// Platform mappings for zonky.io binaries (PostgreSQL specific)
|
|
46
71
|
platformMappings: {
|
|
47
72
|
'darwin-arm64': 'darwin-arm64v8',
|
|
48
73
|
'darwin-x64': 'darwin-amd64',
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-specific default configurations
|
|
3
|
+
* Extracted for dependency injection pattern - allows each engine to define its own defaults
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type EngineDefaults = {
|
|
7
|
+
/** Default version to use when not specified */
|
|
8
|
+
defaultVersion: string
|
|
9
|
+
/** Default port for this engine */
|
|
10
|
+
defaultPort: number
|
|
11
|
+
/** Port range to scan if default is busy */
|
|
12
|
+
portRange: { start: number; end: number }
|
|
13
|
+
/** Supported major versions */
|
|
14
|
+
supportedVersions: string[]
|
|
15
|
+
/** Default superuser name */
|
|
16
|
+
superuser: string
|
|
17
|
+
/** Connection string scheme (e.g., 'postgresql', 'mysql') */
|
|
18
|
+
connectionScheme: string
|
|
19
|
+
/** Log file name within container directory */
|
|
20
|
+
logFileName: string
|
|
21
|
+
/** PID file name (relative to data directory or container) */
|
|
22
|
+
pidFileName: string
|
|
23
|
+
/** Subdirectory for data files within container */
|
|
24
|
+
dataSubdir: string
|
|
25
|
+
/** Client tools required for this engine */
|
|
26
|
+
clientTools: string[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const engineDefaults: Record<string, EngineDefaults> = {
|
|
30
|
+
postgresql: {
|
|
31
|
+
defaultVersion: '16',
|
|
32
|
+
defaultPort: 5432,
|
|
33
|
+
portRange: { start: 5432, end: 5500 },
|
|
34
|
+
supportedVersions: ['14', '15', '16', '17'],
|
|
35
|
+
superuser: 'postgres',
|
|
36
|
+
connectionScheme: 'postgresql',
|
|
37
|
+
logFileName: 'postgres.log',
|
|
38
|
+
pidFileName: 'postmaster.pid',
|
|
39
|
+
dataSubdir: 'data',
|
|
40
|
+
clientTools: ['psql', 'pg_dump', 'pg_restore', 'pg_basebackup'],
|
|
41
|
+
},
|
|
42
|
+
mysql: {
|
|
43
|
+
defaultVersion: '9.0',
|
|
44
|
+
defaultPort: 3306,
|
|
45
|
+
portRange: { start: 3306, end: 3400 },
|
|
46
|
+
supportedVersions: ['5.7', '8.0', '8.4', '9.0'],
|
|
47
|
+
superuser: 'root',
|
|
48
|
+
connectionScheme: 'mysql',
|
|
49
|
+
logFileName: 'mysql.log',
|
|
50
|
+
pidFileName: 'mysql.pid',
|
|
51
|
+
dataSubdir: 'data',
|
|
52
|
+
clientTools: ['mysql', 'mysqldump', 'mysqlpump'],
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get engine defaults by name
|
|
58
|
+
* @throws Error if engine is not found
|
|
59
|
+
*/
|
|
60
|
+
export function getEngineDefaults(engine: string): EngineDefaults {
|
|
61
|
+
const normalized = engine.toLowerCase()
|
|
62
|
+
const defaults = engineDefaults[normalized]
|
|
63
|
+
if (!defaults) {
|
|
64
|
+
const available = Object.keys(engineDefaults).join(', ')
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Unknown engine "${engine}". Available engines: ${available}`,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
return defaults
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if an engine is supported
|
|
74
|
+
*/
|
|
75
|
+
export function isEngineSupported(engine: string): boolean {
|
|
76
|
+
return engine.toLowerCase() in engineDefaults
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get list of all supported engine names
|
|
81
|
+
*/
|
|
82
|
+
export function getSupportedEngines(): string[] {
|
|
83
|
+
return Object.keys(engineDefaults)
|
|
84
|
+
}
|
|
@@ -241,28 +241,53 @@ const postgresqlDependencies: EngineDependencies = {
|
|
|
241
241
|
|
|
242
242
|
const mysqlDependencies: EngineDependencies = {
|
|
243
243
|
engine: 'mysql',
|
|
244
|
-
displayName: 'MySQL',
|
|
244
|
+
displayName: 'MySQL/MariaDB',
|
|
245
245
|
dependencies: [
|
|
246
|
+
{
|
|
247
|
+
name: 'mysqld',
|
|
248
|
+
binary: 'mysqld',
|
|
249
|
+
description: 'MySQL/MariaDB server daemon',
|
|
250
|
+
packages: {
|
|
251
|
+
brew: { package: 'mysql' },
|
|
252
|
+
// Modern Debian/Ubuntu use mariadb-server (MySQL-compatible)
|
|
253
|
+
apt: { package: 'mariadb-server' },
|
|
254
|
+
yum: { package: 'mariadb-server' },
|
|
255
|
+
dnf: { package: 'mariadb-server' },
|
|
256
|
+
pacman: { package: 'mariadb' },
|
|
257
|
+
},
|
|
258
|
+
manualInstall: {
|
|
259
|
+
darwin: [
|
|
260
|
+
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
261
|
+
'Then run: brew install mysql',
|
|
262
|
+
],
|
|
263
|
+
linux: [
|
|
264
|
+
'Debian/Ubuntu: sudo apt install mariadb-server',
|
|
265
|
+
'CentOS/RHEL: sudo yum install mariadb-server',
|
|
266
|
+
'Fedora: sudo dnf install mariadb-server',
|
|
267
|
+
'Arch: sudo pacman -S mariadb',
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
},
|
|
246
271
|
{
|
|
247
272
|
name: 'mysql',
|
|
248
273
|
binary: 'mysql',
|
|
249
|
-
description: 'MySQL command-line client',
|
|
274
|
+
description: 'MySQL/MariaDB command-line client',
|
|
250
275
|
packages: {
|
|
251
|
-
brew: { package: 'mysql
|
|
252
|
-
apt: { package: '
|
|
253
|
-
yum: { package: '
|
|
254
|
-
dnf: { package: '
|
|
276
|
+
brew: { package: 'mysql' },
|
|
277
|
+
apt: { package: 'mariadb-client' },
|
|
278
|
+
yum: { package: 'mariadb' },
|
|
279
|
+
dnf: { package: 'mariadb' },
|
|
255
280
|
pacman: { package: 'mariadb-clients' },
|
|
256
281
|
},
|
|
257
282
|
manualInstall: {
|
|
258
283
|
darwin: [
|
|
259
284
|
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
260
|
-
'Then run: brew install mysql
|
|
285
|
+
'Then run: brew install mysql',
|
|
261
286
|
],
|
|
262
287
|
linux: [
|
|
263
|
-
'Ubuntu
|
|
264
|
-
'CentOS/RHEL: sudo yum install
|
|
265
|
-
'Fedora: sudo dnf install
|
|
288
|
+
'Debian/Ubuntu: sudo apt install mariadb-client',
|
|
289
|
+
'CentOS/RHEL: sudo yum install mariadb',
|
|
290
|
+
'Fedora: sudo dnf install mariadb',
|
|
266
291
|
'Arch: sudo pacman -S mariadb-clients',
|
|
267
292
|
],
|
|
268
293
|
},
|
|
@@ -270,23 +295,47 @@ const mysqlDependencies: EngineDependencies = {
|
|
|
270
295
|
{
|
|
271
296
|
name: 'mysqldump',
|
|
272
297
|
binary: 'mysqldump',
|
|
273
|
-
description: 'MySQL database backup utility',
|
|
298
|
+
description: 'MySQL/MariaDB database backup utility',
|
|
299
|
+
packages: {
|
|
300
|
+
brew: { package: 'mysql' },
|
|
301
|
+
apt: { package: 'mariadb-client' },
|
|
302
|
+
yum: { package: 'mariadb' },
|
|
303
|
+
dnf: { package: 'mariadb' },
|
|
304
|
+
pacman: { package: 'mariadb-clients' },
|
|
305
|
+
},
|
|
306
|
+
manualInstall: {
|
|
307
|
+
darwin: [
|
|
308
|
+
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
309
|
+
'Then run: brew install mysql',
|
|
310
|
+
],
|
|
311
|
+
linux: [
|
|
312
|
+
'Debian/Ubuntu: sudo apt install mariadb-client',
|
|
313
|
+
'CentOS/RHEL: sudo yum install mariadb',
|
|
314
|
+
'Fedora: sudo dnf install mariadb',
|
|
315
|
+
'Arch: sudo pacman -S mariadb-clients',
|
|
316
|
+
],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: 'mysqladmin',
|
|
321
|
+
binary: 'mysqladmin',
|
|
322
|
+
description: 'MySQL/MariaDB server administration utility',
|
|
274
323
|
packages: {
|
|
275
|
-
brew: { package: 'mysql
|
|
276
|
-
apt: { package: '
|
|
277
|
-
yum: { package: '
|
|
278
|
-
dnf: { package: '
|
|
324
|
+
brew: { package: 'mysql' },
|
|
325
|
+
apt: { package: 'mariadb-client' },
|
|
326
|
+
yum: { package: 'mariadb' },
|
|
327
|
+
dnf: { package: 'mariadb' },
|
|
279
328
|
pacman: { package: 'mariadb-clients' },
|
|
280
329
|
},
|
|
281
330
|
manualInstall: {
|
|
282
331
|
darwin: [
|
|
283
332
|
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
284
|
-
'Then run: brew install mysql
|
|
333
|
+
'Then run: brew install mysql',
|
|
285
334
|
],
|
|
286
335
|
linux: [
|
|
287
|
-
'Ubuntu
|
|
288
|
-
'CentOS/RHEL: sudo yum install
|
|
289
|
-
'Fedora: sudo dnf install
|
|
336
|
+
'Debian/Ubuntu: sudo apt install mariadb-client',
|
|
337
|
+
'CentOS/RHEL: sudo yum install mariadb',
|
|
338
|
+
'Fedora: sudo dnf install mariadb',
|
|
290
339
|
'Arch: sudo pacman -S mariadb-clients',
|
|
291
340
|
],
|
|
292
341
|
},
|
package/config/paths.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'os'
|
|
2
2
|
import { join } from 'path'
|
|
3
3
|
import { execSync } from 'child_process'
|
|
4
|
+
import { getEngineDefaults } from './engine-defaults'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Get the real user's home directory, even when running under sudo.
|
|
@@ -41,6 +42,23 @@ function getRealHomeDir(): string {
|
|
|
41
42
|
|
|
42
43
|
const SPINDB_HOME = join(getRealHomeDir(), '.spindb')
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Options for container path functions
|
|
47
|
+
*/
|
|
48
|
+
type ContainerPathOptions = {
|
|
49
|
+
engine: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Options for binary path functions
|
|
54
|
+
*/
|
|
55
|
+
type BinaryPathOptions = {
|
|
56
|
+
engine: string
|
|
57
|
+
version: string
|
|
58
|
+
platform: string
|
|
59
|
+
arch: string
|
|
60
|
+
}
|
|
61
|
+
|
|
44
62
|
export const paths = {
|
|
45
63
|
// Root directory for all spindb data
|
|
46
64
|
root: SPINDB_HOME,
|
|
@@ -54,38 +72,75 @@ export const paths = {
|
|
|
54
72
|
// Global config file
|
|
55
73
|
config: join(SPINDB_HOME, 'config.json'),
|
|
56
74
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
platform
|
|
62
|
-
arch: string,
|
|
63
|
-
): string {
|
|
75
|
+
/**
|
|
76
|
+
* Get path for a specific binary version
|
|
77
|
+
*/
|
|
78
|
+
getBinaryPath(options: BinaryPathOptions): string {
|
|
79
|
+
const { engine, version, platform, arch } = options
|
|
64
80
|
return join(this.bin, `${engine}-${version}-${platform}-${arch}`)
|
|
65
81
|
},
|
|
66
82
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Get path for a specific container
|
|
85
|
+
* New structure: ~/.spindb/containers/{engine}/{name}/
|
|
86
|
+
*/
|
|
87
|
+
getContainerPath(name: string, options: ContainerPathOptions): string {
|
|
88
|
+
const { engine } = options
|
|
89
|
+
return join(this.containers, engine, name)
|
|
70
90
|
},
|
|
71
91
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Get path for container config file
|
|
94
|
+
*/
|
|
95
|
+
getContainerConfigPath(name: string, options: ContainerPathOptions): string {
|
|
96
|
+
const { engine } = options
|
|
97
|
+
return join(this.containers, engine, name, 'container.json')
|
|
75
98
|
},
|
|
76
99
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Get path for container data directory
|
|
102
|
+
*/
|
|
103
|
+
getContainerDataPath(name: string, options: ContainerPathOptions): string {
|
|
104
|
+
const { engine } = options
|
|
105
|
+
const engineDef = getEngineDefaults(engine)
|
|
106
|
+
return join(this.containers, engine, name, engineDef.dataSubdir)
|
|
80
107
|
},
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Get path for container log file
|
|
111
|
+
*/
|
|
112
|
+
getContainerLogPath(name: string, options: ContainerPathOptions): string {
|
|
113
|
+
const { engine } = options
|
|
114
|
+
const engineDef = getEngineDefaults(engine)
|
|
115
|
+
return join(this.containers, engine, name, engineDef.logFileName)
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get path for container PID file
|
|
120
|
+
* Note: For PostgreSQL, PID is inside data dir. For MySQL, it may differ.
|
|
121
|
+
*/
|
|
122
|
+
getContainerPidPath(name: string, options: ContainerPathOptions): string {
|
|
123
|
+
const { engine } = options
|
|
124
|
+
const engineDef = getEngineDefaults(engine)
|
|
125
|
+
// PostgreSQL: data/postmaster.pid
|
|
126
|
+
// MySQL: data/mysql.pid (or just mysql.pid depending on config)
|
|
127
|
+
if (engine === 'postgresql') {
|
|
128
|
+
return join(
|
|
129
|
+
this.containers,
|
|
130
|
+
engine,
|
|
131
|
+
name,
|
|
132
|
+
engineDef.dataSubdir,
|
|
133
|
+
engineDef.pidFileName,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
// MySQL and others: PID file at container level
|
|
137
|
+
return join(this.containers, engine, name, engineDef.pidFileName)
|
|
85
138
|
},
|
|
86
139
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Get path for engine-specific containers directory
|
|
142
|
+
*/
|
|
143
|
+
getEngineContainersPath(engine: string): string {
|
|
144
|
+
return join(this.containers, engine)
|
|
90
145
|
},
|
|
91
146
|
}
|