114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import { EventEmitter as Emitter } from 'events'
|
|
import path from 'path'
|
|
// import promisify from 'util'
|
|
import { readFile as readConfig } from 'fs-read-data'
|
|
import { exec as child } from 'child_process'
|
|
// import ignoreFiles from './ignore'
|
|
import logger from '@uci/logger'
|
|
let log = {} // declare module wide log to be set during construction
|
|
|
|
class Sync extends Emitter {
|
|
constructor(opts = {}) {
|
|
super()
|
|
log = logger({ name: 'remote-code', file:'src/sync.js', class:'Sync'})
|
|
this.opts = opts
|
|
// this.opts.more = this.opts.more || []
|
|
// this.opts.ssh = this.opts.ssh || []
|
|
this.jobOpts = {}
|
|
}
|
|
|
|
async configure(opts,overwrite) {
|
|
if (typeof opts === 'string') opts = await readConfig(opts) // opts here is path to configuration file
|
|
this.opts = overwrite ? Object.assign(this.opts,opts) : Object.assign(opts, this.opts)
|
|
}
|
|
|
|
addOpt(option,value) {
|
|
this.opts.more = this.opts.more || []
|
|
this.opts.more.push(`${(option.length > 1)?'--':'-'}${option} ${value}`)
|
|
log.info (this.opts.more)
|
|
}
|
|
|
|
addSshOpt(option,value) {
|
|
this.opts.ssh = this.opts.ssh || []
|
|
this.opts.ssh.push(`${(option.length > 1)?'--':'-'}${option} ${value}`)
|
|
log.info (this.opts.ssh)
|
|
}
|
|
|
|
command(src, dest) {
|
|
this.opts.src = src || this.opts.src || process.cwd()
|
|
this.opts.dest = dest || this.opts.dest || `/opt/${process.cwd().match(/([^/]*)\/*$/)[1]}`
|
|
this.cmd=`rsync ${this._opts} ${this._ssh()} ${this.opts.src}/ ${this.opts.dest}`
|
|
// this.cmd = JSON.stringify(this.opts)
|
|
return this.cmd
|
|
}
|
|
|
|
_ssh() {
|
|
if (!(this.opts.username && this.opts.host)) return ''
|
|
this.opts.dest = `${this.opts.username}@${this.opts.host}:${this.opts.dest}`
|
|
if (this.opts.keyFilePath) this.addSshOpt('i',this.opts.keyFilePath)
|
|
if (this.opts.port) this.addSshOpt('p',this.opts.port)
|
|
if (!this.opts.ssh) return ''
|
|
return `-e "ssh ${this.opts.ssh.join(' ')}"`
|
|
}
|
|
|
|
_opts() {
|
|
if (typeof opts.mirror==='boolean' && !opts.mirror)
|
|
|
|
|
|
// if ssh agent is not available in child process can make it so
|
|
_agent(path) {
|
|
// this.jobOpts.env
|
|
}
|
|
|
|
// returns a promise when job is done
|
|
execute(src,dest) {
|
|
const sync = this
|
|
let reply=[]
|
|
let error=[]
|
|
sync.emit('busy')
|
|
return new Promise((resolve, reject) => {
|
|
// may need to be sure that child has agent socket envirnoment variable
|
|
if (this.opts.agent) this._agent(this.opts.agent)
|
|
const job = child(this.command(src,dest), this.jobOpts)
|
|
|
|
job.on('error', (err) => {
|
|
log.fatal({err:err, opts:sync.opts, msg:'failed to spawn rsync job'})
|
|
reject(err)
|
|
})
|
|
|
|
job.on('close', (code) => {
|
|
log.info(`sync job exited with code ${code}`)
|
|
if (error.length!==0) sync.emit('remote:error',error)
|
|
sync.emit('done',{command:sync.cmd, reply:reply})
|
|
resolve({command:sync.cmd,reply:reply,error:error})
|
|
})
|
|
|
|
job.stdout.on('data', (data) => {
|
|
log.info({remote:sync.opts.host, console:data, msg:'console data from remote'})
|
|
reply.push(data)
|
|
})
|
|
|
|
job.stderr.on('data', (data) => {
|
|
log.warn({remote:sync.opts.host, error:data, msg:'error from remote'})
|
|
error.push(data)
|
|
})
|
|
|
|
})
|
|
}
|
|
|
|
}// end Class Sync
|
|
|
|
export default Sync
|
|
|
|
function isPlainObject (obj) {
|
|
return Object.prototype.toString.call(obj) === '[object Object]'
|
|
}
|
|
|
|
function escapeSpaces (str) {
|
|
if (typeof str === 'string') {
|
|
return str.replace(/\b\s/g, '\\ ')
|
|
} else {
|
|
return path
|
|
}
|
|
}
|