Skip to content
This repository has been archived by the owner on Jul 28, 2021. It is now read-only.

Commit

Permalink
feat(cmd): big refactor on cmd and opts stuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
zkat committed Nov 3, 2018
1 parent 215905c commit 0cf251f
Show file tree
Hide file tree
Showing 10 changed files with 792 additions and 135 deletions.
57 changes: 45 additions & 12 deletions bin/tink.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,52 @@

require('../lib/node/index.js')

const MainOpts = require('figgy-pudding')(require('../lib/common-opts.js'))
const CMDS = new Map([
['sh', require('../lib/commands/shell.js')],
['shell', require('../lib/commands/shell.js')],
['prep', require('../lib/commands/prepare.js')],
['prepare', require('../lib/commands/prepare.js')],
['ping', require('../lib/commands/ping.js')]
])

if (require.main === module) {
main()
main(process.argv)
}

module.exports = main
function main () {
require('npmlog').heading = 'tink'
return require('yargs')
.commandDir('../lib/commands')
.demandCommand(1, 'Subcommand is required')
.recommendCommands()
.help()
.alias('help', 'h')
.alias('version', 'v')
.completion()
.argv
function main (argv) {
const log = require('npmlog')
const npmConfig = require('../lib/config.js')
log.heading = 'tink'
if (needsYargs(argv)) {
console.error('using yargs...', argv)
let config = require('yargs')
.demandCommand(1, 'Subcommand is required')
.recommendCommands()
.help()
.alias('help', 'h')
.alias('version', 'v')
.completion()
for (const mod of CMDS.values()) {
config = config.command(mod)
}
const yargv = npmConfig(config.argv).concat({ log })
log.level = yargv.loglevel || 'notice'
} else {
// This is an optimization because Yargs can be expensive to load.
const opts = npmConfig({ log, _: argv.slice(2) })
log.level = opts.loglevel
return noYargsShortcut(argv[2], opts)
}
}

function needsYargs (argv) {
return argv.length > 3 && (
argv[3] !== '--' && argv[3].match(/^--?[a-z0-9]+/i)
)
}

function noYargsShortcut (cmd, opts) {
return CMDS.get(cmd).handler(opts)
}
25 changes: 15 additions & 10 deletions lib/commands/ping.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
'use strict'

module.exports = {
const Ping = module.exports = {
command: 'ping',
describe: 'ping registry',
builder (y) {
return y.help().alias('help', 'h')
.options(Object.assign(require('../common-opts.js'), module.exports.options()))
.options(Ping.options)
},
options () { return {} },
// lazy-load subcommands
handler: ping
options: Object.assign(require('../common-opts.js', {})),
handler: async argv => ping(argv)
}

function ping (argv) {
Expand All @@ -20,27 +19,33 @@ function ping (argv) {

const PingConfig = figgyPudding({
json: {},
log: { default: () => log },
loglevel: { default: 'notice' },
registry: {},
silent: {}
})

const opts = PingConfig(npmConfig().concat(argv))
const opts = PingConfig(npmConfig().concat(argv).concat({ log }))

log.notice('PING', opts.registry)
if (opts.loglevel !== 'silent' && !opts.json) {
process.stdout.write(`PING ${opts.registry}`)
}
const start = Date.now()
return libnpm.fetch.json('/-/ping?write=true', opts).catch(() => ({})).then(details => {
if (opts.loglevel === 'silent') {
} else {
const time = Date.now() - start
log.notice('PONG', `${time / 1000}ms`)
if (opts.json) {
console.log(JSON.stringify({
registry: opts.registry,
time,
details
}, null, 2))
} else if (Object.keys(details).length) {
log.notice('PONG', `${JSON.stringify(details, null, 2)}`)
} else {
process.stdout.write(` => PONG ${time / 1000}ms\n`)
if (Object.keys(details).length) {
console.log(JSON.stringify(details, null, 2))
}
}
}
})
Expand Down
48 changes: 26 additions & 22 deletions lib/commands/prepare.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
'use strict'

module.exports = {
const Prepare = module.exports = {
command: 'prepare',
aliases: ['prep'],
describe: 'pre-fetch all dependencies',
builder (y) {
return y.help().alias('help', 'h')
.options(Object.assign(require('../common-opts.js'), module.exports.options()))
return y.help().alias('help', 'h').options(Prepare.options)
},
options () {
return {
force: {
alias: 'f',
describe: 'Unconditionally prepare dependencies.',
type: 'boolean'
}
options: Object.assign(require('../common-opts.js'), {
force: {
alias: 'f',
describe: 'Unconditionally prepare dependencies.',
type: 'boolean'
}
},
handler: prepare
}),
handler: async argv => prepare(argv)
}

function prepare (argv) {
const cp = require('child_process')
async function prepare (argv) {
const figgyPudding = require('figgy-pudding')
const fs = require('graceful-fs')
const log = require('npmlog')
const path = require('path')

log.level = argv.loglevel
let pkgMap = checkPkgMap()
const opts = figgyPudding(Prepare.options)(argv)

log.level = opts.loglevel
let pkgMap = await checkPkgMap()
if (!pkgMap || argv.force) {
log.notice('regenerating pkgmap')
cp.spawnSync(process.argv[0], [
require.resolve('../worker.js'), ...process.argv.slice(2)
], {
stdio: 'inherit'
})
const installer = require('../installer.js')
try {
await installer({
log (level, ...args) {
return log[level](...args)
}
})
} catch (e) {
log.error('installer', e)
}
}
return pkgMap

function checkPkgMap () {
try {
Expand Down
73 changes: 49 additions & 24 deletions lib/commands/shell.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,73 @@
'use strict'

module.exports = {
const Shell = module.exports = {
command: 'shell',
aliases: ['sh'],
describe: 'Launch a tink shell or execute a script',
builder (yargs) {
return yargs.help().alias('help', 'h').options({
'ignore-scripts': {},
'node-arg': {
alias: ['n', 'nodeArg'],
describe: 'Arguments to pass down directly to node',
type: 'array'
},
prefix: {
describe: 'Directory to execute package management operations in.',
type: 'string'
},
'restore-missing': {
default: true,
type: 'boolean'
}
})
return yargs.help().alias('help', 'h').options(Shell.options)
},
options: Object.assign(require('../common-opts'), {
_: { default: [] },
'ignore-scripts': {},
nodeArg: {
alias: ['n', 'node-arg'],
describe: 'Arguments to pass down directly to node',
type: 'array'
},
prefix: {
alias: 'C',
describe: 'Directory to execute package management operations in.',
type: 'string'
},
restore: {
alias: 'restore-missing',
default: true,
type: 'boolean'
},
also: {
hidden: true
},
dev: {
hidden: true
},
development: {
hidden: true
},
only: {
hidden: true
},
production: {
type: 'boolean',
describe: 'Limit downloads to production dependencies, skipping devDependencies.'
}
}),
// lazy-load subcommands
handler: shell
handler: async argv => shell(argv)
}

function shell (argv) {
async function shell (argv) {
const cp = require('child_process')
const figgyPudding = require('figgy-pudding')
const path = require('path')
const prepare = require('./prepare.js')

prepare.handler(argv)
if (argv.nodeArg && argv.nodeArg.length) {
const opts = figgyPudding(Shell.options)(argv)

await prepare.handler(argv)
if (opts.nodeArg && opts.nodeArg.length) {
cp.spawnSync(
process.argv[0],
['-r', require.resolve('../node'), ...(argv.nodeArg || []), ...(argv.script ? [argv.script, ...(argv.arguments || [])] : [])],
['-r', require.resolve('../node/index.js'), ...(opts.nodeArg || []), ...(argv.script ? [argv.script, ...(argv.arguments || [])] : [])],
{ stdio: 'inherit' }
)
} else if (argv._.length > 1) {
const Module = require('module')
require('clear-module').all()
require('clear-module').match(/yargs/)
process.argv = [
process.argv[0],
...argv._.slice(1)
path.resolve(argv._[1]),
...argv._.slice(2)
]
Module.runMain()
} else {
Expand Down
30 changes: 18 additions & 12 deletions lib/common-opts.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,37 @@ const path = require('path')
module.exports = {
cache: {
default: path.join(os.homedir(), '.tink'),
describe: 'Path to the global tink cache',
hidden: true
describe: 'Path to the global tink cache'
},
json: {
default: false,
describe: 'Output in JSON format.',
choices: [false, true],
hidden: true
type: 'boolean'
},
loglevel: {
default: 'warn',
default: 'notice',
alias: ['log', 'l'],
describe: 'Logger output level.',
choices: ['silent', 'error', 'warn', 'http', 'verbose', 'info', 'notice', 'silly'],
hidden: true
choices: ['silent', 'error', 'warn', 'http', 'verbose', 'info', 'notice', 'silly']
},
registry: {
alias: 'r',
default: 'https://registry.npmjs.org',
describe: 'Registry to ping',
hidden: true
describe: 'Registry to ping'
},
userconfig: {
default: path.join(os.homedir(), '.npmrc'),
describe: 'Path to user config file.',
hidden: true
}
describe: 'Path to user config file.'
},
force: {
type: 'boolean',
describe: 'Force an action (use with care). This should be defined per-command.'
},
log: {},
prefix: {},
then: {}
}

Object.keys(module.exports).forEach(k => {
module.exports[k].hidden = true
})
22 changes: 2 additions & 20 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,9 @@
const fs = require('fs')
const figgyPudding = require('figgy-pudding')
const ini = require('ini')
const os = require('os')
const path = require('path')

const tinkConfig = module.exports = figgyPudding({
also: {},
cache: { default: path.join(os.homedir(), '.npm') },
dev: {},
development: {},
force: {},
global: {},
'ignore-scripts': {},
log: {},
loglevel: { default: 'warn' },
only: {},
prefix: {},
production: {},
restore: {},
then: {}, // omfg
umask: {},
userconfig: { default: path.join(os.homedir(), '.npmrc') }
})
const tinkConfig = figgyPudding(require('./common-opts.js'))

module.exports = getNpmConfig
module.exports.pudding = tinkConfig
Expand All @@ -38,7 +20,7 @@ function getNpmConfig (_opts) {
path: '',
configs: []
}).configs.concat(
maybeReadIni(opts.userconfig || path.join(os.homedir(), '.npmrc'))
maybeReadIni(opts.userconfig)
).filter(x => x)
const env = Object.keys(process.env).reduce((acc, key) => {
if (key.match(/^(?:npm|tink)_config_/i)) {
Expand Down
3 changes: 1 addition & 2 deletions lib/installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,7 @@ class Installer {
name: pkg.name,
pkgId: pkg.name + '@' + pkg.version,
prefix: this.prefix,
prefixes: [this.prefix],
umask: this.opts.umask
prefixes: [this.prefix]
})
await this.runScript('install', pkg, depPath)
await this.runScript('postinstall', pkg, depPath)
Expand Down
2 changes: 1 addition & 1 deletion lib/pkgmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ if (require.main === module && process.argv[2] === 'ensure-pkg') {
cache,
integrity,
log: require('npmlog'),
restore: true
'restore-missing': true
})
opts.log.level = opts.loglevel
opts.log.warn('fs', 'restoring broken or missing file from package', `${pkg.name}@${pkg.version}`)
Expand Down
Loading

0 comments on commit 0cf251f

Please sign in to comment.