spindb 0.4.0 → 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.
@@ -0,0 +1,248 @@
1
+ /**
2
+ * MySQL binary detection for system-installed MySQL
3
+ * Detects MySQL installations from Homebrew, apt, or other package managers
4
+ */
5
+
6
+ import { exec } from 'child_process'
7
+ import { promisify } from 'util'
8
+ import { existsSync } from 'fs'
9
+ import { platform } from 'os'
10
+
11
+ const execAsync = promisify(exec)
12
+
13
+ /**
14
+ * Common paths where MySQL binaries might be installed
15
+ */
16
+ const MYSQL_SEARCH_PATHS = {
17
+ darwin: [
18
+ // Homebrew (Apple Silicon)
19
+ '/opt/homebrew/bin',
20
+ '/opt/homebrew/opt/mysql/bin',
21
+ '/opt/homebrew/opt/mysql@8.0/bin',
22
+ '/opt/homebrew/opt/mysql@8.4/bin',
23
+ '/opt/homebrew/opt/mysql@5.7/bin',
24
+ // Homebrew (Intel)
25
+ '/usr/local/bin',
26
+ '/usr/local/opt/mysql/bin',
27
+ '/usr/local/opt/mysql@8.0/bin',
28
+ '/usr/local/opt/mysql@8.4/bin',
29
+ '/usr/local/opt/mysql@5.7/bin',
30
+ // Official MySQL installer
31
+ '/usr/local/mysql/bin',
32
+ ],
33
+ linux: [
34
+ '/usr/bin',
35
+ '/usr/sbin',
36
+ '/usr/local/bin',
37
+ '/usr/local/mysql/bin',
38
+ ],
39
+ win32: [
40
+ 'C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin',
41
+ 'C:\\Program Files\\MySQL\\MySQL Server 8.4\\bin',
42
+ 'C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin',
43
+ ],
44
+ }
45
+
46
+ /**
47
+ * Get search paths for the current platform
48
+ */
49
+ function getSearchPaths(): string[] {
50
+ const plat = platform()
51
+ return MYSQL_SEARCH_PATHS[plat as keyof typeof MYSQL_SEARCH_PATHS] || []
52
+ }
53
+
54
+ /**
55
+ * Check if a binary exists at the given path
56
+ */
57
+ function binaryExists(path: string): boolean {
58
+ return existsSync(path)
59
+ }
60
+
61
+ /**
62
+ * Find a MySQL binary by name
63
+ */
64
+ export async function findMysqlBinary(
65
+ name: string,
66
+ ): Promise<string | null> {
67
+ // First, try using 'which' or 'where' command
68
+ try {
69
+ const cmd = platform() === 'win32' ? 'where' : 'which'
70
+ const { stdout } = await execAsync(`${cmd} ${name}`)
71
+ const path = stdout.trim().split('\n')[0]
72
+ if (path && binaryExists(path)) {
73
+ return path
74
+ }
75
+ } catch {
76
+ // Not found in PATH, continue to search common locations
77
+ }
78
+
79
+ // Search common installation paths
80
+ const searchPaths = getSearchPaths()
81
+ for (const dir of searchPaths) {
82
+ const fullPath = platform() === 'win32'
83
+ ? `${dir}\\${name}.exe`
84
+ : `${dir}/${name}`
85
+ if (binaryExists(fullPath)) {
86
+ return fullPath
87
+ }
88
+ }
89
+
90
+ return null
91
+ }
92
+
93
+ /**
94
+ * Get the path to mysqld (MySQL server)
95
+ */
96
+ export async function getMysqldPath(): Promise<string | null> {
97
+ return findMysqlBinary('mysqld')
98
+ }
99
+
100
+ /**
101
+ * Get the path to mysql client
102
+ */
103
+ export async function getMysqlClientPath(): Promise<string | null> {
104
+ return findMysqlBinary('mysql')
105
+ }
106
+
107
+ /**
108
+ * Get the path to mysqladmin
109
+ */
110
+ export async function getMysqladminPath(): Promise<string | null> {
111
+ return findMysqlBinary('mysqladmin')
112
+ }
113
+
114
+ /**
115
+ * Get the path to mysqldump
116
+ */
117
+ export async function getMysqldumpPath(): Promise<string | null> {
118
+ return findMysqlBinary('mysqldump')
119
+ }
120
+
121
+ /**
122
+ * Get the path to mysql_install_db (MariaDB initialization script)
123
+ */
124
+ export async function getMysqlInstallDbPath(): Promise<string | null> {
125
+ return findMysqlBinary('mysql_install_db')
126
+ }
127
+
128
+ /**
129
+ * Get the path to mariadb-install-db (alternative MariaDB initialization)
130
+ */
131
+ export async function getMariadbInstallDbPath(): Promise<string | null> {
132
+ return findMysqlBinary('mariadb-install-db')
133
+ }
134
+
135
+ /**
136
+ * Detect if the installed MySQL is actually MariaDB
137
+ */
138
+ export async function isMariaDB(): Promise<boolean> {
139
+ const mysqld = await getMysqldPath()
140
+ if (!mysqld) return false
141
+
142
+ try {
143
+ const { stdout } = await execAsync(`"${mysqld}" --version`)
144
+ return stdout.toLowerCase().includes('mariadb')
145
+ } catch {
146
+ return false
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Get the MySQL server version from a mysqld binary
152
+ */
153
+ export async function getMysqlVersion(
154
+ mysqldPath: string,
155
+ ): Promise<string | null> {
156
+ try {
157
+ const { stdout } = await execAsync(`"${mysqldPath}" --version`)
158
+ // Example output: mysqld Ver 8.0.35 for macos14.0 on arm64 (Homebrew)
159
+ const match = stdout.match(/Ver\s+(\d+\.\d+\.\d+)/)
160
+ return match ? match[1] : null
161
+ } catch {
162
+ return null
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get the major version from a full version string
168
+ * e.g., "8.0.35" -> "8.0"
169
+ */
170
+ export function getMajorVersion(fullVersion: string): string {
171
+ const parts = fullVersion.split('.')
172
+ return `${parts[0]}.${parts[1]}`
173
+ }
174
+
175
+ /**
176
+ * Detect all installed MySQL versions
177
+ * Returns a map of major version -> full version string
178
+ */
179
+ export async function detectInstalledVersions(): Promise<
180
+ Record<string, string>
181
+ > {
182
+ const versions: Record<string, string> = {}
183
+
184
+ // Check default mysqld
185
+ const defaultMysqld = await getMysqldPath()
186
+ if (defaultMysqld) {
187
+ const version = await getMysqlVersion(defaultMysqld)
188
+ if (version) {
189
+ const major = getMajorVersion(version)
190
+ versions[major] = version
191
+ }
192
+ }
193
+
194
+ // Check versioned Homebrew installations
195
+ const homebrewPaths = platform() === 'darwin'
196
+ ? [
197
+ '/opt/homebrew/opt/mysql@5.7/bin/mysqld',
198
+ '/opt/homebrew/opt/mysql@8.0/bin/mysqld',
199
+ '/opt/homebrew/opt/mysql@8.4/bin/mysqld',
200
+ '/usr/local/opt/mysql@5.7/bin/mysqld',
201
+ '/usr/local/opt/mysql@8.0/bin/mysqld',
202
+ '/usr/local/opt/mysql@8.4/bin/mysqld',
203
+ ]
204
+ : []
205
+
206
+ for (const path of homebrewPaths) {
207
+ if (binaryExists(path)) {
208
+ const version = await getMysqlVersion(path)
209
+ if (version) {
210
+ const major = getMajorVersion(version)
211
+ if (!versions[major]) {
212
+ versions[major] = version
213
+ }
214
+ }
215
+ }
216
+ }
217
+
218
+ return versions
219
+ }
220
+
221
+ /**
222
+ * Get install instructions for MySQL
223
+ */
224
+ export function getInstallInstructions(): string {
225
+ const plat = platform()
226
+
227
+ if (plat === 'darwin') {
228
+ return (
229
+ 'MySQL server not found. Install MySQL:\n' +
230
+ ' brew install mysql\n' +
231
+ ' # or for a specific version:\n' +
232
+ ' brew install mysql@8.0'
233
+ )
234
+ }
235
+
236
+ if (plat === 'linux') {
237
+ return (
238
+ 'MySQL server not found. Install MySQL:\n' +
239
+ ' Ubuntu/Debian: sudo apt install mysql-server\n' +
240
+ ' RHEL/CentOS: sudo yum install mysql-server'
241
+ )
242
+ }
243
+
244
+ return (
245
+ 'MySQL server not found. Please install MySQL from:\n' +
246
+ ' https://dev.mysql.com/downloads/mysql/'
247
+ )
248
+ }