optimizing your daily workflow
Scott Steinbeck
- Software Developer
- 15+ Year of experience
- Father
- Hardware Tinkerer
Hobbies
- Coding on my free time
- Overcommitting myself
- Automating everything
- IOT Development
- Teaching Coding/Electronics
- Contributing to open source
What is CommandBox?
- Is it a CLI ?
- Does it scaffold apps like yeoman?
- Is it a REPL (Read Evauluate Print Loop)
- Can it start servers?
- Is it configurable?
- Is it only for lucee?
- Is it secure?
- Does it look cool?
- Can I build custom plugins?
- Can I add core features?
- Is it only for coldfusion development?
- Is it better than node?
- Is it easy to use?
Installation
brew install commandbox
curl -fsSl https://downloads.ortussolutions.com/debs/gpg | sudo apt-key add -
echo "deb https://downloads.ortussolutions.com/debs/noarch /" | sudo tee -a /etc/apt/sources.list.d/commandbox.list
sudo apt-get update && sudo apt-get install apt-transport-https commandbox
https://www.ortussolutions.com/products/commandbox
Download the binary
CommandBox Commandline Tools
CommandBox REPL
CommandBox> set foo=bar
CommandBox> REPL
CFSCRIPT-REPL: echo( '${foo}' )
bar
CFSCRIPT-REPL: breakfast = ['bacon','eggs']
=> [
"bacon",
"eggs"
]
CFSCRIPT-REPL: breakfast.len()
=> 2
CFSCRIPT-REPL: breakfast.append( 'orange juice' )
=> [
"bacon",
"eggs",
"orange juice"
]
JMES JSON filtering / jq Command
CommandBox> jq [1,2,-3,4,-5,6,-7,-8,9] [?contains('-8',@)]
=> [
-8
]
CommandBox> jq box.json pluck(@,'name') # only show 'name' key
CommandBox> jq box.json omit(@,'name,version') # show all keys except 'name & version' keys
CommandBox> jq box.json keys(@) # list an array of all keys in a struct
CommandBox> jq box.json values(@) # list an array of all values in a struct
CommandBox> jq box.json to_entries(@)
=> [
{
"key":"author",
"value":"Scott Steinbeck"
},
{
"key":"bugs",
"value":""
},
{
"key":"changelog",
"value":""
}...
JMES JSON filtering / jq Command (2)
Commandbox> jq box.json key_contains(@,'on')
=> {
"shortDescription":"",
"instructions":"",
"version":"0.0.0",
"location":"ForgeboxStorage",
"documentation":"",
"contributors":[],
"description":""
}
# filter the server list and then group by the value of the status key
Commandbox> server list --json | jq "group_by([].{name: name, status: status},'status')"
# Can also be written with pipes
# Step 1. filter server list array to just name and status keys
# Step 2. group by @ (each item) where the value of 'status' is the same
Commandbox> server list --json | jq "[].{name: name, status: status} | group_by(@,'status')"
=> {
"running":[
{
"status":"running",
"name":"Server 1"
}
],
"stopped":[
{
"status":"stopped",
"name":"Server 2"
},...
CommandBox Settings
# commandbox CLI settings
config set tabCompleteInline=true #show autocomplete as dropdown
config set preferredBrowser=chrome #set preferred browser
# server defaults (get used if not set in a sites box.json)
config set server.defaults.web.rewrites.enable=true
config set server.defaults.openbrowser=false
config set server.defaults.jvm.heapsize=1024
# commandbox module setting overrides
config set modules.TestModule.mySetting=overridden
config set modules.TestModule.somethingEnabled=false
Server Management
server list
site1 (starting)
https://127.0.0.1:8081
C:\site1
site1 (running)
https://127.0.0.1:8082
C:\site2
site3 (stopped)
https://127.0.0.1:8083
C:\site3
# Running servers
server list --running
# Stop Servers
server stop site1
server stop --all
# Clean up old severs
server prune days=30
Env Var Overrides
# CommandBox CLI config settings
# config set tabCompleteInline=true #show autocomplete as dropdown
env set box_config_tabCompleteInline=true
# CFConfig Settings
# configure admin password for all servers
env set cfconfig_adminPassword myPassword
env set cfconfig_scopeCascading "standard"
env set cfconfig_whitespaceManagement= "smart"
# Server.json settings
env set box_server_profile=production
env set box_server_web_http_port=8080
env set box_server_web_ssl={ "enabled" : true, "port": 443 }
Env Variables override any local settings
perfect for setting docker container settings
Trick for "cd"ing up directories
// current directory
cd . -> ./
// back 1 directory
cd .. -> ../
// back 2 directories
cd ... -> cd ../../
// back 3 directories
cd .... -> cd ../../../
Command Shortcuts
box> !myApp.exe
box> !git pull
box> !dir
Shortcut for Native OS Binaries
box> #now
> {ts '2016-01-19 16:14:23'}
box> #hash mypass
> A029D0DF84EB5549C641E04A9EF389E5
box> #reverse abc
> cba
Shortcut for CFML Functions via REPL
box> #listGetAt www.foo.com 2 . | #ucase | #reverse
> OOF
box> package show name | #lcase
> my package
box> !java -ver | #ucase
> JAVA VERSION "1.8.0_92"
Piping commands
printTable
sql Command
-
select
-
where
-
orderby
- limit
- headerNames
#extensionlist | sql select=id,name >> extentions.json
recipe's
# Recomended CommandBox system modules
install commandbox-bullet-train,commandbox-cfconfig,commandbox-cfformat,commandbox-dotenv,commandbox-update-check,commandbox-fusionreactor,cfdocs,commandbox-githooks,commandbox-migrations,quick-commands,commandbox-cflint,commandbox-bookmarks
# Recommended CommandBox shortcuts
config set command.aliases.git="!git"
config set command.aliases.gulp="!gulp"
config set command.aliases.npm="!npm"
essentials.boxr
David Belanger
box> recipe essentials.boxr
Great for setting up new dev's with all of the tools
Tasks
Automate common jobs
/**
* Description of task
*/
component {
/**
*
*/
function run() {
print.greenLine( 'Complete!' );
}
}
CommandBox> task run task.cfc
Complete!
Simple Job
Task will execute anything in the run method and finish
component{
function greet( string name, boolean verbose ){
print.line( 'Well, hello there #name#!' );
if( verbose ) {
print.line( "You're looking quite well today." );
}
}
}
task run taskFile=fun target=greet :name=Brad :verbose=false
Paramaters
&
Alternate Method Names
Tasks
Available base class methods
// Returns the AsyncManager class
async()
// Convenience method for getting stuff from WireBox
getInstance( name, dsl, initArguments={}, targetObject='' )
// Retuns current exit code
getExitCode()
// Sets exit code to be returned when task completes
setExitCode( required numeric exitCode )
// Returns the current working directory of the shell
getCWD()
// ask the user a question and wait for response
ask( message, string mask='', string defaultResponse='', keepHistory=false, highlight=true, complete=false )
// Wait until the user's next keystroke amd return the char code
waitForKey( message='' )
// Ask the user a question looking for a yes/no response and return a boolean
confirm( required message )
// Intiator for multiselect DSL. (Check "task interactiviy" page in docs)
multiSelect()
// Run another command by name.
runCommand( required command, returnOutput=false )
// Intiator for Command DSL. (Check "running other commands" page in docs)
command( required name )
// Intiator for directory watcher DSL. (Check "Watchers" page in docs)
watch()
// This resolves an absolute or relative path using the rules of the operating system and CLI.
resolvePath( required string path, basePath=shell.pwd() )
// Intiator for PropertyFile DSL (check "property files" page in docs)
propertyFile( propertyFilePath='' )
// Report error in your task. Raises an exception that will not print the stack trace
error( required message, detail='', clearPrintBuffer=false, exitCode=1 )
// Open a file or folder externally in the default editor for the user.
openPath( path )
// Open a URL in the user's browser
openURL( theURL, browser='' )
// Get and Set Environment Variables
setSystemSetting( required string key, string value )
getSystemSetting( required string key, defaultValue )
getSystemProperty( required string key, defaultValue )
getEnv( required string key, defaultValue )
// Call this method periodically in a long-running task to check and see
// if the user has hit Ctrl-C.
checkInterrupted( thisThread=variables.thisThread )
// Loads up Java classes into the class loader that loaded the CLI for immediate use.
classLoad( paths )
Additional Task Features
- Printing Tables
- Threading/Async
- Interactive Shell
- Downloading Files
- Sending Emails
- File/folder watchers
- Sending emails
- Running other tasks
- And Many More....
https://commandbox.ortusbooks.com/task-runners
job.start( 'Starting server' );
job.addLog( 'This is the server name' );
job.addWarnLog( 'Hey, don''t touch that dial' );
job.start( 'Installing CF Engine first' );
job.addLog( 'This was the version used' );
job.addLog( 'Yeah, we''re done' );
job.complete();
job.addLog( 'Aaand, we''re back!.' );
job.addErrorLog( 'I think we''re going to crash' );
job.error( 'Didn''t see that coming' );
Task - Task Manager
component {
this.config = [
{'name': 'Update models', 'file':'weather_models.cfc','timespan': createtimespan(0,0,60,0)},
{'name': 'Setup stations','file':'setup_station.cfc', 'timespan': createtimespan(0,1,0,0)} ];
function run(){
if(!this.config.len())print.greenLine("We have no cron jobs..... goodbye").toConsole(); return;
//setup config vars
for(var cronItem in this.config){ cronItem.lastRun = 0; }
while( true ) {
for(var cronItem in this.config){
var timeElapsedMs = GetTickCount() - cronItem.lastRun;
if(timeElapsedMs > cronItem.millis) {
//run our task
try{
task(cronItem.file).run(); //run the task
} catch (any e) {
print.line(e.Message).toConsole();
print.line(e.Detail).toConsole()
savecontent variable="mailBody" { writeDump(e); };
// Send
mailService.send();
}
cronItem.lastRun = GetTickCount(); //record last run in milliseconds
}
sleep( 10000 ); //just a safety
}
}
}
}
Scaffolding
- Coldbox
- Task
Via Extention
- Quick
- Intergrated
- Preside
- ColdBox module
- Commandbox module
Would you like more features?
CommandBox Modules
Popular Modules (67 Total)
A command for accessing CFML documentation powered - Pete Freitag
CFFormat
A CommandBox module for formatting CFML component files. - John Berquist
Convention approach to adding environment variables to JVM args for CommandBox. - Eric Peterson
A CLI library for importing, exporting, transferring, and otherwise managing CF engine configuration. - Ortus
cfScript.me
A CommandBox command for CFML Tag to Script Conversion. - Pete Freitag
A static code analysis tool for CFML.
Adds support to start your CommandBox servers with FusionReactor - Ortus
Generating API docs from the command line via DocBox
For Development
Popular Modules (67 Total)
commandbox-banner-hack
A CommandBox module for customizing all the text in the CLI startup banner. - Matthew Clemente
A CommandBox module that allows for directory bookmarking. - Adam Euans
A conversion tool for taking table like data and converting it to excel, csv, json, or pdf - Scott Steinbeck
Send messages to Slack from the Commandbox command line.
For Commandbox workflow
Automatic reload on file changes via nodejs browsersync - John Wilson
Create a PDF eBook from any Gitbook data export -
Make a local commandbox site published live for anyone to see - Eric Peterson
This module can check for new versions of the CLI and system modules
Bullet Train (Toot Toot!!)
Git Repo Info
Current Working Directory
CommandBox Version & Time
Custom Bullet Train Car
Creating modules/commands
box install commandbox-command-scaffold
Creating modules/commands
{
"author":"Scott Steinbeck",
"location":"ForgeboxStorage",
"name":"bookmarks Command",
"private":false,
"slug":"commandbox-bookmarks-command",
"type":"commandbox-modules",
"version":"0.0.0"
}
box.json
Scaffolding
/**
* This is a description of what
* this command does!
*
* {code:bash}
* bookmarks param1
* {code}
**/
component {
/**
* @param1.hint Description of
* the first parameter
*/
function run( required String param1 ){
return 'Hello ' & param1 & '!';
}
}
CommandBox Module Hooks
(interception Points)
component {
function configure(){
settings = {}; // settings specific to the module
interceptors = []; //interception points within the module
}
function onCLIStart( interceptData ) {} // when commandbox starts
function onCLIExit() {} // when commandbox exits
function onBulletTrain( interceptData ) { // when bullet train starts
var print = wirebox.getInstance( 'print' );
interceptData.cars.myBulletTrainCar.text = print.whiteOnRed(' This sure is easy! ');
interceptData.cars.myBulletTrainCar.background = 'red';
}
function preCommandParamProcess( interceptData ) {} // prior to the time the system settings are expanded
function preCommand( interceptData ) {} // before the execution of a command
function postCommand( interceptData ) {} // after command execution is complete
function prePrompt( interceptData ) {} // before drawing the prompt in the interactive shell
function preProcessLine( interceptData ) {} // fire before and after each command
function postProcessLine( interceptData ) {} // after the entire line has been executed.
}
CommandBox
Local Server Development
Mulit Engine Support
# Start the default engine
CommandBox> start
# Start the latest stable Railo engine
CommandBox> start cfengine=railo
# Start a specific engine and version
CommandBox> start cfengine=adobe@10.0.12
# Start the most recent Adobe server that starts with version "11"
CommandBox> start cfengine=adobe@11
# Start the most recent adobe engine that matches the range
CommandBox> start cfengine="adobe@>9.0 <=11"
# Start the most recent adobe engine that matches the range
CommandBox> start cfengine=lucee@5.3 javaVersion=11
CFConfig
Export your coldfusion config settings to a JSON file
CommandBox> install commandbox-cfconfig
cfconfig export myConfig.json
cfconfig import myConfig.json
#automatically export after when the server is stopped
config set modules.commandbox-cfconfig.exportOnStop=true
Manage CF Mappings
Manage Datasources
Manage Mail Servers
Manage Lucee Caches
cfconfig datasource save name=myDSN dbdriver=mysql host=localhost port=3306 database=myDB username=brad password=foobar
cfconfig datasource save name=myDS ... to=serverName
cfconfig datasource save name=myDS ... to=/path/to/server/home
Manage Custom Tag Paths
Manage Event Gateway Configurations
Manage Lucee Loggers
Manage Scheduled Tasks
Dot Env (Enviroment Variables)
Simple way to store variables that can be used in tons of places throughout commandbox & coldbox
# ColdBox Name and Environment
APPNAME=crazy horse
ENVIRONMENT=development
MYSUPERSECRETPASSWORD=bacon
located in .env file in the root of the project (or in ~./box.env globally)
- often times contains secrets
Can be used to configure
- commandbox config
- box.json
- server.json
- cfconfig
- coldbox config
Debugging
Start a server, follow the logs
server log --follow
# You can also look at your server's access log (if enabled) and rewrite log (if enabled).
server log --follow -access
server log --follow --rewrite
Start server in console mode
# SMALL
start --console
# MEDIUM DEBUGGING
start --console --debug
# X-LARGE DEBUGGING
# You may still really be having issues getting your server to start up correctly due to a setting not getting picked up, rewrites not working, or maybe a jar not loading.
start --console --trace
CommandBox
Production Server
HTTPS Redirect/HSTS
{
"web": {
"ssl" : {
"enable" : true,
"port" : 443,
"HSTS" : {
"enable" : true,
"maxAge" : 31536000,
"includeSubDomains" : true
}
}
}
}
server.json
HTTP Strict Transport Security (HSTS)
This instructs the browser to automatically use HTTPS
Server Security Profiles
-
Production - Locked down for production hosting
-
Development - Lax security for local development
-
None - For backwards compat and custom setups. Doesn't apply any web server rules
Default Profile
- If there is an env var called environment, it is used to set the default profile
-
If the site is bound on localhost, default the profile to "development". Localhost is defined as any IP address starting with 127.(be careful for reverse proxy)
-
If neither of the above are true, the default profile is "production". This makes CommandBox servers secure by default.
Server Security Profiles
Profile | Production | Development |
---|---|---|
directoryListing | false | true |
blockCFAdmin | external | false |
blockSensitivePaths | true | true |
blockFlashRemoting | true | true |
Server.json overrides
{
"profile": "production",
"web": {
"blockCFAdmin": false
}
}
Server Rules
{
"web" : {
"rules" : [
"path-suffix(/box.json) -> set-error(404)",
"path-suffix(hidden.js) -> set-error(404)",
"path-prefix(/admin/) -> ip-access-control(192.168.0.* allow)",
"path(/sitemap.xml) -> rewrite(/sitemap.cfm)",
"disallowed-methods(trace)"
],
"rulesFile" : "..." //or rules file
}
}
-
Security - Block paths, IPs, or users
-
URL rewrites - Rewrite incoming URLs to something different
-
Modifying HTTP requests on the fly - Set headers, cookies, or response codes
The magic behind Server Profiles
Server Service
[Unit]
Description=mySite Service
[Service]
ExecStart=/usr/bin/box server start /var/www/mySiteAPI/server.json
Type=forking
[Install]
WantedBy=multi-user.target
Starting your site on boot
mySite.service
# place in startup directory
Filepath: /usr/lib/systemd/system/mySite.service
#start the service
systemctl start mySite.service
#stop the service
systemctl stop mySite.service
#check service status
systemctl status mySite.service
CommandBox optimizing your daily workflow
By uniquetrio2000
CommandBox optimizing your daily workflow
- 596