Skip to main content
Glama
check-python.js22.9 kB
#!/usr/bin/env node /** * Script to setup Python environment using uv * Using this simplified approach: * 1. Check if uv is installed * 2. If not installed, try to install it automatically * 3. If installation fails, prompt user to install manually * 4. Create Python 3.11 virtual environment with uv * 5. Install dependencies and setup the environment */ const { execSync, exec } = require('child_process'); const path = require('path'); const fs = require('fs'); const os = require('os'); // Extension directory const extensionDir = __dirname ? path.dirname(__dirname) : process.cwd(); // File to store Python path const pythonPathFile = path.join(extensionDir, '.python-path'); const uvPathFile = path.join(extensionDir, '.uv-path'); const setupCompleteFile = path.join(extensionDir, '.setup-complete'); console.log('Checking for UV and setting up Python environment...'); console.log(`Extension directory: ${extensionDir}`); // Execute a command as a promise function execPromise(command) { return new Promise((resolve, reject) => { exec(command, { maxBuffer: 1024 * 1024 * 10 }, (error, stdout, stderr) => { if (error) { error.stdout = stdout; error.stderr = stderr; reject(error); } else { resolve(stdout); } }); }); } // Helper function to check if a file is executable function isExecutable(filePath) { try { fs.accessSync(filePath, fs.constants.X_OK); return true; } catch (err) { return false; } } // Function to display UV installation instructions based on platform function promptUvInstallation() { console.log('\n=================================================='); console.log('MANUAL UV INSTALLATION REQUIRED'); console.log('=================================================='); console.log('Please install UV manually using one of the following commands:'); if (process.platform === 'win32') { console.log('\nFor Windows (run in PowerShell as Administrator):'); console.log('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"'); } else { console.log('\nFor macOS/Linux:'); console.log('Option 1 (may require sudo): curl -LsSf https://astral.sh/uv/install.sh | sudo sh'); console.log('Option 2 (user install): curl -LsSf https://astral.sh/uv/install.sh | sh'); } console.log('\nAfter installation:'); console.log('1. Restart your IDE completely'); console.log('2. Verify UV is installed by running "uv --version" in a terminal'); console.log('3. The extension will use UV automatically when restarted'); console.log('=================================================='); } // Check if UV is installed function isUvInstalled() { console.log('\n========== CHECKING FOR UV =========='); // Default response object const result = { installed: false, path: null }; // First check if we have a saved path if (fs.existsSync(uvPathFile)) { const savedPath = fs.readFileSync(uvPathFile, 'utf8').trim(); console.log(`Found saved UV path: ${savedPath}`); // Validate that the saved path is compatible with current platform const isWin32 = process.platform === 'win32'; const pathHasBackslash = savedPath.includes('\\'); if ((isWin32 && !pathHasBackslash) || (!isWin32 && pathHasBackslash)) { console.log(`Warning: Saved UV path is not compatible with current platform (${process.platform}). Ignoring saved path.`); try { fs.unlinkSync(uvPathFile); console.log(`Removed incompatible saved path file: ${uvPathFile}`); } catch (error) { console.warn(`Failed to remove saved path file: ${error.message}`); } } else if (fs.existsSync(savedPath) && isExecutable(savedPath)) { console.log(`Verified UV at saved path: ${savedPath}`); return { installed: true, path: savedPath }; } else { console.log(`Saved UV path doesn't exist or is not executable: ${savedPath}`); try { fs.unlinkSync(uvPathFile); console.log(`Removed invalid saved path file: ${uvPathFile}`); } catch (error) { console.warn(`Failed to remove saved path file: ${error.message}`); } } } // Try running 'uv --version' to see if it's in PATH try { const version = execSync('uv --version', { stdio: 'pipe' }).toString().trim(); console.log(`Found UV in PATH: version ${version}`); // Get the actual path to the UV executable let uvPath = 'uv'; // Default if we can't determine the actual path try { if (process.platform === 'win32') { const pathOutput = execSync('where uv', { stdio: 'pipe' }).toString().trim().split('\n')[0]; uvPath = pathOutput; } else { const pathOutput = execSync('which uv', { stdio: 'pipe' }).toString().trim(); uvPath = pathOutput; } console.log(`UV full path: ${uvPath}`); // Save the path for future use fs.writeFileSync(uvPathFile, uvPath, { encoding: 'utf8' }); console.log(`Saved UV path to ${uvPathFile}`); } catch (pathError) { console.log(`Could not determine UV path: ${pathError.message}`); } return { installed: true, path: uvPath }; } catch (error) { console.log('UV not found in PATH'); // Check in common install locations const homeDir = os.homedir(); const commonPaths = []; if (process.platform === 'win32') { commonPaths.push( path.join(homeDir, '.local', 'bin', 'uv.exe'), // Common install location path.join(homeDir, '.cargo', 'bin', 'uv.exe'), path.join(homeDir, 'AppData', 'Local', 'uv', 'uv.exe'), path.join(homeDir, 'AppData', 'Local', 'Programs', 'uv', 'uv.exe'), path.join('C:', 'ProgramData', 'uv', 'uv.exe') ); } else { commonPaths.push( path.join(homeDir, '.cargo', 'bin', 'uv'), path.join(homeDir, '.local', 'bin', 'uv'), '/usr/local/bin/uv', '/opt/homebrew/bin/uv', '/opt/local/bin/uv', '/usr/bin/uv' ); } console.log('Checking common installation locations...'); for (const uvPath of commonPaths) { console.log(`Checking ${uvPath}...`); if (fs.existsSync(uvPath) && isExecutable(uvPath)) { console.log(`Found UV at: ${uvPath}`); // Verify it works try { const version = execSync(`"${uvPath}" --version`, { stdio: 'pipe' }).toString().trim(); console.log(`Verified UV at ${uvPath}: version ${version}`); // Save the path for future use fs.writeFileSync(uvPathFile, uvPath, { encoding: 'utf8' }); console.log(`Saved UV path to ${uvPathFile}`); return { installed: true, path: uvPath }; } catch (verifyError) { console.log(`Found UV at ${uvPath} but verification failed: ${verifyError.message}`); } } } console.log('UV not found in any common installation locations'); return result; } } // Install UV async function installUv() { console.log('\n========== INSTALLING UV =========='); console.log(`Installing uv on ${process.platform}...`); try { let installCommand; if (process.platform === 'win32') { installCommand = 'powershell -ExecutionPolicy ByPass -Command "& {irm https://astral.sh/uv/install.ps1 | iex}"'; } else { // Try to create the target directory with proper permissions first try { fs.mkdirSync(path.join(os.homedir(), '.local', 'bin'), { recursive: true }); } catch (err) { console.log(`Note: Could not ensure ~/.local/bin exists: ${err.message}`); } // Use the user-level install (no sudo) installCommand = 'curl -LsSf https://astral.sh/uv/install.sh | sh'; } console.log(`Running: ${installCommand}`); try { const stdout = await execPromise(installCommand); console.log(`Installation output: ${stdout}`); // Check if installation was successful const uvInfo = isUvInstalled(); if (uvInfo.installed) { console.log(`UV successfully installed at: ${uvInfo.path}`); return uvInfo; } else { // Try alternative installation if the first method failed console.log('First installation method failed, trying alternative...'); if (process.platform === 'win32') { // Alternative Windows installation using direct download const tempDir = path.join(os.tmpdir(), 'uv-installer'); try { if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); } const downloadCommand = 'powershell -Command "& {Invoke-WebRequest -Uri https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-pc-windows-msvc.zip -OutFile uv.zip}"'; await execPromise(`cd "${tempDir}" && ${downloadCommand}`); await execPromise(`cd "${tempDir}" && powershell -Command "& {Expand-Archive -Path uv.zip -DestinationPath .}""`); const userBinDir = path.join(os.homedir(), '.local', 'bin'); if (!fs.existsSync(userBinDir)) { fs.mkdirSync(userBinDir, { recursive: true }); } fs.copyFileSync(path.join(tempDir, 'uv.exe'), path.join(userBinDir, 'uv.exe')); console.log(`Copied UV to ${path.join(userBinDir, 'uv.exe')}`); // Check installation again return isUvInstalled(); } catch (altError) { console.error(`Alternative installation failed: ${altError.message}`); console.error('Please install UV manually.'); promptUvInstallation(); return { installed: false, path: null }; } } else { // Alternative macOS/Linux installation - download binary directly let platform = 'unknown'; let arch = process.arch; if (process.platform === 'darwin') { platform = 'apple-darwin'; // Handle ARM vs Intel Mac arch = process.arch === 'arm64' ? 'aarch64' : 'x86_64'; } else if (process.platform === 'linux') { platform = 'unknown-linux-gnu'; // Handle ARM vs x86 arch = process.arch === 'arm64' ? 'aarch64' : 'x86_64'; } if (platform !== 'unknown') { const binaryName = `uv-${arch}-${platform}`; const downloadUrl = `https://github.com/astral-sh/uv/releases/latest/download/${binaryName}.tar.gz`; const tempDir = path.join(os.tmpdir(), 'uv-installer'); try { if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); } await execPromise(`cd "${tempDir}" && curl -L ${downloadUrl} -o uv.tar.gz`); await execPromise(`cd "${tempDir}" && tar xzf uv.tar.gz`); const userBinDir = path.join(os.homedir(), '.local', 'bin'); if (!fs.existsSync(userBinDir)) { fs.mkdirSync(userBinDir, { recursive: true }); } fs.copyFileSync(path.join(tempDir, 'uv'), path.join(userBinDir, 'uv')); fs.chmodSync(path.join(userBinDir, 'uv'), '755'); // Make executable console.log(`Copied UV to ${path.join(userBinDir, 'uv')}`); // Update PATH for the current process process.env.PATH = `${userBinDir}:${process.env.PATH}`; // Check installation again return isUvInstalled(); } catch (altError) { console.error(`Alternative installation failed: ${altError.message}`); console.error('Please install UV manually.'); promptUvInstallation(); return { installed: false, path: null }; } } else { console.error(`Unsupported platform: ${process.platform}`); promptUvInstallation(); return { installed: false, path: null }; } } } } catch (installError) { console.error(`Installation script failed: ${installError.message}`); console.error(`stdout: ${installError.stdout || 'none'}`); console.error(`stderr: ${installError.stderr || 'none'}`); console.error('Failed to install uv. Please install it manually.'); promptUvInstallation(); return { installed: false, path: null }; } } catch (error) { console.error(`Failed to install uv: ${error.message}`); promptUvInstallation(); return { installed: false, path: null }; } } // Setup Python with UV async function setupPythonWithUv() { console.log('\n========== SETTING UP PYTHON WITH UV =========='); // Check if uv is installed or install it let uvInfo = isUvInstalled(); if (!uvInfo.installed) { console.log('uv not found, attempting to install...'); uvInfo = await installUv(); if (!uvInfo.installed) { console.error('Failed to install uv. Cannot proceed with Python setup.'); promptUvInstallation(); return false; } } console.log(`Using uv at: ${uvInfo.path}`); // Create a Python virtual environment const venvPath = path.join(extensionDir, '.venv'); console.log(`Setting up Python virtual environment at: ${venvPath}`); // First clean up any existing venv if (fs.existsSync(venvPath)) { console.log(`Removing existing venv at ${venvPath}`); try { await execPromise(`${process.platform === 'win32' ? 'rmdir /s /q' : 'rm -rf'} "${venvPath}"`); console.log('Successfully removed existing venv'); } catch (error) { console.warn(`Warning: Failed to remove existing venv: ${error.message}`); // Continue anyway, we'll try to work with the existing venv } } console.log(`Creating a new venv at ${venvPath}`); // Create venv with uv try { const uvCmd = uvInfo.path === 'uv' ? 'uv' : `"${uvInfo.path}"`; const createVenvCmd = `${uvCmd} venv "${venvPath}" --python 3.11`; console.log(`Running: ${createVenvCmd}`); await execPromise(createVenvCmd); console.log('Successfully created Python virtual environment with uv'); // Install dependencies using uv instead of pip const requirementsPath = path.join(extensionDir, 'src', 'requirements.txt'); if (fs.existsSync(requirementsPath)) { console.log('Installing Python dependencies using uv...'); try { // Determine Python executable path based on platform const pythonPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'python.exe') : path.join(venvPath, 'bin', 'python'); // Install dependencies using uv pip instead of regular pip const installCmd = `${uvCmd} pip install --python "${pythonPath}" -r "${requirementsPath}"`; console.log(`Running: ${installCmd}`); await execPromise(installCmd); console.log('Successfully installed Python dependencies with uv'); // Verify Python path and write to file if (fs.existsSync(pythonPath)) { try { // Create Python path file fs.writeFileSync(pythonPathFile, pythonPath, { encoding: 'utf8' }); console.log(`Python path saved to ${pythonPathFile}`); // Create setup complete marker fs.writeFileSync(setupCompleteFile, new Date().toISOString(), { encoding: 'utf8' }); console.log(`Setup complete marker created at ${setupCompleteFile}`); return true; } catch (error) { console.error(`Error writing setup files: ${error.message}`); promptUvInstallation(); return false; } } else { console.error(`Python executable not found at expected path: ${pythonPath}`); promptUvInstallation(); return false; } } catch (error) { console.error(`Error installing Python dependencies with uv: ${error.message}`); promptUvInstallation(); return false; } } else { console.log('No requirements.txt found. Skipping dependency installation.'); // Verify Python path exists even without requirements const pythonPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'python.exe') : path.join(venvPath, 'bin', 'python'); if (fs.existsSync(pythonPath)) { // Create Python path file fs.writeFileSync(pythonPathFile, pythonPath, { encoding: 'utf8' }); console.log(`Python path saved to ${pythonPathFile}`); // Create setup complete marker fs.writeFileSync(setupCompleteFile, new Date().toISOString(), { encoding: 'utf8' }); console.log(`Setup complete marker created at ${setupCompleteFile}`); return true; } else { console.error(`Python executable not found at expected path: ${pythonPath}`); promptUvInstallation(); return false; } } } catch (error) { console.error(`Error creating venv with uv: ${error.message}`); promptUvInstallation(); return false; } } // Main function async function main() { console.log(`Running Python setup in ${extensionDir}`); // Clean up any existing .uv-path when packaging the extension if (process.env.NODE_ENV === 'production' && fs.existsSync(uvPathFile)) { console.log(`Removing .uv-path in production mode: ${uvPathFile}`); try { fs.unlinkSync(uvPathFile); } catch (error) { console.warn(`Failed to remove .uv-path in production mode: ${error.message}`); } } // If setup is already complete and recent, skip if (fs.existsSync(setupCompleteFile) && fs.existsSync(pythonPathFile)) { const setupTime = new Date(fs.readFileSync(setupCompleteFile, 'utf8')); const now = new Date(); const hoursSinceSetup = (now - setupTime) / (1000 * 60 * 60); if (hoursSinceSetup < 24) { // Only use cache for 24 hours const pythonPath = fs.readFileSync(pythonPathFile, 'utf8').trim(); if (fs.existsSync(pythonPath) && isExecutable(pythonPath)) { console.log(`Python setup already complete (${hoursSinceSetup.toFixed(2)} hours ago)`); console.log(`Using cached Python path: ${pythonPath}`); return 0; } } } try { // STEP 1: Check for UV installation let uvInfo = isUvInstalled(); // STEP 2: If UV not found, try to install it if (!uvInfo.installed) { console.log('UV not found, attempting installation...'); uvInfo = await installUv(); // STEP 3: If installation fails, prompt user with manual instructions if (!uvInfo.installed) { console.error('Failed to install UV automatically.'); promptUvInstallation(); return 1; } } console.log(`UV found at: ${uvInfo.path}`); // STEP 4: Setup Python virtual environment with UV const success = await setupPythonWithUv(); if (success) { console.log('\nSetup completed successfully!'); return 0; } else { console.error('\nSetup failed: Failed to setup Python with UV'); return 1; } } catch (error) { console.error(`\nSetup failed: ${error.message}`); return 1; } } // Run the main function main().then(exitCode => { process.exit(exitCode); }).catch(error => { console.error(`Unhandled exception: ${error.message}`); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hanlulong/stata-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server