diff --git a/settings.json b/settings.json index c1d86a7..0a8e7bb 100644 --- a/settings.json +++ b/settings.json @@ -7,6 +7,9 @@ "mariaDbPorts": {}, "allowRemoteAccess": false, "language": "tr", + "cliEnvEnabled": true, + "defaultPhpVersion": "7.4.33", + "defaultMariaDbVersion": "mariadb-11.4.2", "mysqlPort": "3306", "mysqlPorts": {} } \ No newline at end of file diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index cb17edb..8d066b5 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -1050,7 +1050,8 @@ export function registerIpcHandlers(): void { enabled: settings.cliEnvEnabled !== false, defaultPhp: settings.defaultPhpVersion, defaultMariaDb: settings.defaultMariaDbVersion, - binDir: cliBinService.getBinDir() + binDir: cliBinService.getBinDir(), + aliases: cliBinService.getAllAliases() } }) diff --git a/src/main/services/CliBinService.ts b/src/main/services/CliBinService.ts index e2f96cf..33b254e 100644 --- a/src/main/services/CliBinService.ts +++ b/src/main/services/CliBinService.ts @@ -10,14 +10,19 @@ import { configService } from './ConfigService' const execAsync = promisify(exec) export class CliBinService { - private binDir: string + private _binDir: string | null = null + private aliases: { command: string, target: string }[] = [] - constructor() { - // We store shims in the app's roaming/user path to avoid permission issues - this.binDir = path.join(app.getPath('userData'), 'cli-bin') - if (!fs.existsSync(this.binDir)) { - fs.mkdirSync(this.binDir, { recursive: true }) + constructor() {} + + private getBinDirInternal(): string { + if (!this._binDir) { + this._binDir = path.join(app.getPath('userData'), 'cli-bin') + if (!fs.existsSync(this._binDir)) { + fs.mkdirSync(this._binDir, { recursive: true }) + } } + return this._binDir } async sync() { @@ -27,11 +32,13 @@ export class CliBinService { const installedPhp = phpVersions.filter(v => v.status === 'installed') const installedMariaDb = mariaDbVersions.filter(v => v.status === 'installed') + this.aliases = [] // Clean current shims - const files = fs.readdirSync(this.binDir) + const binDir = this.getBinDirInternal() + const files = fs.readdirSync(binDir) for (const file of files) { - fs.unlinkSync(path.join(this.binDir, file)) + fs.unlinkSync(path.join(binDir, file)) } // Generate PHP shims @@ -113,25 +120,55 @@ export class CliBinService { // Create a small .cmd proxy for each command // Using "@%* " to pass all arguments correctly const content = `@echo off\n"${targetPath}" %*\n` - fs.writeFileSync(path.join(this.binDir, `${name}.cmd`), content) + const binDir = this.getBinDirInternal() + fs.writeFileSync(path.join(binDir, `${name}.cmd`), content) // Also create a .bat just in case - fs.writeFileSync(path.join(this.binDir, `${name}.bat`), content) + fs.writeFileSync(path.join(binDir, `${name}.bat`), content) + + // Track alias + if (!this.aliases.some(a => a.command === name)) { + this.aliases.push({ command: name, target: targetPath }) + } } async ensureInPath() { if (process.platform !== 'win32') return try { - // Get current User PATH - const { stdout } = await execAsync('powershell -Command "[Environment]::GetEnvironmentVariable(\'Path\', \'User\')"') - const currentPath = stdout.trim() + // Use PowerShell to manage PATH safely. + // 1. Get current User PATH + // 2. Add binDir if not exists + // 3. Set new PATH + // 4. Broadcast WM_SETTINGCHANGE to notify system + const binDir = this.getBinDirInternal() - if (!currentPath.includes(this.binDir)) { - const newPath = `${currentPath}${currentPath.endsWith(';') ? '' : ';'}${this.binDir}` - // Update User PATH safely using PowerShell - await execAsync(`powershell -Command "[Environment]::SetEnvironmentVariable('Path', '${newPath}', 'User')"`) - console.log(`Added Multi-PHP bin to User PATH: ${this.binDir}`) + const psScript = ` + $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User') + if ($currentPath -notlike '*${binDir}*') { + $newPath = $currentPath + if ($newPath -and -not $newPath.EndsWith(';')) { $newPath += ';' } + $newPath += '${binDir}' + [Environment]::SetEnvironmentVariable('Path', $newPath, 'User') + + # Notify Windows of the change (WM_SETTINGCHANGE) + $signature = @' + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out IntPtr lpdwResult); +'@ + $type = Add-Type -MemberDefinition $signature -Name "Win32" -Namespace "Native" -PassThru -ErrorAction SilentlyContinue + if ($type) { + $type::SendMessageTimeout(0xFFFF, 0x001A, [IntPtr]::Zero, "Environment", 0x0002, 1000, [ref][IntPtr]::Zero) + } + Write-Output "PATH_UPDATED" + } else { + Write-Output "ALREADY_IN_PATH" + } + ` + + const { stdout } = await execAsync(`powershell -Command "${psScript.replace(/\n/g, ' ')}"`) + if (stdout.includes('PATH_UPDATED')) { + console.log(`Successfully added Multi-PHP bin to User PATH: ${binDir}`) } } catch (e) { console.error('Failed to update PATH:', e) @@ -139,7 +176,11 @@ export class CliBinService { } getBinDir() { - return this.binDir + return this.getBinDirInternal() + } + + getAllAliases() { + return this.aliases } } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 5f40b04..5f0e99e 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -107,6 +107,9 @@ interface AppSettings { mariaDbPorts?: Record allowRemoteAccess: boolean language: string + cliEnvEnabled: boolean + defaultPhpVersion: string + defaultMariaDbVersion: string } function App(): JSX.Element { @@ -137,7 +140,10 @@ function App(): JSX.Element { phpPort: '9001', mariaDbPort: '3306', allowRemoteAccess: false, - language: 'tr' + language: 'tr', + cliEnvEnabled: true, + defaultPhpVersion: '', + defaultMariaDbVersion: '' }) const [notification, setNotification] = useState<{ open: boolean, message: string, severity: 'success' | 'error' }>({ open: false, @@ -1317,11 +1323,34 @@ function App(): JSX.Element { onClick={async () => { await window.api.invoke('cli:sync') setNotification({ open: true, message: t('settings.cli_sync_success'), severity: 'success' }) + fetchCliConfig() }} > {t('settings.cli_sync_btn')} + + {cliConfig.aliases && cliConfig.aliases.length > 0 && ( + + + {t('settings.cli_aliases_title')} + + + + {cliConfig.aliases.map((a: any) => ( + + {a.command}} + secondary={a.target} + primaryTypographyProps={{ variant: 'body2', fontWeight: 'bold' }} + secondaryTypographyProps={{ variant: 'caption', sx: { opacity: 0.5 } }} + /> + + ))} + + + + )} diff --git a/src/renderer/src/locales/en.json b/src/renderer/src/locales/en.json index 2702f97..54d2a3b 100644 --- a/src/renderer/src/locales/en.json +++ b/src/renderer/src/locales/en.json @@ -109,10 +109,11 @@ "cli_default_php_desc": "Choose which version will be used when you run the 'php' command.", "cli_default_mariadb": "Default MariaDB Version (mysql)", "cli_default_mariadb_desc": "Default version for 'mysql' or 'mariadb' commands.", - "cli_sync_btn": "SYNC SETTINGS", + "cli_sync_btn": "Sync Commands", "cli_path_found": "PATH Found:", "cli_path_not_found": "PATH Not Set Yet", - "cli_sync_success": "CLI settings and PATH integration updated successfully.", + "cli_sync_success": "CLI commands updated successfully.", + "cli_aliases_title": "Generated Commands (Aliases)", "server_settings": "Server Settings" }, "server": { diff --git a/src/renderer/src/locales/tr.json b/src/renderer/src/locales/tr.json index f09aa01..0393403 100644 --- a/src/renderer/src/locales/tr.json +++ b/src/renderer/src/locales/tr.json @@ -110,10 +110,11 @@ "cli_default_php_desc": "'php' komutunu çalıştırdığınızda hangi sürümün kullanılacağını seçin.", "cli_default_mariadb": "Varsayılan MariaDB Sürümü (mysql)", "cli_default_mariadb_desc": "'mysql' veya 'mariadb' komutu için varsayılan sürüm.", - "cli_sync_btn": "AYARLARI SENKRONİZE ET", + "cli_sync_btn": "Komutları Eşitle", "cli_path_found": "PATH Ayarı Bulundu:", "cli_path_not_found": "PATH Ayarı Henüz Yapılmamış", - "cli_sync_success": "CLI ayarları ve PATH entegrasyonu başarıyla güncellendi." + "cli_sync_success": "CLI komutları başarıyla güncellendi.", + "cli_aliases_title": "Oluşturulan Komutlar (Takma Adlar)" }, "server": { "nginx": {