229 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| #!/usr/bin/env node
 | |
| 
 | |
| /**
 | |
|  * SZCI npm postinstall script
 | |
|  * Downloads the appropriate binary for the current platform from repository 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/ship.zone/szci';
 | |
| const VERSION = process.env.npm_package_version || '4.1.37';
 | |
| 
 | |
| 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 = `szci-${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('  SZCI - 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/ship.zone/szci/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/master/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/ship.zone/szci');
 | |
|         console.error('2. Downloading the binary manually from the releases page');
 | |
|         console.error('3. Building from source with: deno task compile');
 | |
| 
 | |
|         // 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('✅ SZCI installation completed successfully!');
 | |
|   console.log('');
 | |
|   console.log('You can now use SZCI by running:');
 | |
|   console.log('  szci --help');
 | |
|   console.log('');
 | |
|   console.log('===========================================');
 | |
| }
 | |
| 
 | |
| // Run the installation
 | |
| main().catch(err => {
 | |
|   console.error(`❌ Installation failed: ${err.message}`);
 | |
|   process.exit(1);
 | |
| });
 |