#!/usr/bin/env node /** * NUPST npm postinstall script * Downloads the appropriate binary for the current platform from GitHub releases */ import { platform, arch } from 'os'; import { existsSync, mkdirSync, writeFileSync, chmodSync, unlinkSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import https from 'https'; import { pipeline } from 'stream'; import { promisify } from 'util'; import { createWriteStream } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const streamPipeline = promisify(pipeline); // Configuration const REPO_BASE = 'https://code.foss.global/serve.zone/nupst'; const VERSION = process.env.npm_package_version || '5.0.5'; function getBinaryInfo() { const plat = platform(); const architecture = arch(); const platformMap = { 'darwin': 'macos', 'linux': 'linux', 'win32': 'windows' }; const archMap = { 'x64': 'x64', 'arm64': 'arm64' }; const mappedPlatform = platformMap[plat]; const mappedArch = archMap[architecture]; if (!mappedPlatform || !mappedArch) { return { supported: false, platform: plat, arch: architecture }; } let binaryName = `nupst-${mappedPlatform}-${mappedArch}`; if (plat === 'win32') { binaryName += '.exe'; } return { supported: true, platform: mappedPlatform, arch: mappedArch, binaryName, originalPlatform: plat }; } function downloadFile(url, destination) { return new Promise((resolve, reject) => { console.log(`Downloading from: ${url}`); // Follow redirects const download = (url, redirectCount = 0) => { if (redirectCount > 5) { reject(new Error('Too many redirects')); return; } https.get(url, (response) => { if (response.statusCode === 301 || response.statusCode === 302) { console.log(`Following redirect to: ${response.headers.location}`); download(response.headers.location, redirectCount + 1); return; } if (response.statusCode !== 200) { reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`)); return; } const totalSize = parseInt(response.headers['content-length'], 10); let downloadedSize = 0; let lastProgress = 0; response.on('data', (chunk) => { downloadedSize += chunk.length; const progress = Math.round((downloadedSize / totalSize) * 100); // Only log every 10% to reduce noise if (progress >= lastProgress + 10) { console.log(`Download progress: ${progress}%`); lastProgress = progress; } }); const file = createWriteStream(destination); pipeline(response, file, (err) => { if (err) { reject(err); } else { console.log('Download complete!'); resolve(); } }); }).on('error', reject); }; download(url); }); } async function main() { console.log('==========================================='); console.log(' NUPST - Binary Installation'); console.log('==========================================='); console.log(''); const binaryInfo = getBinaryInfo(); if (!binaryInfo.supported) { console.error(`❌ Error: Unsupported platform/architecture: ${binaryInfo.platform}/${binaryInfo.arch}`); console.error(''); console.error('Supported platforms:'); console.error(' • Linux (x64, arm64)'); console.error(' • macOS (x64, arm64)'); console.error(' • Windows (x64)'); console.error(''); console.error('If you believe your platform should be supported, please file an issue:'); console.error(' https://code.foss.global/serve.zone/nupst/issues'); process.exit(1); } console.log(`Platform: ${binaryInfo.platform} (${binaryInfo.originalPlatform})`); console.log(`Architecture: ${binaryInfo.arch}`); console.log(`Binary: ${binaryInfo.binaryName}`); console.log(`Version: ${VERSION}`); console.log(''); // Create dist/binaries directory if it doesn't exist const binariesDir = join(__dirname, '..', 'dist', 'binaries'); if (!existsSync(binariesDir)) { console.log('Creating binaries directory...'); mkdirSync(binariesDir, { recursive: true }); } const binaryPath = join(binariesDir, binaryInfo.binaryName); // Check if binary already exists and skip download if (existsSync(binaryPath)) { console.log('✓ Binary already exists, skipping download'); } else { // Construct download URL // Try release URL first, fall back to raw branch if needed const releaseUrl = `${REPO_BASE}/releases/download/v${VERSION}/${binaryInfo.binaryName}`; const fallbackUrl = `${REPO_BASE}/raw/branch/main/dist/binaries/${binaryInfo.binaryName}`; console.log('Downloading platform-specific binary...'); console.log('This may take a moment depending on your connection speed.'); console.log(''); try { // Try downloading from release await downloadFile(releaseUrl, binaryPath); } catch (err) { console.log(`Release download failed: ${err.message}`); console.log('Trying fallback URL...'); try { // Try fallback URL await downloadFile(fallbackUrl, binaryPath); } catch (fallbackErr) { console.error(`❌ Error: Failed to download binary`); console.error(` Primary URL: ${releaseUrl}`); console.error(` Fallback URL: ${fallbackUrl}`); console.error(''); console.error('This might be because:'); console.error('1. The release has not been created yet'); console.error('2. Network connectivity issues'); console.error('3. The version specified does not exist'); console.error(''); console.error('You can try:'); console.error('1. Installing from source: https://code.foss.global/serve.zone/nupst'); console.error('2. Downloading the binary manually from the releases page'); console.error('3. Using the install script: curl -sSL https://code.foss.global/serve.zone/nupst/raw/branch/main/install.sh | sudo bash'); // Clean up partial download if (existsSync(binaryPath)) { unlinkSync(binaryPath); } process.exit(1); } } console.log(`✓ Binary downloaded successfully`); } // On Unix-like systems, ensure the binary is executable if (binaryInfo.originalPlatform !== 'win32') { try { console.log('Setting executable permissions...'); chmodSync(binaryPath, 0o755); console.log('✓ Binary permissions updated'); } catch (err) { console.error(`⚠️ Warning: Could not set executable permissions: ${err.message}`); console.error(' You may need to manually run:'); console.error(` chmod +x ${binaryPath}`); } } console.log(''); console.log('✅ NUPST installation completed successfully!'); console.log(''); console.log('You can now use NUPST by running:'); console.log(' nupst --help'); console.log(''); console.log('For initial setup, run:'); console.log(' sudo nupst ups add'); console.log(''); console.log('==========================================='); } // Run the installation main().catch(err => { console.error(`❌ Installation failed: ${err.message}`); process.exit(1); });