UNPKG

seb-cli-tool

Version:

SEB CLI - Smart Embedded Board Configuration Tool - Cloud-First MCU Management

243 lines (215 loc) • 8.3 kB
#!/usr/bin/env node const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); // Import update checker let UpdateChecker; try { UpdateChecker = require('../scripts/update-checker.js'); } catch (error) { // Update checker not available, continue without it UpdateChecker = null; } // Get the directory where this script is located const scriptDir = path.dirname(require.main.filename); const packageDir = path.dirname(scriptDir); // Check if we're running from a packaged binary or development const isWindows = process.platform === 'win32'; const isBinaryPackaged = fs.existsSync(path.join(packageDir, 'dist', isWindows ? 'seb.exe' : 'seb')); const isDevelopment = fs.existsSync(path.join(packageDir, 'seb', 'cli', 'main.py')); let pythonCommand; let pythonArgs; // Python command detection with virtual environment support function findPythonCommand() { const { execSync } = require('child_process'); const isWindows = process.platform === 'win32'; // First check for SEB configuration file const userHome = process.env.HOME || process.env.USERPROFILE; const sebConfigPath = path.join(userHome, '.seb', 'config.json'); if (fs.existsSync(sebConfigPath)) { try { const config = JSON.parse(fs.readFileSync(sebConfigPath, 'utf8')); if (config.python_path && fs.existsSync(config.python_path)) { try { execSync(`"${config.python_path}" --version`, { stdio: 'ignore' }); return config.python_path; } catch (e) { // Continue to other options } } } catch (e) { // Continue to other options } } // Check for SEB virtual environment in package directory const sebVenvPath = path.join(packageDir, 'seb_env'); if (fs.existsSync(sebVenvPath)) { const venvPython = path.join(sebVenvPath, isWindows ? 'Scripts' : 'bin', isWindows ? 'python.exe' : 'python'); const venvPython3 = path.join(sebVenvPath, isWindows ? 'Scripts' : 'bin', isWindows ? 'python3.exe' : 'python3'); try { execSync(`"${venvPython}" --version`, { stdio: 'ignore' }); return venvPython; } catch (e) { try { execSync(`"${venvPython3}" --version`, { stdio: 'ignore' }); return venvPython3; } catch (e) { // Continue to other options } } } // Check if we're in a virtual environment if (process.env.VIRTUAL_ENV) { const venvPython = path.join(process.env.VIRTUAL_ENV, isWindows ? 'Scripts' : 'bin', isWindows ? 'python.exe' : 'python'); try { execSync(`"${venvPython}" --version`, { stdio: 'ignore' }); return venvPython; } catch (e) { // Fallback to venv python3 const venvPython3 = path.join(process.env.VIRTUAL_ENV, isWindows ? 'Scripts' : 'bin', isWindows ? 'python3.exe' : 'python3'); try { execSync(`"${venvPython3}" --version`, { stdio: 'ignore' }); return venvPython3; } catch (e) { // Continue to system Python } } } // Check for global SEB virtual environment const globalSebVenvPath = path.join(userHome, '.seb', 'venv'); const globalSebVenvPython = path.join(globalSebVenvPath, isWindows ? 'Scripts' : 'bin', isWindows ? 'python.exe' : 'python'); const globalSebVenvPython3 = path.join(globalSebVenvPath, isWindows ? 'Scripts' : 'bin', isWindows ? 'python3.exe' : 'python3'); try { execSync(`"${globalSebVenvPython}" --version`, { stdio: 'ignore' }); return globalSebVenvPython; } catch (e) { try { execSync(`"${globalSebVenvPython3}" --version`, { stdio: 'ignore' }); return globalSebVenvPython3; } catch (e) { // Continue to system Python } } // Try system Python with Windows-specific paths if (isWindows) { // Try common Windows Python paths const pythonPaths = [ 'python', 'python3', 'py', path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python312', 'python.exe'), path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python311', 'python.exe'), path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Python', 'Python310', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python312', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python311', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python310', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python', 'Python312', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python', 'Python311', 'python.exe'), path.join(process.env.PROGRAMFILES || '', 'Python', 'Python310', 'python.exe'), ]; for (const pythonPath of pythonPaths) { try { execSync(`"${pythonPath}" --version`, { stdio: 'ignore' }); return pythonPath; } catch (e) { // Continue to next path } } } else { // Unix-like systems try { execSync('python3 --version', { stdio: 'ignore' }); return 'python3'; } catch (e) { try { execSync('python --version', { stdio: 'ignore' }); return 'python'; } catch (e) { // Continue to null } } } return null; } // Priority order: Platform-specific binary > Virtual environment > Development if (isBinaryPackaged) { // Use packaged binary (source code protected) - PRIORITY 1 const binaryName = isWindows ? 'seb.exe' : 'seb'; pythonCommand = path.join(packageDir, 'dist', binaryName); pythonArgs = process.argv.slice(2); } else if (isDevelopment) { // Use Python module in development - PRIORITY 2 pythonCommand = findPythonCommand() || 'python3'; pythonArgs = ['-m', 'seb.cli.main', ...process.argv.slice(2)]; } else { // Fallback: try to find Python and install if needed - PRIORITY 3 pythonCommand = findPythonCommand() || 'python3'; pythonArgs = ['-m', 'seb.cli.main', ...process.argv.slice(2)]; } // Enhanced error handling function handleError(error) { if (error.code === 'ENOENT') { console.error('āŒ Error: Python not found or SEB CLI not properly installed.'); console.error(''); console.error('šŸ”§ For Windows users:'); console.error(' 1. Make sure Python 3.10+ is installed from https://www.python.org/downloads/'); console.error(' 2. During installation, check "Add Python to PATH"'); console.error(' 3. Restart your terminal/PowerShell'); console.error(' 4. Try running: seb --version'); console.error(''); console.error('šŸ’” Alternative solutions:'); console.error(' • Run: npm install -g seb-cli-tool (reinstall)'); console.error(' • Check if Python is in PATH: python --version'); console.error(' • Try: py --version (Windows Python launcher)'); process.exit(1); } else { console.error('āŒ Error:', error.message); process.exit(1); } } // Enhanced output handling function handleOutput(data) { process.stdout.write(data); } function handleErrorOutput(data) { process.stderr.write(data); } // Check for updates in background (non-blocking) if (UpdateChecker && process.argv.length > 2 && !process.argv.includes('--no-update-check')) { const checker = new UpdateChecker(); checker.checkForUpdates().then(result => { if (result.hasUpdate) { console.log(`\nšŸ”„ Update available: ${result.currentVersion} → ${result.latestVersion}`); console.log(`šŸ“ Changelog: ${result.changelog}`); console.log(`šŸ’” Run 'npm update -g @rootaccess/seb-cli' to update\n`); } }).catch(() => { // Silent fail for update checks }); } // Main execution try { const sebProcess = spawn(pythonCommand, pythonArgs, { stdio: ['inherit', 'pipe', 'pipe'], cwd: process.cwd(), env: { ...process.env, SEB_CLI_MODE: 'npm' } }); // Handle output sebProcess.stdout.on('data', handleOutput); sebProcess.stderr.on('data', handleErrorOutput); // Handle process completion sebProcess.on('close', (code) => { process.exit(code); }); // Handle process errors sebProcess.on('error', handleError); // Handle process termination process.on('SIGINT', () => { sebProcess.kill('SIGINT'); }); process.on('SIGTERM', () => { sebProcess.kill('SIGTERM'); }); } catch (error) { handleError(error); }