UNPKG

pear

Version:
203 lines (182 loc) 5.54 kB
#!/usr/bin/env node const process = require('process') const HypercoreID = require('hypercore-id-encoding') const os = require('os') const path = require('path') const fs = require('fs') const { isWindows, isLinux, isMac, platform, arch } = require('which-runtime') const goodbye = require('graceful-goodbye') const speedometer = require('speedometer') const byteSize = require('tiny-byte-size') const { discoveryKey } = require('hypercore-crypto') const isTTY = process.stdout.isTTY const PROD_KEY = 'pear://pzcjqmpoo6szkoc4bpkw65ib9ctnrq7b6mneeinbhbheihaq6p6o' const PEAR_KEY = require('./package.json').pear.platform.key const DKEY = discoveryKey(HypercoreID.decode(PEAR_KEY)).toString('hex') const HOST = platform + '-' + arch const PEAR_DIR = isMac ? path.join(os.homedir(), 'Library', 'Application Support', 'pear') : isLinux ? path.join(os.homedir(), '.config', 'pear') : path.join(os.homedir(), 'AppData', 'Roaming', 'pear') const LINK = path.join(PEAR_DIR, 'current') const BIN = path.join(PEAR_DIR, 'bin') const CURRENT_BIN = path.join( LINK, 'by-arch', HOST, 'bin/pear-runtime' + (isWindows ? '.exe' : '') ) const forceUpdate = process.argv[2] === 'update' if (isInstalled() && !forceUpdate) { const warning = `[ WARNING ] To complete Pear installation, prepend the following to the system ${isWindows ? 'Path environment variable' : '$PATH'}: ${BIN} Until then, this executable spawns the ${'`pear`'} binary. Fix automatically with: pear run pear://runtime` console.error(warning) let child = null const childProcessExit = new Promise((resolve) => { child = require('child_process') .spawn(CURRENT_BIN, process.argv.slice(2), { stdio: 'inherit' }) .on('exit', function (code) { resolve(code) }) }) goodbye(async () => { child.kill() const code = await childProcessExit process.exit(code) }) } else { if (isLinux && !libatomicCheck()) { console.log( 'Installation failed. The required library libatomic.so was not found on the system.' ) console.log(` Please install it first using the appropriate package manager for your system. - Debian/Ubuntu: sudo apt install libatomic1 - Fedora: sudo dnf install libatomic - Arch Linux: sudo pacman -S libatomic_ops - Alpine Linux: sudo apk add libatomic - RHEL/CentOS: sudo yum install libatomic `) process.exit(1) } const bootstrap = require('pear-updater-bootstrap') console.log( 'Installing Pear Runtime (Please stand by, this might take a bit...)\n' ) if (PEAR_KEY !== PROD_KEY) console.log('Bootstrapping:', PEAR_KEY) bootstrap(PEAR_KEY, PEAR_DIR, { onupdater: startDriveMonitor, force: forceUpdate }).then( function () { stopDriveMonitor() console.log('Pear Runtime installed!') console.log() console.log('Finish the installation by opening the runtime app') console.log() console.log('npx pear run pear://runtime') if (makeBin()) { console.log() console.log('Or by adding the following to your path') console.log() if (isWindows) { console.log(`cmd: set PATH="${BIN};%PATH%"`) console.log(`PowerShell: $env:PATH="${BIN};$env:PATH"`) } else { console.log(`export PATH="${BIN}:$PATH"`) } } }, function (err) { if (forceUpdate && err.code === 'ENOENT') { console.log( `Update failed: Pear Runtime is not installed at ${err.path}` ) } else { throw err } } ) } function makeBin() { try { fs.mkdirSync(BIN, { recursive: true }) if (isWindows) { fs.writeFileSync( path.join(BIN, 'pear.cmd'), `@echo off\r\n"${CURRENT_BIN}" %*` ) fs.writeFileSync(path.join(BIN, 'pear.ps1'), `& "${CURRENT_BIN}" @args`) } else { fs.symlinkSync(CURRENT_BIN, path.join(BIN, 'pear')) } } catch { return false } return true } function isInstalled() { try { const p = fs.realpathSync(LINK) return path.basename(path.dirname(p)) === DKEY } catch { return false } } let monitorInterval = null function clear() { process.stdout.write('\x1b[2K') // clear line process.stdout.write('\r') // cursor to 0 } function stopDriveMonitor() { clearInterval(monitorInterval) if (isTTY) clear() } function startDriveMonitor(updater) { if (!isTTY) return const downloadSpeedometer = speedometer() const uploadSpeedometer = speedometer() let peers = 0 let downloadedBytes = 0 let uploadedBytes = 0 updater.drive .getBlobs() .then((blobs) => { blobs.core.on('download', (_index, bytes) => { downloadedBytes += bytes downloadSpeedometer(bytes) }) blobs.core.on('upload', (_index, bytes) => { uploadedBytes += bytes uploadSpeedometer(bytes) }) blobs.core.on('peer-add', () => { peers = blobs.core.peers.length }) blobs.core.on('peer-remove', () => { peers = blobs.core.peers.length }) }) .catch(() => { // ignore }) monitorInterval = setInterval(() => { clear() process.stdout.write( `[⬇ ${byteSize(downloadedBytes)} - ${byteSize(downloadSpeedometer())}/s - ${peers} peers] [⬆ ${byteSize(uploadedBytes)} - ${byteSize(uploadSpeedometer())}/s - ${peers} peers]` ) }, 500) } function libatomicCheck() { try { require('rocksdb-native') return true } catch { return false } }