168 lines
4.7 KiB
JavaScript
168 lines
4.7 KiB
JavaScript
const { Injectable } = require('flitter-di')
|
|
const moment = require('moment')
|
|
|
|
class UniversalPath extends Injectable {
|
|
static get services() {
|
|
return [...super.services, 'hosts']
|
|
}
|
|
|
|
static PATH_TYPE_FILE = Symbol('file')
|
|
static PATH_TYPE_DIRECTORY = Symbol('directory')
|
|
static PATH_TYPE_UNKNOWN = Symbol('unknown')
|
|
_directory_classify_command = 'test -d'
|
|
_file_classify_command = 'test -f'
|
|
_datetime_format = 'Y-MM-DD_HH-mm-ss-SSSS'
|
|
|
|
static fromString(path_string) {
|
|
const parts = path_string.split('::')
|
|
const hostname = parts.length > 1 ? parts[0] : 'localhost'
|
|
const path = parts.length > 1 ? parts[1] : parts[0]
|
|
const host = this.prototype.hosts.get(hostname)
|
|
return new this(host, path)
|
|
}
|
|
|
|
constructor(host, host_path, type) {
|
|
super()
|
|
this._host = host
|
|
this._path = host_path
|
|
this._type = type ? type : this.constructor.PATH_TYPE_UNKNOWN
|
|
}
|
|
|
|
get host() {
|
|
return this._host
|
|
}
|
|
|
|
get path() {
|
|
return this._path
|
|
}
|
|
|
|
get type() {
|
|
return this._type
|
|
}
|
|
|
|
async resolve() {
|
|
return this._host.resolve_path(this._path)
|
|
}
|
|
|
|
is_directory() {
|
|
return this.type === this.constructor.PATH_TYPE_DIRECTORY
|
|
}
|
|
|
|
is_file() {
|
|
return this.type === this.constructor.PATH_TYPE_FILE
|
|
}
|
|
|
|
is_valid() {
|
|
return this.is_file() || this.is_directory()
|
|
}
|
|
|
|
async classify() {
|
|
const dir_result = await this._host.execute(`${this._directory_classify_command} ${this._path}`)
|
|
if ( dir_result.exit_code === 0 ) {
|
|
this._type = this.constructor.PATH_TYPE_DIRECTORY
|
|
return
|
|
}
|
|
|
|
const file_result = await this._host.execute(`${this._file_classify_command} ${this._path}`)
|
|
if ( file_result.exit_code === 0 ) {
|
|
this._type = this.constructor.PATH_TYPE_FILE
|
|
return
|
|
}
|
|
|
|
this._type = this.constructor.PATH_TYPE_UNKNOWN
|
|
}
|
|
|
|
async open_read_stream() {
|
|
await this.classify()
|
|
if ( this._type === this.constructor.PATH_TYPE_FILE ) {
|
|
return this._host.open_file_read_stream(this._path)
|
|
} else {
|
|
throw new Error('Maestro does not support generation of read streams for this type of path: '+this._type.description)
|
|
}
|
|
}
|
|
|
|
async open_write_stream() {
|
|
await this.classify()
|
|
if (
|
|
[this.constructor.PATH_TYPE_FILE, this.constructor.PATH_TYPE_UNKNOWN].includes(this._type)
|
|
) {
|
|
return this._host.open_file_write_stream(this._path)
|
|
} else {
|
|
throw new Error('Maestro does not support generation of write streams for this type of path: '+this._type.description)
|
|
}
|
|
}
|
|
|
|
async copy_from(other_path) {
|
|
const read = await other_path.open_read_stream()
|
|
const write = await this.open_write_stream()
|
|
await read.pipe(write)
|
|
}
|
|
|
|
async copy_to(other_path) {
|
|
const read = await this.open_read_stream()
|
|
const write = await other_path.open_write_stream()
|
|
await read.pipe(write)
|
|
}
|
|
|
|
async unlink() {
|
|
await this.host.delete_path(this._path)
|
|
}
|
|
|
|
async move_from(other_path) {
|
|
await this.copy_from(other_path)
|
|
await other_path.unlink()
|
|
}
|
|
|
|
async move_to(other_path) {
|
|
await this.copy_to(other_path)
|
|
await this.unlink()
|
|
}
|
|
|
|
async touch(directory = false) {
|
|
await this.classify()
|
|
if ( !directory ) {
|
|
const base_dir = this._path.split('/').slice(0, -1).join('/')
|
|
await this._host.run(`mkdir -p ${base_dir}`)
|
|
await this._host.run(`touch ${this._path}`)
|
|
} else {
|
|
await this._host.run(`mkdir -p ${this._path}`)
|
|
}
|
|
}
|
|
|
|
async echo(text) {
|
|
await this.classify()
|
|
if ( this.is_directory() ) {
|
|
throw new Error('Cannot echo to a directory.')
|
|
}
|
|
|
|
if ( !this.is_valid() ) {
|
|
await this.touch()
|
|
}
|
|
|
|
const ws = await this.open_write_stream()
|
|
ws.write(text)
|
|
return new Promise(resolve => {
|
|
ws.on('finish', () => resolve())
|
|
ws.end()
|
|
})
|
|
}
|
|
|
|
async hash() {
|
|
const line = await this._host.run_line_result(`sha256sum ${this._path}`)
|
|
return line.split(' ')[0]
|
|
}
|
|
|
|
async backup() {
|
|
const now = moment().format(this._datetime_format)
|
|
const backup_path = `${this}.maestro-backup-${now}`
|
|
const backup_target = this.constructor.fromString(backup_path)
|
|
await this.copy_to(backup_target)
|
|
}
|
|
|
|
toString() {
|
|
return `${this._host.name}::${this._path}`
|
|
}
|
|
}
|
|
|
|
module.exports = exports = UniversalPath
|