spindb 0.5.2 → 0.5.4
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 +188 -9
- package/cli/commands/connect.ts +334 -105
- 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/list.ts +1 -1
- package/cli/commands/menu.ts +664 -167
- package/cli/commands/restore.ts +11 -25
- 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 +20 -12
- package/cli/ui/theme.ts +1 -1
- package/config/engine-defaults.ts +24 -1
- package/config/os-dependencies.ts +151 -113
- package/config/paths.ts +7 -36
- package/core/binary-manager.ts +12 -6
- package/core/config-manager.ts +17 -5
- package/core/dependency-manager.ts +144 -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 +35 -4
- 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
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
* across different operating systems and package managers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { getPostgresHomebrewPackage } from './engine-defaults'
|
|
9
|
+
|
|
8
10
|
export type PackageManagerId = 'brew' | 'apt' | 'yum' | 'dnf' | 'pacman'
|
|
9
11
|
|
|
10
|
-
export type Platform = 'darwin' | 'linux'
|
|
12
|
+
export type Platform = 'darwin' | 'linux' | 'win32'
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Package definition for a specific package manager
|
|
@@ -116,122 +118,66 @@ export const packageManagers: PackageManagerConfig[] = [
|
|
|
116
118
|
// PostgreSQL Dependencies
|
|
117
119
|
// =============================================================================
|
|
118
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Helper to create PostgreSQL client tool dependency
|
|
123
|
+
* Uses getPostgresHomebrewPackage() to get the current latest version
|
|
124
|
+
*/
|
|
125
|
+
function createPostgresDependency(
|
|
126
|
+
name: string,
|
|
127
|
+
binary: string,
|
|
128
|
+
description: string,
|
|
129
|
+
): Dependency {
|
|
130
|
+
const pgPackage = getPostgresHomebrewPackage()
|
|
131
|
+
return {
|
|
132
|
+
name,
|
|
133
|
+
binary,
|
|
134
|
+
description,
|
|
135
|
+
packages: {
|
|
136
|
+
brew: {
|
|
137
|
+
package: pgPackage,
|
|
138
|
+
postInstall: [`brew link --overwrite ${pgPackage}`],
|
|
139
|
+
},
|
|
140
|
+
apt: { package: 'postgresql-client' },
|
|
141
|
+
yum: { package: 'postgresql' },
|
|
142
|
+
dnf: { package: 'postgresql' },
|
|
143
|
+
pacman: { package: 'postgresql-libs' },
|
|
144
|
+
},
|
|
145
|
+
manualInstall: {
|
|
146
|
+
darwin: [
|
|
147
|
+
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
148
|
+
`Then run: brew install ${pgPackage} && brew link --overwrite ${pgPackage}`,
|
|
149
|
+
'Or install Postgres.app: https://postgresapp.com/downloads.html',
|
|
150
|
+
],
|
|
151
|
+
linux: [
|
|
152
|
+
'Ubuntu/Debian: sudo apt install postgresql-client',
|
|
153
|
+
'CentOS/RHEL: sudo yum install postgresql',
|
|
154
|
+
'Fedora: sudo dnf install postgresql',
|
|
155
|
+
'Arch: sudo pacman -S postgresql-libs',
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
119
161
|
const postgresqlDependencies: EngineDependencies = {
|
|
120
162
|
engine: 'postgresql',
|
|
121
163
|
displayName: 'PostgreSQL',
|
|
122
164
|
dependencies: [
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
140
|
-
'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
|
|
141
|
-
'Or install Postgres.app: https://postgresapp.com/downloads.html',
|
|
142
|
-
],
|
|
143
|
-
linux: [
|
|
144
|
-
'Ubuntu/Debian: sudo apt install postgresql-client',
|
|
145
|
-
'CentOS/RHEL: sudo yum install postgresql',
|
|
146
|
-
'Fedora: sudo dnf install postgresql',
|
|
147
|
-
'Arch: sudo pacman -S postgresql-libs',
|
|
148
|
-
],
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: 'pg_dump',
|
|
153
|
-
binary: 'pg_dump',
|
|
154
|
-
description: 'PostgreSQL database backup utility',
|
|
155
|
-
packages: {
|
|
156
|
-
brew: {
|
|
157
|
-
package: 'postgresql@17',
|
|
158
|
-
postInstall: ['brew link --overwrite postgresql@17'],
|
|
159
|
-
},
|
|
160
|
-
apt: { package: 'postgresql-client' },
|
|
161
|
-
yum: { package: 'postgresql' },
|
|
162
|
-
dnf: { package: 'postgresql' },
|
|
163
|
-
pacman: { package: 'postgresql-libs' },
|
|
164
|
-
},
|
|
165
|
-
manualInstall: {
|
|
166
|
-
darwin: [
|
|
167
|
-
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
168
|
-
'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
|
|
169
|
-
'Or install Postgres.app: https://postgresapp.com/downloads.html',
|
|
170
|
-
],
|
|
171
|
-
linux: [
|
|
172
|
-
'Ubuntu/Debian: sudo apt install postgresql-client',
|
|
173
|
-
'CentOS/RHEL: sudo yum install postgresql',
|
|
174
|
-
'Fedora: sudo dnf install postgresql',
|
|
175
|
-
'Arch: sudo pacman -S postgresql-libs',
|
|
176
|
-
],
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
name: 'pg_restore',
|
|
181
|
-
binary: 'pg_restore',
|
|
182
|
-
description: 'PostgreSQL database restore utility',
|
|
183
|
-
packages: {
|
|
184
|
-
brew: {
|
|
185
|
-
package: 'postgresql@17',
|
|
186
|
-
postInstall: ['brew link --overwrite postgresql@17'],
|
|
187
|
-
},
|
|
188
|
-
apt: { package: 'postgresql-client' },
|
|
189
|
-
yum: { package: 'postgresql' },
|
|
190
|
-
dnf: { package: 'postgresql' },
|
|
191
|
-
pacman: { package: 'postgresql-libs' },
|
|
192
|
-
},
|
|
193
|
-
manualInstall: {
|
|
194
|
-
darwin: [
|
|
195
|
-
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
196
|
-
'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
|
|
197
|
-
'Or install Postgres.app: https://postgresapp.com/downloads.html',
|
|
198
|
-
],
|
|
199
|
-
linux: [
|
|
200
|
-
'Ubuntu/Debian: sudo apt install postgresql-client',
|
|
201
|
-
'CentOS/RHEL: sudo yum install postgresql',
|
|
202
|
-
'Fedora: sudo dnf install postgresql',
|
|
203
|
-
'Arch: sudo pacman -S postgresql-libs',
|
|
204
|
-
],
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: 'pg_basebackup',
|
|
209
|
-
binary: 'pg_basebackup',
|
|
210
|
-
description: 'PostgreSQL base backup utility for physical backups',
|
|
211
|
-
packages: {
|
|
212
|
-
brew: {
|
|
213
|
-
package: 'postgresql@17',
|
|
214
|
-
postInstall: ['brew link --overwrite postgresql@17'],
|
|
215
|
-
},
|
|
216
|
-
apt: { package: 'postgresql-client' },
|
|
217
|
-
yum: { package: 'postgresql' },
|
|
218
|
-
dnf: { package: 'postgresql' },
|
|
219
|
-
pacman: { package: 'postgresql-libs' },
|
|
220
|
-
},
|
|
221
|
-
manualInstall: {
|
|
222
|
-
darwin: [
|
|
223
|
-
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
224
|
-
'Then run: brew install postgresql@17 && brew link --overwrite postgresql@17',
|
|
225
|
-
'Or install Postgres.app: https://postgresapp.com/downloads.html',
|
|
226
|
-
],
|
|
227
|
-
linux: [
|
|
228
|
-
'Ubuntu/Debian: sudo apt install postgresql-client',
|
|
229
|
-
'CentOS/RHEL: sudo yum install postgresql',
|
|
230
|
-
'Fedora: sudo dnf install postgresql',
|
|
231
|
-
'Arch: sudo pacman -S postgresql-libs',
|
|
232
|
-
],
|
|
233
|
-
},
|
|
234
|
-
},
|
|
165
|
+
createPostgresDependency('psql', 'psql', 'PostgreSQL interactive terminal'),
|
|
166
|
+
createPostgresDependency(
|
|
167
|
+
'pg_dump',
|
|
168
|
+
'pg_dump',
|
|
169
|
+
'PostgreSQL database backup utility',
|
|
170
|
+
),
|
|
171
|
+
createPostgresDependency(
|
|
172
|
+
'pg_restore',
|
|
173
|
+
'pg_restore',
|
|
174
|
+
'PostgreSQL database restore utility',
|
|
175
|
+
),
|
|
176
|
+
createPostgresDependency(
|
|
177
|
+
'pg_basebackup',
|
|
178
|
+
'pg_basebackup',
|
|
179
|
+
'PostgreSQL base backup utility for physical backups',
|
|
180
|
+
),
|
|
235
181
|
],
|
|
236
182
|
}
|
|
237
183
|
|
|
@@ -343,6 +289,98 @@ const mysqlDependencies: EngineDependencies = {
|
|
|
343
289
|
],
|
|
344
290
|
}
|
|
345
291
|
|
|
292
|
+
// =============================================================================
|
|
293
|
+
// Optional Tools (engine-agnostic)
|
|
294
|
+
// =============================================================================
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* usql - Universal SQL client
|
|
298
|
+
* Works with PostgreSQL, MySQL, SQLite, and 20+ other databases
|
|
299
|
+
* https://github.com/xo/usql
|
|
300
|
+
*/
|
|
301
|
+
export const usqlDependency: Dependency = {
|
|
302
|
+
name: 'usql',
|
|
303
|
+
binary: 'usql',
|
|
304
|
+
description:
|
|
305
|
+
'Universal SQL client with auto-completion, syntax highlighting, and multi-database support',
|
|
306
|
+
packages: {
|
|
307
|
+
brew: {
|
|
308
|
+
package: 'xo/xo/usql',
|
|
309
|
+
preInstall: ['brew tap xo/xo'],
|
|
310
|
+
},
|
|
311
|
+
// Note: usql is not in standard Linux package repos, must use manual install
|
|
312
|
+
},
|
|
313
|
+
manualInstall: {
|
|
314
|
+
darwin: [
|
|
315
|
+
'Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
316
|
+
'Then run: brew tap xo/xo && brew install xo/xo/usql',
|
|
317
|
+
],
|
|
318
|
+
linux: [
|
|
319
|
+
'Download from GitHub releases: https://github.com/xo/usql/releases',
|
|
320
|
+
'Extract and move to PATH: sudo mv usql /usr/local/bin/',
|
|
321
|
+
'Or install via Go: go install github.com/xo/usql@latest',
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* pgcli - PostgreSQL CLI with auto-completion and syntax highlighting
|
|
328
|
+
* https://github.com/dbcli/pgcli
|
|
329
|
+
*/
|
|
330
|
+
export const pgcliDependency: Dependency = {
|
|
331
|
+
name: 'pgcli',
|
|
332
|
+
binary: 'pgcli',
|
|
333
|
+
description:
|
|
334
|
+
'PostgreSQL CLI with intelligent auto-completion and syntax highlighting',
|
|
335
|
+
packages: {
|
|
336
|
+
brew: { package: 'pgcli' },
|
|
337
|
+
apt: { package: 'pgcli' },
|
|
338
|
+
dnf: { package: 'pgcli' },
|
|
339
|
+
yum: { package: 'pgcli' },
|
|
340
|
+
pacman: { package: 'pgcli' },
|
|
341
|
+
},
|
|
342
|
+
manualInstall: {
|
|
343
|
+
darwin: [
|
|
344
|
+
'Install with Homebrew: brew install pgcli',
|
|
345
|
+
'Or with pip: pip install pgcli',
|
|
346
|
+
],
|
|
347
|
+
linux: [
|
|
348
|
+
'Debian/Ubuntu: sudo apt install pgcli',
|
|
349
|
+
'Fedora: sudo dnf install pgcli',
|
|
350
|
+
'Or with pip: pip install pgcli',
|
|
351
|
+
],
|
|
352
|
+
},
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* mycli - MySQL CLI with auto-completion and syntax highlighting
|
|
357
|
+
* https://github.com/dbcli/mycli
|
|
358
|
+
*/
|
|
359
|
+
export const mycliDependency: Dependency = {
|
|
360
|
+
name: 'mycli',
|
|
361
|
+
binary: 'mycli',
|
|
362
|
+
description:
|
|
363
|
+
'MySQL/MariaDB CLI with intelligent auto-completion and syntax highlighting',
|
|
364
|
+
packages: {
|
|
365
|
+
brew: { package: 'mycli' },
|
|
366
|
+
apt: { package: 'mycli' },
|
|
367
|
+
dnf: { package: 'mycli' },
|
|
368
|
+
yum: { package: 'mycli' },
|
|
369
|
+
pacman: { package: 'mycli' },
|
|
370
|
+
},
|
|
371
|
+
manualInstall: {
|
|
372
|
+
darwin: [
|
|
373
|
+
'Install with Homebrew: brew install mycli',
|
|
374
|
+
'Or with pip: pip install mycli',
|
|
375
|
+
],
|
|
376
|
+
linux: [
|
|
377
|
+
'Debian/Ubuntu: sudo apt install mycli',
|
|
378
|
+
'Fedora: sudo dnf install mycli',
|
|
379
|
+
'Or with pip: pip install mycli',
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
|
|
346
384
|
// =============================================================================
|
|
347
385
|
// Registry
|
|
348
386
|
// =============================================================================
|
package/config/paths.ts
CHANGED
|
@@ -1,46 +1,17 @@
|
|
|
1
|
-
import { homedir } from 'os'
|
|
2
1
|
import { join } from 'path'
|
|
3
|
-
import { execSync } from 'child_process'
|
|
4
2
|
import { getEngineDefaults } from './engine-defaults'
|
|
3
|
+
import { platformService } from '../core/platform-service'
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
|
-
* Get the
|
|
8
|
-
*
|
|
9
|
-
* not root's home directory.
|
|
6
|
+
* Get the SpinDB home directory using the platform service.
|
|
7
|
+
* This handles sudo detection and platform-specific home directories.
|
|
10
8
|
*/
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (sudoUser) {
|
|
16
|
-
// Get the original user's home directory
|
|
17
|
-
try {
|
|
18
|
-
// Use getent to reliably get the home directory for the sudo user
|
|
19
|
-
const result = execSync(`getent passwd ${sudoUser}`, {
|
|
20
|
-
encoding: 'utf-8',
|
|
21
|
-
})
|
|
22
|
-
const parts = result.trim().split(':')
|
|
23
|
-
if (parts.length >= 6 && parts[5]) {
|
|
24
|
-
return parts[5]
|
|
25
|
-
}
|
|
26
|
-
} catch {
|
|
27
|
-
// Fall back to constructing the path
|
|
28
|
-
// On most Linux systems, home dirs are /home/username
|
|
29
|
-
// On macOS, they're /Users/username
|
|
30
|
-
const platform = process.platform
|
|
31
|
-
if (platform === 'darwin') {
|
|
32
|
-
return `/Users/${sudoUser}`
|
|
33
|
-
} else {
|
|
34
|
-
return `/home/${sudoUser}`
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Not running under sudo, use normal homedir
|
|
40
|
-
return homedir()
|
|
9
|
+
function getSpinDBHome(): string {
|
|
10
|
+
const platformInfo = platformService.getPlatformInfo()
|
|
11
|
+
return join(platformInfo.homeDir, '.spindb')
|
|
41
12
|
}
|
|
42
13
|
|
|
43
|
-
const SPINDB_HOME =
|
|
14
|
+
const SPINDB_HOME = getSpinDBHome()
|
|
44
15
|
|
|
45
16
|
/**
|
|
46
17
|
* Options for container path functions
|
package/core/binary-manager.ts
CHANGED
|
@@ -56,15 +56,17 @@ export class BinaryManager {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Check if binaries for a specific version are already installed
|
|
59
|
+
* Uses full version for directory naming (e.g., postgresql-17.7.0-darwin-arm64)
|
|
59
60
|
*/
|
|
60
61
|
async isInstalled(
|
|
61
62
|
version: string,
|
|
62
63
|
platform: string,
|
|
63
64
|
arch: string,
|
|
64
65
|
): Promise<boolean> {
|
|
66
|
+
const fullVersion = this.getFullVersion(version)
|
|
65
67
|
const binPath = paths.getBinaryPath({
|
|
66
68
|
engine: 'postgresql',
|
|
67
|
-
version,
|
|
69
|
+
version: fullVersion,
|
|
68
70
|
platform,
|
|
69
71
|
arch,
|
|
70
72
|
})
|
|
@@ -113,14 +115,15 @@ export class BinaryManager {
|
|
|
113
115
|
arch: string,
|
|
114
116
|
onProgress?: ProgressCallback,
|
|
115
117
|
): Promise<string> {
|
|
118
|
+
const fullVersion = this.getFullVersion(version)
|
|
116
119
|
const url = this.getDownloadUrl(version, platform, arch)
|
|
117
120
|
const binPath = paths.getBinaryPath({
|
|
118
121
|
engine: 'postgresql',
|
|
119
|
-
version,
|
|
122
|
+
version: fullVersion,
|
|
120
123
|
platform,
|
|
121
124
|
arch,
|
|
122
125
|
})
|
|
123
|
-
const tempDir = join(paths.bin, `temp-${
|
|
126
|
+
const tempDir = join(paths.bin, `temp-${fullVersion}-${platform}-${arch}`)
|
|
124
127
|
const jarFile = join(tempDir, 'postgres.jar')
|
|
125
128
|
|
|
126
129
|
// Ensure directories exist
|
|
@@ -200,9 +203,10 @@ export class BinaryManager {
|
|
|
200
203
|
platform: string,
|
|
201
204
|
arch: string,
|
|
202
205
|
): Promise<boolean> {
|
|
206
|
+
const fullVersion = this.getFullVersion(version)
|
|
203
207
|
const binPath = paths.getBinaryPath({
|
|
204
208
|
engine: 'postgresql',
|
|
205
|
-
version,
|
|
209
|
+
version: fullVersion,
|
|
206
210
|
platform,
|
|
207
211
|
arch,
|
|
208
212
|
})
|
|
@@ -256,9 +260,10 @@ export class BinaryManager {
|
|
|
256
260
|
arch: string,
|
|
257
261
|
binary: string,
|
|
258
262
|
): string {
|
|
263
|
+
const fullVersion = this.getFullVersion(version)
|
|
259
264
|
const binPath = paths.getBinaryPath({
|
|
260
265
|
engine: 'postgresql',
|
|
261
|
-
version,
|
|
266
|
+
version: fullVersion,
|
|
262
267
|
platform,
|
|
263
268
|
arch,
|
|
264
269
|
})
|
|
@@ -274,6 +279,7 @@ export class BinaryManager {
|
|
|
274
279
|
arch: string,
|
|
275
280
|
onProgress?: ProgressCallback,
|
|
276
281
|
): Promise<string> {
|
|
282
|
+
const fullVersion = this.getFullVersion(version)
|
|
277
283
|
if (await this.isInstalled(version, platform, arch)) {
|
|
278
284
|
onProgress?.({
|
|
279
285
|
stage: 'cached',
|
|
@@ -281,7 +287,7 @@ export class BinaryManager {
|
|
|
281
287
|
})
|
|
282
288
|
return paths.getBinaryPath({
|
|
283
289
|
engine: 'postgresql',
|
|
284
|
-
version,
|
|
290
|
+
version: fullVersion,
|
|
285
291
|
platform,
|
|
286
292
|
arch,
|
|
287
293
|
})
|
package/core/config-manager.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { exec } from 'child_process'
|
|
|
4
4
|
import { promisify } from 'util'
|
|
5
5
|
import { dirname } from 'path'
|
|
6
6
|
import { paths } from '../config/paths'
|
|
7
|
+
import { logDebug, logWarning } from './error-handler'
|
|
7
8
|
import type {
|
|
8
9
|
SpinDBConfig,
|
|
9
10
|
BinaryConfig,
|
|
@@ -41,8 +42,12 @@ export class ConfigManager {
|
|
|
41
42
|
const content = await readFile(configPath, 'utf8')
|
|
42
43
|
this.config = JSON.parse(content) as SpinDBConfig
|
|
43
44
|
return this.config
|
|
44
|
-
} catch {
|
|
45
|
+
} catch (error) {
|
|
45
46
|
// If config is corrupted, reset to default
|
|
47
|
+
logWarning('Config file corrupted, resetting to default', {
|
|
48
|
+
configPath,
|
|
49
|
+
error: error instanceof Error ? error.message : String(error),
|
|
50
|
+
})
|
|
46
51
|
this.config = { ...DEFAULT_CONFIG }
|
|
47
52
|
await this.save()
|
|
48
53
|
return this.config
|
|
@@ -110,8 +115,12 @@ export class ConfigManager {
|
|
|
110
115
|
if (match) {
|
|
111
116
|
version = match[0]
|
|
112
117
|
}
|
|
113
|
-
} catch {
|
|
114
|
-
|
|
118
|
+
} catch (error) {
|
|
119
|
+
logDebug('Version detection failed', {
|
|
120
|
+
tool,
|
|
121
|
+
path,
|
|
122
|
+
error: error instanceof Error ? error.message : String(error),
|
|
123
|
+
})
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
config.binaries[tool] = {
|
|
@@ -142,8 +151,11 @@ export class ConfigManager {
|
|
|
142
151
|
if (path && existsSync(path)) {
|
|
143
152
|
return path
|
|
144
153
|
}
|
|
145
|
-
} catch {
|
|
146
|
-
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logDebug('which command failed for binary detection', {
|
|
156
|
+
tool,
|
|
157
|
+
error: error instanceof Error ? error.message : String(error),
|
|
158
|
+
})
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
// Check common locations
|
|
@@ -15,7 +15,11 @@ import {
|
|
|
15
15
|
packageManagers,
|
|
16
16
|
getEngineDependencies,
|
|
17
17
|
getUniqueDependencies,
|
|
18
|
+
usqlDependency,
|
|
19
|
+
pgcliDependency,
|
|
20
|
+
mycliDependency,
|
|
18
21
|
} from '../config/os-dependencies'
|
|
22
|
+
import { platformService } from './platform-service'
|
|
19
23
|
|
|
20
24
|
const execAsync = promisify(exec)
|
|
21
25
|
|
|
@@ -46,7 +50,7 @@ export type InstallResult = {
|
|
|
46
50
|
* Detect which package manager is available on the current system
|
|
47
51
|
*/
|
|
48
52
|
export async function detectPackageManager(): Promise<DetectedPackageManager | null> {
|
|
49
|
-
const platform =
|
|
53
|
+
const { platform } = platformService.getPlatformInfo()
|
|
50
54
|
|
|
51
55
|
// Filter to package managers available on this platform
|
|
52
56
|
const candidates = packageManagers.filter((pm) =>
|
|
@@ -73,7 +77,7 @@ export async function detectPackageManager(): Promise<DetectedPackageManager | n
|
|
|
73
77
|
* Get the current platform
|
|
74
78
|
*/
|
|
75
79
|
export function getCurrentPlatform(): Platform {
|
|
76
|
-
return
|
|
80
|
+
return platformService.getPlatformInfo().platform as Platform
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
// =============================================================================
|
|
@@ -87,21 +91,12 @@ export async function findBinary(
|
|
|
87
91
|
binary: string,
|
|
88
92
|
): Promise<{ path: string; version?: string } | null> {
|
|
89
93
|
try {
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
const path = stdout.trim().split('\n')[0]
|
|
93
|
-
|
|
94
|
+
// Use platformService to find the binary path
|
|
95
|
+
const path = await platformService.findToolPath(binary)
|
|
94
96
|
if (!path) return null
|
|
95
97
|
|
|
96
98
|
// Try to get version
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const { stdout: versionOutput } = await execAsync(`${binary} --version`)
|
|
100
|
-
const match = versionOutput.match(/(\d+\.\d+(\.\d+)?)/)
|
|
101
|
-
version = match ? match[1] : undefined
|
|
102
|
-
} catch {
|
|
103
|
-
// Version check failed, that's ok
|
|
104
|
-
}
|
|
99
|
+
const version = (await platformService.getToolVersion(path)) || undefined
|
|
105
100
|
|
|
106
101
|
return { path, version }
|
|
107
102
|
} catch {
|
|
@@ -216,7 +211,9 @@ function execWithInheritedStdio(command: string): void {
|
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
if (result.status !== 0) {
|
|
219
|
-
throw new Error(
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Command failed with exit code ${result.status}: ${cmdToRun}`,
|
|
216
|
+
)
|
|
220
217
|
}
|
|
221
218
|
}
|
|
222
219
|
|
|
@@ -427,3 +424,135 @@ export async function getAllDependencyReports(): Promise<
|
|
|
427
424
|
)
|
|
428
425
|
return reports
|
|
429
426
|
}
|
|
427
|
+
|
|
428
|
+
// =============================================================================
|
|
429
|
+
// usql (Enhanced Shell) Support
|
|
430
|
+
// =============================================================================
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Check if usql is installed
|
|
434
|
+
*/
|
|
435
|
+
export async function isUsqlInstalled(): Promise<boolean> {
|
|
436
|
+
const status = await checkDependency(usqlDependency)
|
|
437
|
+
return status.installed
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Get usql dependency status
|
|
442
|
+
*/
|
|
443
|
+
export async function getUsqlStatus(): Promise<DependencyStatus> {
|
|
444
|
+
return checkDependency(usqlDependency)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Install usql using the detected package manager
|
|
449
|
+
*/
|
|
450
|
+
export async function installUsql(
|
|
451
|
+
packageManager: DetectedPackageManager,
|
|
452
|
+
): Promise<InstallResult> {
|
|
453
|
+
return installDependency(usqlDependency, packageManager)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Get usql manual installation instructions
|
|
458
|
+
*/
|
|
459
|
+
export function getUsqlManualInstructions(
|
|
460
|
+
platform: Platform = getCurrentPlatform(),
|
|
461
|
+
): string[] {
|
|
462
|
+
return getManualInstallInstructions(usqlDependency, platform)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Get the usql dependency definition
|
|
467
|
+
*/
|
|
468
|
+
export function getUsqlDependency(): Dependency {
|
|
469
|
+
return usqlDependency
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// =============================================================================
|
|
473
|
+
// pgcli (PostgreSQL Enhanced Shell) Support
|
|
474
|
+
// =============================================================================
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Check if pgcli is installed
|
|
478
|
+
*/
|
|
479
|
+
export async function isPgcliInstalled(): Promise<boolean> {
|
|
480
|
+
const status = await checkDependency(pgcliDependency)
|
|
481
|
+
return status.installed
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Get pgcli dependency status
|
|
486
|
+
*/
|
|
487
|
+
export async function getPgcliStatus(): Promise<DependencyStatus> {
|
|
488
|
+
return checkDependency(pgcliDependency)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Install pgcli using the detected package manager
|
|
493
|
+
*/
|
|
494
|
+
export async function installPgcli(
|
|
495
|
+
packageManager: DetectedPackageManager,
|
|
496
|
+
): Promise<InstallResult> {
|
|
497
|
+
return installDependency(pgcliDependency, packageManager)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Get pgcli manual installation instructions
|
|
502
|
+
*/
|
|
503
|
+
export function getPgcliManualInstructions(
|
|
504
|
+
platform: Platform = getCurrentPlatform(),
|
|
505
|
+
): string[] {
|
|
506
|
+
return getManualInstallInstructions(pgcliDependency, platform)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Get the pgcli dependency definition
|
|
511
|
+
*/
|
|
512
|
+
export function getPgcliDependency(): Dependency {
|
|
513
|
+
return pgcliDependency
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// =============================================================================
|
|
517
|
+
// mycli (MySQL Enhanced Shell) Support
|
|
518
|
+
// =============================================================================
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Check if mycli is installed
|
|
522
|
+
*/
|
|
523
|
+
export async function isMycliInstalled(): Promise<boolean> {
|
|
524
|
+
const status = await checkDependency(mycliDependency)
|
|
525
|
+
return status.installed
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Get mycli dependency status
|
|
530
|
+
*/
|
|
531
|
+
export async function getMycliStatus(): Promise<DependencyStatus> {
|
|
532
|
+
return checkDependency(mycliDependency)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Install mycli using the detected package manager
|
|
537
|
+
*/
|
|
538
|
+
export async function installMycli(
|
|
539
|
+
packageManager: DetectedPackageManager,
|
|
540
|
+
): Promise<InstallResult> {
|
|
541
|
+
return installDependency(mycliDependency, packageManager)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Get mycli manual installation instructions
|
|
546
|
+
*/
|
|
547
|
+
export function getMycliManualInstructions(
|
|
548
|
+
platform: Platform = getCurrentPlatform(),
|
|
549
|
+
): string[] {
|
|
550
|
+
return getManualInstallInstructions(mycliDependency, platform)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Get the mycli dependency definition
|
|
555
|
+
*/
|
|
556
|
+
export function getMycliDependency(): Dependency {
|
|
557
|
+
return mycliDependency
|
|
558
|
+
}
|