UNPKG

2.08 kBJavaScriptView Raw
1'use strict'
2
3const co = require('co')
4const bastion = require('./bastion')
5const debug = require('./debug')
6
7function handlePsqlError (reject, psql) {
8 psql.on('error', (err) => {
9 if (err.code === 'ENOENT') {
10 reject(`The local psql command could not be located. For help installing psql, see https://devcenter.heroku.com/articles/heroku-postgresql#local-setup`)
11 } else {
12 reject(err)
13 }
14 })
15}
16
17function execPsql (query, dbEnv) {
18 const {spawn} = require('child_process')
19 return new Promise((resolve, reject) => {
20 let result = ''
21 debug('Running query: %s', query.trim())
22 let psql = spawn('psql', ['-c', query], {env: dbEnv, encoding: 'utf8', stdio: [ 'ignore', 'pipe', 'inherit' ]})
23 psql.stdout.on('data', function (data) {
24 result += data.toString()
25 })
26 psql.on('close', function (code) {
27 resolve(result)
28 })
29 handlePsqlError(reject, psql)
30 })
31}
32
33function psqlInteractive (dbEnv, prompt) {
34 const {spawn} = require('child_process')
35 return new Promise((resolve, reject) => {
36 let psql = spawn('psql',
37 ['--set', `PROMPT1=${prompt}`, '--set', `PROMPT2=${prompt}`],
38 {env: dbEnv, stdio: 'inherit'})
39 handlePsqlError(reject, psql)
40 psql.on('close', (data) => {
41 resolve()
42 })
43 })
44}
45
46function handleSignals () {
47 process.removeAllListeners('SIGINT')
48 process.on('SIGINT', () => {})
49}
50
51function * exec (db, query) {
52 handleSignals()
53 let configs = bastion.getConfigs(db)
54
55 yield bastion.sshTunnel(db, configs.dbTunnelConfig)
56 return yield execPsql(query, configs.dbEnv)
57}
58
59function * interactive (db) {
60 const pgUtil = require('./util')
61 let name = pgUtil.getUrl(db.attachment.config_vars).replace(/^HEROKU_POSTGRESQL_/, '').replace(/_URL$/, '')
62 let prompt = `${db.attachment.app.name}::${name}%R%# `
63 handleSignals()
64 let configs = bastion.getConfigs(db)
65
66 yield bastion.sshTunnel(db, configs.dbTunnelConfig)
67 return yield psqlInteractive(configs.dbEnv, prompt)
68}
69
70module.exports = {
71 exec: co.wrap(exec),
72 interactive: co.wrap(interactive)
73}