Blog

05
February 2015

Gavin Pickin

Using CommandBox CLI to build your own Commands for Lucee

Apache, CFML Language, CFML Server, CommandBox, Lucee, Server Admin, Tools and IDEs

Yesterday I apparently started a series of posts, on CommandBox CLI, and how to write your own commands, in cfml, to make your life easier. I started a set of commands under the kiwiSays namespace, and we built 3 commands / cfcs, called addWebsite, startLucee and stopLucee. We got most of addWebsite built, today lets look at startLucee and stopLucee.

I setup a github repo for the project, as we progress, hopefully its useful to see the code… I’ll make a new branch as we create new blog posts. You can find the repo here.
https://github.com/gpickin/cbcli-command-kiwiSays

Before we get too far into the new commands, lets refactor our first one, so its cleaner.

component extends="commandbox.system.BaseCommand" {
        
    /**
     * @websiteURL.hint The Website URL
     * @websitePath.hint Path to the Website Directory
     */
   
    function run( required string websiteURL, required string websitePath ){
             ARGUMENTS.websitePath = fileSystemUtil.resolvePath( ARGUMENTS.websitePath );
    
             var apacheConf = "";
                apacheConf = apacheConf & '<VirtualHost *:80>#CR#';
                apacheConf = apacheConf & 'ServerAdmin myemail@mydomain.com#CR#';
                apacheConf = apacheConf & 'DocumentRoot "#websitePath#"#CR#';
                apacheConf = apacheConf & 'ServerName #websiteURL##CR#';
                apacheConf = apacheConf & 'Include /www/_servers/conf/inc_lucee_conn.inc#CR#';
                apacheConf = apacheConf & '</VirtualHost>#CR#';

                print.line().line( apacheConf );
                fileWrite( '/www/apacheconfs/#websiteURL#.conf', apacheConf );
                runCommand( "run 'sudo apachectl restart’" );
    }
}

 

Everything is jammed in the run function, and while that works, its not really neat and might get harder to maintain, as we build upon this down the road. Lets break it up some, by including other functions in our cfc. Lets pull out the Apache Conf generation, and put it in a new function, called generateApacheConf.

component extends="commandbox.system.BaseCommand" {
        
    /**
     * @websiteURL.hint The Website URL
     * @websitePath.hint Path to the Website Directory
     */
   
    function run( required string websiteURL, required string websitePath ){
     ARGUMENTS.websitePath = fileSystemUtil.resolvePath( ARGUMENTS.websitePath );
    
     generateApacheConf( ARGUMENTS.websiteURL, ARGUMENTS.websitePath);
        runCommand( "run 'sudo apachectl restart’" );
    }
    function generateApacheConf( required string websiteURL, required string websitePath ){
   
    var apacheConf = "";
apacheConf = apacheConf & '<VirtualHost *:80>#CR#';
apacheConf = apacheConf & 'ServerAdmin myemail@mydomain.com#CR#';
apacheConf = apacheConf & 'DocumentRoot "#websitePath#"#CR#';
apacheConf = apacheConf & 'ServerName #websiteURL##CR#';
apacheConf = apacheConf & 'Include /www/_servers/conf/inc_lucee_conn.inc#CR#';
apacheConf = apacheConf & '</VirtualHost>#CR#';

print.line().line( apacheConf );
fileWrite( '/www/apacheconfs/#websiteURL#.conf', apacheConf );
   
    }
}

 

Now, our run function, is more like a controller… calls out to other functions to manage the dirty work. 
That is how we are going the next commands in this super command. We’re going to call the stopLucee command, and the startLucee command from the addWebsite command.

We could right the code in here, but if we want to call them separately too, it just makes sense to have the code in one place, and share that code. DRY Don’t repeat yourself, right.

If you remember from yesterday, when we wanted to run a command, that ran a command in the native shell, we had to call runCommand( run ‘the command’). Today we’re going to call another commandBox command directly, so we only have to use one level of run. So lets add the following code.

runCommand( "kiwiSays stopLucee");
runCommand( "kiwiSays startLucee");

Now, if we restart commandBox, and run kiwiSays addWebsite, it will:

  • generate the Apache Conf from our function inside of our addWebsite command
  • then run a command that runs a native shell command to restart apache
  • then call kiwiSays stopLucee - which is a hello world
  • then call kiwiSays startLucee - which is a hello world too.

Great… that works, and your addWebsite.cfc file should look like this

component extends="commandbox.system.BaseCommand" {
        
    /**
    * @websiteURL.hint The Website URL
    * @websitePath.hint Path to the Website Directory
    */
    function run( required string websiteURL, required string websitePath ){
            
            ARGUMENTS.websitePath = fileSystemUtil.resolvePath( ARGUMENTS.websitePath );

            generateApacheConf( ARGUMENTS.websiteURL, ARGUMENTS.websitePath);

            runCommand( "run 'sudo apachectl restart’" );
            runCommand( "kiwiSays stopLucee");
            runCommand( "kiwiSays startLucee");
    }
   
    function generateApacheConf( required string websiteURL, required string websitePath ){
   
        var apacheConf = "";
        apacheConf = apacheConf & '<VirtualHost *:80>#CR#';
        apacheConf = apacheConf & 'ServerAdmin myemail@mydomain.com#CR#';
        apacheConf = apacheConf & 'DocumentRoot "#websitePath#"#CR#';
        apacheConf = apacheConf & 'ServerName #websiteURL##CR#';
        apacheConf = apacheConf & 'Include /www/_servers/conf/inc_lucee_conn.inc#CR#';
        apacheConf = apacheConf & '</VirtualHost>#CR#';

        print.line().line( apacheConf );
        fileWrite( '/www/apacheconfs/#websiteURL#.conf', apacheConf );
   
    }
}

 

Lets get our stopLucee and startLucee commands fleshed out. As I said yesterday, the first iteration of these commands will use hardcoded paths etc, which of course, you can change to suit your needs. Later, we will look at other ways of making it more flexible, useable, and distributable… especially across platform. For now, play along.
stopLucee is a simple command. We’re going to use a variable for the location of the path of our lucee install. We’ll print a line to show progress, and identify what we’re doing, i.e. stopping lucee running from this install path, and then, we’ll run the command.

component extends="commandbox.system.BaseCommand" {

     function run() {
          var serverPath = '/www/_servers/lucee';
          print.line('Stopping Lucee - ' & serverPath);
          runCommand( "run '#serverPath#/bin/shutdown.sh'" );
     }
}

 

Not much to it, but thats all we need. 
Lets copy paste and update for a startLucee command.

component extends="commandbox.system.BaseCommand" {

     function run() {
          var serverPath = '/www/_servers/lucee';
          print.line('Starting Lucee - ' & serverPath);
          runCommand( "run '#serverPath#/bin/startup.sh'" );
     }
}

 

Lets restart CommandBox and try it out.

$ kiwiSays addWebsite
Enter websiteURL (The Website URL) :www.gpickin.com
Enter websitePath (Path to the Website Directory) :/www/www.gpickin.com
<VirtualHost *:80>
ServerAdmin myemail@mydomain.com
DocumentRoot "/www/www.gpickin.com"
ServerName www.gpickin.com
Include /www/_servers/conf/inc_lucee_conn.inc
</VirtualHost>
Command completed succesfully!
Stopping Lucee - /www/_servers/lucee
Command completed succesfully!
Starting Lucee - /www/_servers/lucee
Command completed succesfully!

Awesome… now we have a single command, that calls other commands, creates conf files, restarts apache, stops and then starts Lucee, pretty easy.

You might be asking, why are we stopping and restarting Lucee… we haven’t made any changes to server.xml… or my special inc_lucee_hosts.xml file I mentioned in my post titled "Adding Goodies to Server.xml to make life easier with Lucee” http://www.gpickin.com/index.cfm/blog/adding-goodies-to-serverxml-to-make-life-easier-with-lucee well, we have to leave something for the next post, right?

So thanks for reading, hope you check back in for the next post in the series.
Before Files - https://github.com/gpickin/cbcli-command-kiwiSays/tree/Blog-Post-1
After Files - https://github.com/gpickin/cbcli-command-kiwiSays/tree/Blog-Post-2
 

Blog Search