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