seb-cli-tool
Version:
SEB CLI - Smart Embedded Board Configuration Tool - Cloud-First MCU Management
401 lines (340 loc) • 14.2 kB
JavaScript
const { spawn, execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const which = require('which');
console.log('🔧 Setting up SEB CLI Python dependencies...');
// Check Windows-specific prerequisites
function checkWindowsPrerequisites() {
const isWindows = process.platform === 'win32';
if (!isWindows) return;
console.log('🔍 Checking Windows prerequisites...');
// Check if running as Administrator (optional warning)
try {
const { execSync } = require('child_process');
execSync('net session', { stdio: 'ignore' });
console.log('✅ Running with Administrator privileges');
} catch (e) {
console.log('⚠️ Not running as Administrator (this might cause issues)');
console.log('💡 If installation fails, try running as Administrator');
}
// Check PowerShell execution policy (skip if module not available)
try {
const { execSync } = require('child_process');
const policy = execSync('powershell -Command "Get-ExecutionPolicy"', { encoding: 'utf8' }).trim();
if (policy === 'Restricted') {
console.log('⚠️ PowerShell execution policy is Restricted');
console.log('💡 Run: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser');
} else {
console.log(`✅ PowerShell execution policy: ${policy}`);
}
} catch (e) {
console.log('⚠️ Could not check PowerShell execution policy (continuing anyway)');
}
}
// Find Python executable
function findPython() {
const isWindows = process.platform === 'win32';
try {
// Try python3 first
return which.sync('python3');
} catch (e) {
try {
// Fallback to python
return which.sync('python');
} catch (e) {
// On Windows, try common Python installation paths
if (isWindows) {
const commonPaths = [
'C:\\Python310\\python.exe',
'C:\\Python311\\python.exe',
'C:\\Python312\\python.exe',
'C:\\Users\\' + process.env.USERNAME + '\\AppData\\Local\\Programs\\Python\\Python310\\python.exe',
'C:\\Users\\' + process.env.USERNAME + '\\AppData\\Local\\Programs\\Python\\Python311\\python.exe',
'C:\\Users\\' + process.env.USERNAME + '\\AppData\\Local\\Programs\\Python\\Python312\\python.exe'
];
for (const pythonPath of commonPaths) {
if (fs.existsSync(pythonPath)) {
console.log(`✅ Found Python at: ${pythonPath}`);
return pythonPath;
}
}
}
console.error('❌ Python not found. Please install Python 3.10+ from https://www.python.org/downloads/');
if (isWindows) {
console.error('💡 Make sure to check "Add Python to PATH" during installation');
console.error('💡 Or try running: npm run setup-windows');
}
process.exit(1);
}
}
}
// Check Python version
function checkPythonVersion(pythonPath) {
try {
const version = execSync(`"${pythonPath}" --version`, { encoding: 'utf8' });
const match = version.match(/Python (\d+)\.(\d+)/);
if (match) {
const major = parseInt(match[1]);
const minor = parseInt(match[2]);
if (major < 3 || (major === 3 && minor < 10)) {
console.error('❌ Python 3.10+ is required. Found:', version.trim());
process.exit(1);
}
console.log(`✅ Found Python ${version.trim()}`);
return true;
}
} catch (e) {
console.error('❌ Could not check Python version:', e.message);
process.exit(1);
}
}
// Create virtual environment
function createVirtualEnv(pythonPath) {
const isWindows = process.platform === 'win32';
const isGlobalInstall = process.env.npm_config_global === 'true' || process.argv.includes('--global');
let venvPath;
if (isGlobalInstall) {
const userHome = process.env.HOME || process.env.USERPROFILE;
const sebHome = path.join(userHome, '.seb');
venvPath = path.join(sebHome, 'venv');
// Create .seb directory if it doesn't exist
if (!fs.existsSync(sebHome)) {
try {
fs.mkdirSync(sebHome, { recursive: true });
} catch (error) {
console.error('❌ Could not create .seb directory:', error.message);
if (isWindows) {
console.error('💡 Try running as Administrator or check folder permissions');
console.error('💡 Alternative: Try installing in a different location');
}
throw error;
}
}
} else {
// For local installations, use package directory
const packageDir = path.dirname(__dirname);
venvPath = path.join(packageDir, 'seb_env');
}
// Windows-specific: Check for path length issues
if (isWindows && venvPath.length > 200) {
console.warn('⚠️ Warning: Path is very long, this might cause issues on Windows');
console.warn(` Path length: ${venvPath.length} characters`);
console.warn(' Consider installing in a shorter path');
}
if (fs.existsSync(venvPath)) {
console.log('✅ Virtual environment already exists');
return venvPath;
}
console.log('🔧 Creating virtual environment...');
return new Promise((resolve, reject) => {
const venvDir = path.dirname(venvPath);
const venvName = path.basename(venvPath);
console.log(`📁 Creating venv in: ${venvDir}`);
console.log(`📁 Venv name: ${venvName}`);
const venvProcess = spawn(pythonPath, ['-m', 'venv', venvName], {
stdio: 'inherit',
cwd: venvDir
});
venvProcess.on('close', (code) => {
if (code === 0) {
console.log('✅ Virtual environment created');
resolve(venvPath);
} else {
console.error('❌ Failed to create virtual environment');
if (isWindows) {
console.error('💡 Common Windows issues:');
console.error(' - Run as Administrator');
console.error(' - Check antivirus is not blocking');
console.error(' - Try: npm run setup-windows');
console.error(' - Try installing in a different location (shorter path)');
// Try alternative approach for Windows
console.log('🔄 Trying alternative virtual environment creation...');
tryAlternativeVenvCreation(pythonPath, venvPath).then(resolve).catch(reject);
} else {
reject(new Error(`venv creation failed with code ${code}`));
}
}
});
venvProcess.on('error', (error) => {
console.error('❌ Error creating virtual environment:', error.message);
if (isWindows) {
console.error('💡 Try running: npm run setup-windows');
}
reject(error);
});
});
}
// Alternative virtual environment creation for Windows
function tryAlternativeVenvCreation(pythonPath, originalVenvPath) {
return new Promise((resolve, reject) => {
console.log('🔄 Trying alternative virtual environment creation...');
// Try creating in a shorter path
const userHome = process.env.USERPROFILE;
const alternativePath = path.join(userHome, 'seb_venv');
console.log(`📁 Trying alternative path: ${alternativePath}`);
const altVenvProcess = spawn(pythonPath, ['-m', 'venv', alternativePath], {
stdio: 'inherit',
cwd: userHome
});
altVenvProcess.on('close', (code) => {
if (code === 0) {
console.log('✅ Alternative virtual environment created successfully');
console.log(`📁 Location: ${alternativePath}`);
resolve(alternativePath);
} else {
console.error('❌ Alternative virtual environment creation also failed');
console.error('💡 Manual installation required:');
console.error(' 1. Open Command Prompt as Administrator');
console.error(' 2. Run: python -m venv C:\\seb_venv');
console.error(' 3. Run: C:\\seb_venv\\Scripts\\activate');
console.error(' 4. Run: pip install -r requirements.txt');
reject(new Error('All virtual environment creation methods failed'));
}
});
altVenvProcess.on('error', (error) => {
console.error('❌ Alternative virtual environment creation error:', error.message);
reject(error);
});
});
}
// Get virtual environment Python path
function getVenvPython(venvPath) {
const isWindows = process.platform === 'win32';
const pythonName = isWindows ? 'python.exe' : 'python';
const pythonPath = path.join(venvPath, isWindows ? 'Scripts' : 'bin', pythonName);
if (fs.existsSync(pythonPath)) {
return pythonPath;
}
// Try python3
const python3Name = isWindows ? 'python3.exe' : 'python3';
const python3Path = path.join(venvPath, isWindows ? 'Scripts' : 'bin', python3Name);
if (fs.existsSync(python3Path)) {
return python3Path;
}
throw new Error('Could not find Python in virtual environment');
}
// Install Python dependencies in virtual environment
function installPythonDeps(venvPython) {
const packageDir = path.dirname(__dirname);
const requirementsPath = path.join(packageDir, 'requirements.txt');
const isWindows = process.platform === 'win32';
if (!fs.existsSync(requirementsPath)) {
console.log('⚠️ No requirements.txt found, skipping Python dependency installation');
return Promise.resolve();
}
console.log('📦 Installing Python dependencies...');
console.log(`📁 Requirements file: ${requirementsPath}`);
return new Promise((resolve, reject) => {
const pipProcess = spawn(venvPython, ['-m', 'pip', 'install', '-r', requirementsPath], {
stdio: 'inherit',
cwd: packageDir
});
pipProcess.on('close', (code) => {
if (code === 0) {
console.log('✅ Python dependencies installed successfully');
resolve();
} else {
console.error('❌ Failed to install Python dependencies');
if (isWindows) {
console.error('💡 Common Windows pip issues:');
console.error(' - Check internet connection');
console.error(' - Try: pip install --upgrade pip');
console.error(' - Try: npm run setup-windows');
console.error(' - Try running as Administrator');
console.error(' - Check antivirus/firewall settings');
// Provide manual installation steps
console.error('💡 Manual installation steps:');
console.error(' 1. Open Command Prompt as Administrator');
console.error(' 2. Navigate to virtual environment: cd %USERPROFILE%\\.seb\\venv\\Scripts');
console.error(' 3. Activate: activate.bat');
console.error(' 4. Install: pip install -r requirements.txt');
}
reject(new Error(`pip install failed with code ${code}`));
}
});
pipProcess.on('error', (error) => {
console.error('❌ Error running pip:', error.message);
if (isWindows) {
console.error('💡 Try running: npm run setup-windows');
}
reject(error);
});
});
}
// Install the SEB package in development mode
function installSebPackage(venvPython) {
const packageDir = path.dirname(__dirname);
const setupPath = path.join(packageDir, 'setup.py');
if (!fs.existsSync(setupPath)) {
console.log('⚠️ No setup.py found, skipping package installation');
return Promise.resolve();
}
console.log('🔧 Installing SEB package in development mode...');
return new Promise((resolve, reject) => {
const installProcess = spawn(venvPython, ['-m', 'pip', 'install', '-e', '.'], {
stdio: 'inherit',
cwd: packageDir
});
installProcess.on('close', (code) => {
if (code === 0) {
console.log('✅ SEB package installed successfully');
resolve();
} else {
console.error('❌ Failed to install SEB package');
reject(new Error(`pip install -e failed with code ${code}`));
}
});
installProcess.on('error', (error) => {
console.error('❌ Error installing SEB package:', error.message);
reject(error);
});
});
}
// Create configuration file for global installations
function createConfigFile(venvPath) {
const isGlobalInstall = process.env.npm_config_global === 'true' || process.argv.includes('--global');
if (isGlobalInstall) {
const userHome = process.env.HOME || process.env.USERPROFILE;
const sebHome = path.join(userHome, '.seb');
const configPath = path.join(sebHome, 'config.json');
const isWindows = process.platform === 'win32';
const config = {
venv_path: venvPath,
python_path: path.join(venvPath, isWindows ? 'Scripts' : 'bin', isWindows ? 'python.exe' : 'python'),
created_at: new Date().toISOString(),
platform: process.platform,
analytics_enabled: true // Enable analytics by default
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
console.log('✅ Configuration file created for global installation');
}
}
// Main installation process
async function main() {
try {
// Check Windows prerequisites first
checkWindowsPrerequisites();
const pythonPath = findPython();
checkPythonVersion(pythonPath);
// Always create virtual environment to avoid externally-managed-environment issues
const venvPath = await createVirtualEnv(pythonPath);
const venvPython = getVenvPython(venvPath);
await installPythonDeps(venvPython);
await installSebPackage(venvPython);
// Create configuration file for global installations
createConfigFile(venvPath);
console.log('🎉 SEB CLI setup complete!');
console.log(`💡 Virtual environment: ${venvPath}`);
console.log('💡 You can now use: seb --help');
} catch (error) {
console.error('❌ Setup failed:', error.message);
console.log('💡 Try running: npm run setup-python');
process.exit(1);
}
}
// Run if called directly
if (require.main === module) {
main();
}
module.exports = { main, findPython, checkPythonVersion, createVirtualEnv, getVenvPython, installPythonDeps, installSebPackage, createConfigFile };