Tony Kovanen
9 years ago
8 changed files with 331 additions and 204 deletions
@ -0,0 +1,174 @@ |
|||||
|
#!/usr/bin/env node |
||||
|
import Progress from 'progress'; |
||||
|
import copy from '../lib/copy'; |
||||
|
import { resolve } from 'path'; |
||||
|
import login from '../lib/login'; |
||||
|
import * as cfg from '../lib/cfg'; |
||||
|
import { version } from '../../package'; |
||||
|
import Logger from '../lib/build-logger'; |
||||
|
import bytes from 'bytes'; |
||||
|
import chalk from 'chalk'; |
||||
|
import minimist from 'minimist'; |
||||
|
import Now from '../lib'; |
||||
|
import ms from 'ms'; |
||||
|
import { handleError, error } from '../lib/error'; |
||||
|
|
||||
|
const argv = minimist(process.argv.slice(2)); |
||||
|
const help = () => { |
||||
|
console.log(` |
||||
|
𝚫 now [options] <command|path> |
||||
|
|
||||
|
Commands: |
||||
|
|
||||
|
list output list of instances |
||||
|
ls alias of list |
||||
|
|
||||
|
Options: |
||||
|
|
||||
|
-h, --help output usage information |
||||
|
-v, --version output the version number |
||||
|
-d, --debug Debug mode [off] |
||||
|
-f, --force Force a new deployment even if nothing has changed |
||||
|
-L, --login Configure login |
||||
|
-C, --no-clipboard Do not attempt to copy URL to clipboard |
||||
|
`); |
||||
|
}; |
||||
|
|
||||
|
let path = argv._[0]; |
||||
|
|
||||
|
if (path) { |
||||
|
if ('/' !== path[0]) { |
||||
|
path = resolve(process.cwd(), path); |
||||
|
} |
||||
|
} else { |
||||
|
path = process.cwd(); |
||||
|
} |
||||
|
|
||||
|
// options |
||||
|
const debug = argv.debug || argv.d; |
||||
|
const clipboard = !(argv.noClipboard || argv.C); |
||||
|
const force = argv.f || argv.force; |
||||
|
const forceSync = argv.F || argv.forceSync; |
||||
|
const shouldLogin = argv.L || argv.login; |
||||
|
const apiUrl = argv.url || 'https://api.now.sh'; |
||||
|
|
||||
|
const config = cfg.read(); |
||||
|
|
||||
|
if (argv.h || argv.help) { |
||||
|
help(); |
||||
|
process.exit(0); |
||||
|
} else if (argv.v || argv.version) { |
||||
|
console.log(chalk.bold('𝚫 now'), version); |
||||
|
process.exit(0); |
||||
|
} else if (!config.token || shouldLogin) { |
||||
|
login(apiUrl) |
||||
|
.then((token) => { |
||||
|
if (shouldLogin) { |
||||
|
console.log('> Logged in successfully. Token saved in ~/.now.json'); |
||||
|
process.exit(0); |
||||
|
} else { |
||||
|
sync(token).catch((err) => { |
||||
|
error(`Unknown error: ${err.stack}`); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
} |
||||
|
}) |
||||
|
.catch((e) => { |
||||
|
error(`Authentication error – ${e.message}`); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
} else { |
||||
|
sync(config.token).catch((err) => { |
||||
|
error(`Unknown error: ${err.stack}`); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async function sync (token) { |
||||
|
const start = Date.now(); |
||||
|
|
||||
|
console.log(`> Deploying "${path}"`); |
||||
|
|
||||
|
const now = new Now(apiUrl, token, { debug }); |
||||
|
|
||||
|
try { |
||||
|
await now.create(path, { forceNew: force, forceSync: forceSync }); |
||||
|
} catch (err) { |
||||
|
handleError(err); |
||||
|
process.exit(1); |
||||
|
} |
||||
|
|
||||
|
const { url } = now; |
||||
|
const elapsed = ms(new Date() - start); |
||||
|
|
||||
|
if (clipboard) { |
||||
|
try { |
||||
|
await copy(url); |
||||
|
console.log(`${chalk.cyan('> Ready!')} ${chalk.bold(url)} (copied to clipboard) [${elapsed}]`); |
||||
|
} catch (err) { |
||||
|
console.log(`${chalk.cyan('> Ready!')} ${chalk.bold(url)} [${elapsed}]`); |
||||
|
} |
||||
|
} else { |
||||
|
console.log(`> ${url} [${elapsed}]`); |
||||
|
} |
||||
|
|
||||
|
const start_u = new Date(); |
||||
|
const complete = () => { |
||||
|
const elapsed_u = ms(new Date() - start_u); |
||||
|
console.log(`> Sync complete (${bytes(now.syncAmount)}) [${elapsed_u}] `); |
||||
|
|
||||
|
// close http2 agent |
||||
|
now.close(); |
||||
|
|
||||
|
// show build logs |
||||
|
printLogs(now.host); |
||||
|
}; |
||||
|
|
||||
|
if (now.syncAmount) { |
||||
|
const bar = new Progress('> Upload [:bar] :percent :etas', { |
||||
|
width: 20, |
||||
|
complete: '=', |
||||
|
incomplete: '', |
||||
|
total: now.syncAmount |
||||
|
}); |
||||
|
|
||||
|
now.upload(); |
||||
|
|
||||
|
now.on('upload', ({ name, data }) => { |
||||
|
const amount = data.length; |
||||
|
if (debug) { |
||||
|
console.log(`> [debug] Uploaded: ${name} (${bytes(data.length)})`); |
||||
|
} |
||||
|
bar.tick(amount); |
||||
|
}); |
||||
|
|
||||
|
now.on('complete', complete); |
||||
|
|
||||
|
now.on('error', (err) => { |
||||
|
error('Upload failed'); |
||||
|
handleError(err); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
} else { |
||||
|
console.log('> Sync complete (cached)'); |
||||
|
|
||||
|
// close http2 agent |
||||
|
now.close(); |
||||
|
|
||||
|
// show build logs |
||||
|
printLogs(now.host); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function printLogs (host) { |
||||
|
// log build |
||||
|
const logger = new Logger(host); |
||||
|
logger.on('error', () => { |
||||
|
console.log('> Connection error.'); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
logger.on('close', () => { |
||||
|
console.log(`${chalk.cyan('> Deployment complete!')}`); |
||||
|
process.exit(0); |
||||
|
}); |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
#!/usr/bin/env node |
||||
|
|
||||
|
import minimist from 'minimist'; |
||||
|
import chalk from 'chalk'; |
||||
|
import table from 'text-table'; |
||||
|
import ms from 'ms'; |
||||
|
import Now from '../lib'; |
||||
|
import login from '../lib/login'; |
||||
|
import * as cfg from '../lib/cfg'; |
||||
|
import { handleError, error } from '../lib/error'; |
||||
|
|
||||
|
const argv = minimist(process.argv.slice(2)); |
||||
|
const app = argv._[0]; |
||||
|
|
||||
|
// options |
||||
|
const debug = argv.debug || argv.d; |
||||
|
const apiUrl = argv.url || 'https://api.now.sh'; |
||||
|
|
||||
|
const config = cfg.read(); |
||||
|
|
||||
|
Promise.resolve(config.token || login(apiUrl)) |
||||
|
.then(async (token) => { |
||||
|
try { |
||||
|
await list(token); |
||||
|
} catch (err) { |
||||
|
error(`Unknown error: ${err.stack}`); |
||||
|
process.exit(1); |
||||
|
} |
||||
|
}) |
||||
|
.catch((e) => { |
||||
|
error(`Authentication error – ${e.message}`); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
|
||||
|
async function list (token) { |
||||
|
const now = new Now(apiUrl, token, { debug }); |
||||
|
|
||||
|
let deployments; |
||||
|
try { |
||||
|
deployments = await now.list(app); |
||||
|
} catch (err) { |
||||
|
handleError(err); |
||||
|
process.exit(1); |
||||
|
} |
||||
|
|
||||
|
now.close(); |
||||
|
|
||||
|
const apps = new Map(); |
||||
|
for (const dep of deployments) { |
||||
|
const deps = apps.get(dep.name) || []; |
||||
|
apps.set(dep.name, deps.concat(dep)); |
||||
|
} |
||||
|
|
||||
|
const current = Date.now(); |
||||
|
const text = [...apps].map(([name, deps]) => { |
||||
|
const t = table(deps.map(({ uid, url, created }) => { |
||||
|
const time = ms(current - created, { long: true }) + ' ago'; |
||||
|
return [ uid, time, `https://${url}` ]; |
||||
|
}), { align: ['l', 'r', 'l'] }); |
||||
|
return chalk.bold(name) + '\n\n' + indent(t, 2).split('\n').join('\n\n'); |
||||
|
}).join('\n\n'); |
||||
|
|
||||
|
if (text) console.log('\n' + text + '\n'); |
||||
|
} |
||||
|
|
||||
|
function indent (text, n) { |
||||
|
return text.split('\n').map((l) => ' '.repeat(n) + l).join('\n'); |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
import ms from 'ms'; |
||||
|
|
||||
|
export function handleError (err) { |
||||
|
if (403 === err.status) { |
||||
|
error('Authentication error. Run `now -L` or `now --login` to log-in again.'); |
||||
|
} else if (429 === err.status) { |
||||
|
if (null != err.retryAfter) { |
||||
|
error('Rate limit exceeded error. Try again in ' + |
||||
|
ms(err.retryAfter * 1000, { long: true }) + |
||||
|
', or upgrade your account: https://zeit.co/now#pricing'); |
||||
|
} else { |
||||
|
error('Rate limit exceeded error. Please try later.'); |
||||
|
} |
||||
|
} else if (err.userError) { |
||||
|
error(err.message); |
||||
|
} else if (500 === err.status) { |
||||
|
error('Unexpected server error. Please retry.'); |
||||
|
} else { |
||||
|
error(`Unexpected error. Please try later. (${err.message})`); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function error (err) { |
||||
|
console.error(`> \u001b[31mError!\u001b[39m ${err}`); |
||||
|
} |
Loading…
Reference in new issue