8 changed files with 281 additions and 8 deletions
@ -0,0 +1,16 @@ |
|||||
|
/* eslint-disable no-var */ |
||||
|
|
||||
|
// Native
|
||||
|
var path = require('path') |
||||
|
var fs = require('fs') |
||||
|
|
||||
|
var dist = path.join(__dirname, 'dist') |
||||
|
var src = path.join(__dirname, 'src') |
||||
|
|
||||
|
// Don't install when developing locally
|
||||
|
if (fs.existsSync(src)) { |
||||
|
// eslint-disable-next-line unicorn/no-process-exit
|
||||
|
process.exit(0) |
||||
|
} |
||||
|
|
||||
|
require(path.join(dist, 'download.js')) |
@ -0,0 +1,10 @@ |
|||||
|
// Native
|
||||
|
import fs from 'fs' |
||||
|
|
||||
|
export default function (file) { |
||||
|
const s = fs.statSync(file) |
||||
|
const newMode = s.mode | 64 | 8 | 1 |
||||
|
if (s.mode === newMode) return |
||||
|
const base8 = newMode.toString(8).slice(-3) |
||||
|
fs.chmodSync(file, base8) |
||||
|
} |
@ -0,0 +1,148 @@ |
|||||
|
/* eslint-disable unicorn/no-process-exit */ |
||||
|
|
||||
|
// Native
|
||||
|
import fs from 'fs' |
||||
|
import path from 'path' |
||||
|
import zlib from 'zlib' |
||||
|
|
||||
|
// Packages
|
||||
|
import onDeath from 'death' |
||||
|
import fetch from 'node-fetch' |
||||
|
import retry from 'async-retry' |
||||
|
|
||||
|
// Utilities
|
||||
|
import plusxSync from './chmod' |
||||
|
import { |
||||
|
disableProgress, |
||||
|
enableProgress, |
||||
|
info, |
||||
|
showProgress, |
||||
|
warn |
||||
|
} from './log' |
||||
|
|
||||
|
fetch.Promise = Promise |
||||
|
global.Promise = Promise |
||||
|
const now = path.join(__dirname, 'now') |
||||
|
const targetWin32 = path.join(__dirname, 'now.exe') |
||||
|
const target = process.platform === 'win32' ? targetWin32 : now |
||||
|
const partial = target + '.partial' |
||||
|
|
||||
|
const packagePath = path.join(__dirname, '../../package.json') |
||||
|
const packageJSON = JSON.parse(fs.readFileSync(packagePath, 'utf8')) |
||||
|
|
||||
|
const platformToName = { |
||||
|
darwin: 'now-macos', |
||||
|
linux: 'now-linux', |
||||
|
win32: 'now-win.exe' |
||||
|
} |
||||
|
|
||||
|
async function main() { |
||||
|
try { |
||||
|
fs.writeFileSync( |
||||
|
now, |
||||
|
'#!/usr/bin/env node\n' + |
||||
|
'console.log("Please wait until the \'now\' installation completes!")\n' |
||||
|
) |
||||
|
} catch (err) { |
||||
|
if (err.code === 'EACCES') { |
||||
|
warn( |
||||
|
'Please try installing now CLI again with the `--unsafe-perm` option.' |
||||
|
) |
||||
|
info('Example: `npm i -g --unsafe-perm now`') |
||||
|
|
||||
|
process.exit() |
||||
|
} |
||||
|
|
||||
|
throw err |
||||
|
} |
||||
|
|
||||
|
onDeath(() => { |
||||
|
fs.writeFileSync( |
||||
|
now, |
||||
|
'#!/usr/bin/env node\n' + |
||||
|
'console.log("The \'now\' installation did not complete successfully.")\n' + |
||||
|
'console.log("Please run \'npm i -g now\' to reinstall!")\n' |
||||
|
) |
||||
|
process.exit() |
||||
|
}) |
||||
|
|
||||
|
info('For the source code, check out: https://github.com/zeit/now-cli') |
||||
|
|
||||
|
// Print an empty line
|
||||
|
console.log('') |
||||
|
|
||||
|
await retry(async () => { |
||||
|
enableProgress('Downloading now CLI ' + packageJSON.version) |
||||
|
showProgress(0) |
||||
|
|
||||
|
try { |
||||
|
const name = platformToName[process.platform] |
||||
|
const url = `https://cdn.zeit.co/releases/now-cli/${packageJSON.version}/${name}` |
||||
|
const resp = await fetch(url, { compress: false }) |
||||
|
|
||||
|
if (resp.status !== 200) { |
||||
|
throw new Error(resp.statusText + ' ' + url) |
||||
|
} |
||||
|
|
||||
|
const size = resp.headers.get('content-length') |
||||
|
const ws = fs.createWriteStream(partial) |
||||
|
|
||||
|
await new Promise((resolve, reject) => { |
||||
|
let bytesRead = 0 |
||||
|
|
||||
|
resp.body |
||||
|
.on('error', reject) |
||||
|
.on('data', chunk => { |
||||
|
bytesRead += chunk.length |
||||
|
showProgress(100 * bytesRead / size) |
||||
|
}) |
||||
|
|
||||
|
const gunzip = zlib.createGunzip() |
||||
|
|
||||
|
gunzip |
||||
|
.on('error', reject) |
||||
|
|
||||
|
resp.body.pipe(gunzip).pipe(ws) |
||||
|
|
||||
|
ws |
||||
|
.on('error', reject) |
||||
|
.on('close', () => { |
||||
|
showProgress(100) |
||||
|
resolve() |
||||
|
}) |
||||
|
}) |
||||
|
} finally { |
||||
|
disableProgress() |
||||
|
} |
||||
|
}, { |
||||
|
retries: 500, |
||||
|
onRetry: (err) => console.error(err) |
||||
|
}) |
||||
|
|
||||
|
fs.renameSync(partial, target) |
||||
|
|
||||
|
if (process.platform === 'win32') { |
||||
|
// Now.exe is executed only
|
||||
|
fs.unlinkSync(now) |
||||
|
// Workaround for https://github.com/npm/cmd-shim/pull/25
|
||||
|
const gitBashFile = path.join(process.env.APPDATA, 'npm/now') |
||||
|
fs.writeFileSync( |
||||
|
gitBashFile, |
||||
|
'#!/bin/sh\n' + |
||||
|
'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")\n' + |
||||
|
'\n' + |
||||
|
'case `uname` in\n' + |
||||
|
' *CYGWIN*) basedir=`cygpath -w "$basedir"`;;\n' + |
||||
|
'esac\n' + |
||||
|
'\n' + |
||||
|
fs.readFileSync(gitBashFile, 'utf8') |
||||
|
) |
||||
|
} else { |
||||
|
plusxSync(now) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
main().catch(err => { |
||||
|
console.error(err) |
||||
|
process.exit(2) |
||||
|
}) |
@ -0,0 +1,43 @@ |
|||||
|
// Packages
|
||||
|
import assert from 'assert' |
||||
|
import chalk from 'chalk' |
||||
|
import Progress from 'progress' |
||||
|
|
||||
|
let bar |
||||
|
|
||||
|
export function enableProgress(text) { |
||||
|
assert(!bar) |
||||
|
|
||||
|
bar = new Progress(`> ${text} [:bar] :percent`, { |
||||
|
stream: process.stdout, |
||||
|
width: 20, |
||||
|
complete: '=', |
||||
|
incomplete: ' ', |
||||
|
total: 100 |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function info(text) { |
||||
|
console.log(`> ${text}`) |
||||
|
} |
||||
|
|
||||
|
export function warn(text) { |
||||
|
console.log(chalk.red('> Warning!'), text) |
||||
|
} |
||||
|
|
||||
|
export function showProgress(percentage) { |
||||
|
assert(bar) |
||||
|
bar.update(percentage / 100) |
||||
|
} |
||||
|
|
||||
|
export function disableProgress() { |
||||
|
assert(bar) |
||||
|
|
||||
|
// It is auto-completed once it updates to 100
|
||||
|
// otherwise it outputs a blank line
|
||||
|
if (!bar.complete) { |
||||
|
bar.terminate() |
||||
|
} |
||||
|
|
||||
|
bar = undefined |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
// Native
|
||||
|
const path = require('path') |
||||
|
|
||||
|
module.exports = { |
||||
|
target: 'node', |
||||
|
node: { |
||||
|
__dirname: false, |
||||
|
__filename: false, |
||||
|
process: false |
||||
|
}, |
||||
|
entry: [ |
||||
|
'./src/index.js' |
||||
|
], |
||||
|
output: { |
||||
|
path: path.join(__dirname, 'dist'), |
||||
|
filename: 'download.js' |
||||
|
}, |
||||
|
module: { |
||||
|
loaders: [ { |
||||
|
test: /.js$/, |
||||
|
loader: 'babel-loader', |
||||
|
exclude: /node_modules/, |
||||
|
query: { |
||||
|
plugins: [ |
||||
|
'transform-async-to-generator', |
||||
|
'transform-runtime' |
||||
|
], |
||||
|
presets: [ |
||||
|
'es2015' |
||||
|
] |
||||
|
} |
||||
|
} ] |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue