UNPKG

nvenv

Version:

Python venv-like Node.js environment manager - project-local Node.js installation without global environment pollution

102 lines (80 loc) 2.69 kB
const https = require('https'); const fs = require('fs'); const path = require('path'); const { shouldBeSilent, log } = require('./utils'); /** * Download a file from URL to destination with progress indicator * @param {string} url - URL to download from * @param {string} destPath - Destination file path * @param {object} options - Options { silent: boolean } * @returns {Promise<void>} */ function downloadFile(url, destPath, options = {}) { return new Promise((resolve, reject) => { const silent = shouldBeSilent(options); // Create destination directory if it doesn't exist const destDir = path.dirname(destPath); if (!fs.existsSync(destDir)) { fs.mkdirSync(destDir, { recursive: true }); } log(`Downloading from: ${url}`, options); log(`Saving to: ${destPath}`, options); const file = fs.createWriteStream(destPath); let downloadedBytes = 0; let totalBytes = 0; const request = https.get(url, (response) => { // Handle redirects if (response.statusCode === 301 || response.statusCode === 302) { file.close(); fs.unlinkSync(destPath); const redirectUrl = response.headers.location; log(`Following redirect to: ${redirectUrl}`, options); return downloadFile(redirectUrl, destPath, options) .then(resolve) .catch(reject); } if (response.statusCode !== 200) { file.close(); fs.unlinkSync(destPath); reject(new Error(`Failed to download: HTTP ${response.statusCode}`)); return; } totalBytes = parseInt(response.headers['content-length'], 10); response.on('data', (chunk) => { downloadedBytes += chunk.length; if (!silent && totalBytes) { const percent = ((downloadedBytes / totalBytes) * 100).toFixed(1); const downloadedMB = (downloadedBytes / 1024 / 1024).toFixed(1); const totalMB = (totalBytes / 1024 / 1024).toFixed(1); process.stdout.write( `\rProgress: ${percent}% (${downloadedMB}MB / ${totalMB}MB)` ); } }); response.pipe(file); file.on('finish', () => { file.close(); log('\nDownload completed!', options); resolve(); }); }); request.on('error', (err) => { file.close(); // Delete partially downloaded file if (fs.existsSync(destPath)) { fs.unlinkSync(destPath); } reject(err); }); file.on('error', (err) => { file.close(); if (fs.existsSync(destPath)) { fs.unlinkSync(destPath); } reject(err); }); }); } module.exports = { downloadFile };