/**
* @module flitter-cli/CliUnit
*/
const ShellDirective = require('./directives/ShellDirective')
const TemplateDirective = require('./directives/TemplateDirective')
const TestDirective = require('./directives/TestDirective')
const DeployDirective = require('./directives/DeployDirective')
const UsageDirective = require('./directives/UsageDirective')
const Unit = require('libflitter/Unit')
/**
* Unit that provides the functionality associated with flitter-cli.
* @extends module:libflitter/Unit~Unit
*/
class CliUnit extends Unit {
/**
* Defines the services required by this unit.
* @returns {Array<string>}
*/
static get services() {
return [...super.services, 'output', 'canon', 'app']
}
/**
* Gets the name of the service provided by this unit: 'cli'
* @returns {string} - 'cli'
*/
static get name() {
return 'cli'
}
/**
* Loads the module. If any registered unit has deployments/templates/directives, register them with flitter-cli.
* Register the help messages to be used by ./flitter help. Then, bind them all to the context.
* @param {module:libflitter/app/FlitterApp~FlitterApp} app - the Flitter app
* @param {module:libflitter/Context~Context} context - the Unit's context
* @returns {Promise<void>}
*/
async go(app){
this.app = app
let directives = this.directives()
let templates = {}
let deployments = {}
const services = app.di().container.proxy()
for ( const unit_name of app.__unit_array ) {
const unit = services[unit_name]
// Load the unit's directives
if ( typeof unit.directives === 'function' ) {
const base_directives = unit.directives()
const unit_directives = {}
for ( const name in base_directives ) {
const D = base_directives[name]
this.app.di().inject(D)
unit_directives[name] = D
}
directives = {...directives, ...unit_directives}
}
// Load the unit's templates
if ( typeof unit.templates === 'function' ) {
templates = {...templates, ...unit.templates()}
}
// Load the unit's deployments
if ( typeof unit.deploy === 'function' ) {
const deploy_name = unit.name()
deployments[deploy_name] = unit.deploy.bind(unit)
}
}
let usage = {}
for ( let directive_name in directives ){
const directive = directives[directive_name]
if ( directive.help() !== null ){
usage[directive.name()] = directive.help()
}
}
this.loaded_deployments = deployments
this.loaded_templates = templates
this.loaded_directives = directives
this.usage = usage
this._is_cli_invoked = this.app.di().has('CliApp')
}
is_cli() {
return this._is_cli_invoked
}
/**
* Get the name of the unit.
* @returns {string} "cli"
*/
name(){
return "cli"
}
/**
* Get the directive classes provided by this unit. Should be key-value pairs such that the key is the name of
* the class, and the value is an instance of {@link module:flitter-cli/Directive~Directive}.
* @returns {Object}
*/
directives(){
return {
ShellDirective,
TemplateDirective,
TestDirective,
DeployDirective,
UsageDirective
}
}
/**
* Invoke a command, programmatically. Replaces console.log with a pseudo function that collects messages.
* @param {string} directive - the directive to be called
* @param {Array<string>} argv - array of command line arguments
* @returns {Promise<Array>} - array of items that were sent to console.log during the command's execution
*/
async invoke(directive, argv = []){
const CliAppUnit = require('./CliAppUnit')
const cli = this.app.di().make(CliAppUnit)
// create a fake console.log to collect messages
const old_log = console.log
function pseudo_log(message){
this.push(message)
}
console.flitter_cli_messages = []
console.log = pseudo_log.bind(console.flitter_cli_messages)
// format argv
let args = [directive].concat(argv)
// run the CLI
await cli.go(this.app, args)
// cleanup the changes we made
const msg = console.flitter_cli_messages
delete console.flitter_cli_messages
console.log = old_log
return msg
}
}
module.exports = exports = CliUnit