Skip to content

Commit

Permalink
Create a bundle using pkg on the fly
Browse files Browse the repository at this point in the history
  • Loading branch information
leo committed Aug 15, 2017
1 parent 35e7b99 commit 7e37d88
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 8 deletions.
16 changes: 16 additions & 0 deletions download/install.js
@@ -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'))
10 changes: 10 additions & 0 deletions download/src/chmod.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)
}
148 changes: 148 additions & 0 deletions download/src/index.js
@@ -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)
})
43 changes: 43 additions & 0 deletions download/src/log.js
@@ -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
}
34 changes: 34 additions & 0 deletions download/webpack.config.js
@@ -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'
]
}
} ]
}
}
30 changes: 24 additions & 6 deletions package.json
Expand Up @@ -5,9 +5,12 @@
"scripts": {
"test": "eslint .",
"prepublish": "webpack",
"lint:staged": "lint-staged",
"dev": "webpack -w",
"precommit": "lint-staged"
"precommit": "lint-staged",
"postinstall": "node download/install.js",
"prepublish": "in-install || (npm run prepare && cp /dev/null download/dist/now)",
"pack": "pkg dist/now.js -c package.json -o packed/now",
"prepare": "webpack --context download --config download/webpack.config.js"
},
"lint-staged": {
"*.js": [
Expand All @@ -16,15 +19,28 @@
"git add"
]
},
"main": "./dist/now.js",
"bin": {
"now": "download/dist/now"
},
"files": [
"dist"
"download/dist",
"download/install.js"
],
"bin": {
"now": "./dist/now.js"
"pkg": {
"scripts": [
"bin/*",
"lib/**/*"
],
"targets": [
"node7-alpine-x64",
"node7-linux-x64",
"node7-macos-x64",
"node7-win-x64"
]
},
"eslintIgnore": [
"src/providers/sh/legacy/**",
"download/**",
"dist"
],
"eslintConfig": {
Expand Down Expand Up @@ -63,6 +79,7 @@
"ansi-escapes": "2.0.0",
"archiver": "2.0.0",
"array-unique": "0.3.2",
"assert": "1.4.1",
"async-retry": "1.1.3",
"aws-sdk": "2.98.0",
"babel-core": "6.25.0",
Expand All @@ -76,6 +93,7 @@
"chalk": "2.1.0",
"clipboardy": "1.1.4",
"convert-stream": "1.0.2",
"death": "1.1.0",
"debug": "3.0.0",
"deployment-type": "1.0.1",
"docker-file-parser": "1.0.2",
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Expand Up @@ -13,7 +13,7 @@ module.exports = {
loaders: [
{
test: /\.js$/,
exclude: [/node_modules/],
exclude: /node_modules/,
loaders: ['shebang-loader', 'babel-loader']
}
]
Expand Down
6 changes: 5 additions & 1 deletion yarn.lock
Expand Up @@ -205,7 +205,7 @@ assert-plus@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"

assert@^1.1.1:
assert@1.4.1, assert@^1.1.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
dependencies:
Expand Down Expand Up @@ -1253,6 +1253,10 @@ date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"

death@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318"

debug@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.0.0.tgz#1d2feae53349047b08b264ec41906ba17a8516e4"
Expand Down

0 comments on commit 7e37d88

Please sign in to comment.