Command-line interfaces (CLIs) are an often overlooked, but extremely important part of every developers workflow. Think about how different your day-to-day life would be if git functioned differently? Or (gasp) incorrectly or inconsistently? At Nodejitsu, we know CLI applications. The CLI for our public platform jitsu is designed to be quick to get started, highly portable and above all: consistent and robust. With these principals in mind we took extra care designing Flatiron to be adaptable to our production-quality needs.
Flatiron is an adaptable decoupled framework for both node.js and the browser. An adaptable framework enables users to build multiple types of applications. In Flatiron we are focusing on:
- Web applications (http and websockets)
- Command line (CLI) applications
- Front-end applications
This article will focus on the tools at your disposal when using Flatiron to build CLI applications as well as how many existing Flatiron CLI applications are structured.
- Getting started
- To the code!
- Configuring your Command-line Application
- Composable Command-line applications
- Flatiron Command-line apps in the wild
Getting started
Writing a Command-line application with Flatiron starts out like writing every other flatiron application:
$ flatiron create simple-app cli info: Creating application simple-app info: Using cli scaffold. info: Creating directory config info: Creating directory lib info: Creating directory commands info: Creating directory test info: Writing package.json info: Writing app.js info: Writing lib/index.js info: Application simple-app is now ready
Lets examine the directory structure created by running flatiron create simple-app cli:
simple-app/
app.js
config/
lib/
index.js
commands/
package.json
test/
With this simple scaffold the application has already been setup with:
- Commands lazy-loaded from the file or directory specified by
options.source. app.cmd: Helper function for creating CLI routes.app.argv: Parsed CLI arguments usingoptimist.app.config: Hierarchical configuration sourced from: environment variables, CLI arguments and a JSON file in that order.app.log: Multi-transport logging usingwinston.app.alias: Helper function to alias shallow commands (e.g.app config listtoapp conf).app.inspect: Robust object inspection and formatting usingcliff.app.prompt: CLI prompt using the Flatironpromptmodule.
There are other options which make writing CLI applications quick and easy. Leave the tough stuff to us.
To the code!
Lets examine each line of the code generated by flatiron create simple-app cli:
var flatiron = require('flatiron'),
path = require('path'),
app = flatiron.app;
app.config.file({ file: path.join(__dirname, 'config', 'config.json') });
app.use(flatiron.plugins.cli, {
source: path.join(__dirname, 'lib', 'commands'),
usage: 'Empty Flatiron Application, please fill out commands'
});
app.start();
Setup up Configuration
app.config.file({ file: path.join(__dirname, 'config', 'config.json') });
Add a store to back the configuration for this application. It will automatically load :pwd/config/config.json from disk.
Attach the CLI plugin
app.use(flatiron.plugins.cli, {
source: path.join(__dirname, 'lib', 'commands'),
usage: 'Empty Flatiron Application, please fill out commands'
});
Attach Command-line functionality to the application. See Configuring your Command-line Application for more detailed documentation.
Start the Application
app.start();
Initializes the application and then dispatches to the director router using app.argv._. For example when running app config get foo, app.argv._ will be ['app', 'config', 'get', 'foo'].
Configuring your Command-line Application
There is a simple convention for passing options to both flatiron.plugins.cli and flatiron.plugins.http: the settings for the named property added to the application has the same name in the options passed to .use(). For example:
//
// Configuring app.argv
//
app.use(flatiron.plugins.cli, {
//
// Settings used by `require('optimist').options()
//
argv: {
login: {
alias: 'l',
description: 'Login to use',
string: true
}
}
});
//
// `app.argv.l` is now available
//
console.log(app.argv.l);There are some important settings you need to be aware of:
source {string}: File or directory on disk to lazy load commands from. In the case of a directory, the names of the files map to the first parameter inapp.argv._.usage {string|Array}: Help text to display when usingapp helpargv {Object}: Settings for CLI options parsing.prompt {Object}: Settings for Flatironpromptmodule.version: {boolean}: Automatically sets up response forapp --versionandapp -vasync: {boolean}: Iftrueconfigures the CLI router attached to the application to be asynchronous. See thedirectordocumentation for more information.
Composable Command-line applications
Flatiron enables developing adaptable applications through a lightweight dependency injection system called broadway. Writing broadway plugins is easy and can be used to easily compose applications out of reusable components. This was the motivation behind a new CLI-plugin for Flatiron released today: flatiron-cli-config. This plugin extends the application by adding handlers for app config *. It also adds help for all of these commands available through app help config *:
app config list: Lists all key-value pairs known to the application.app config get <key>: Displays the value forto the user. app config set <key> <value>: Sets theto the specified value. app config delete <key>: Clears the value for the specified.
Using this plugin is simple:
app.use(require('flatiron-cli-config'));
That's it. Your application is now fully setup to use edit configuration files from the command-line.
Flatiron Command-line applications in the wild
Since we released Flatiron there have been a number of interesting applications released and refactored:
- issues: Github Issues from the CLI
- box: Powerful key -> value storage for the CLI.
- todo: Todos in the CLI like what.
- npmcount: Silly program that counts number of npm packages from one or more users.
- jitsu: Flawless command line deployment of your Node.js apps to the cloud.
Well that about wraps it up. Can't wait to see what crazy things I'll be able to do from the CLI soon!