From 06c6b9d8c669d1267525a1eeac01c40f9e399cc5 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 9 Mar 2017 23:47:58 -0600 Subject: [PATCH 001/123] Bump for 3.7.0-snapshot --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 8b4d7391a..0c8cb7e6d 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From b6827669487fba1562c98845093c8aa8c924fa93 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 10 Mar 2017 01:52:22 -0600 Subject: [PATCH 002/123] Rebuilt with runwar stable --- build/build.properties | 4 ++-- build/build.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build.properties b/build/build.properties index d0f5cc480..aab372829 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,12 +11,12 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.4.7 +cfml.loader.version=1.4.8 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 launch4j.version=3.4 -runwar.version=3.6.0-SNAPSHOT +runwar.version=3.6.0 #build locations build.type=localdev diff --git a/build/build.xml b/build/build.xml index 0c8cb7e6d..8b4d7391a 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From f4a361ed38870b22fd948495ce9a077a42ed55f7 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 10 Mar 2017 12:03:35 -0600 Subject: [PATCH 003/123] Rebump for 3.7.0 build --- build/build.properties | 2 +- build/build.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build.properties b/build/build.properties index aab372829..2237a9469 100644 --- a/build/build.properties +++ b/build/build.properties @@ -16,7 +16,7 @@ cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 launch4j.version=3.4 -runwar.version=3.6.0 +runwar.version=3.6.1-SNAPSHOT #build locations build.type=localdev diff --git a/build/build.xml b/build/build.xml index 8b4d7391a..8d4236b60 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From fe1e1c30278014384fe2c861d515f52d95e8daca Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 11 Mar 2017 00:13:00 -0600 Subject: [PATCH 004/123] COMMANDBOX-597 --- .../server-commands/commands/server/start.cfc | 10 ++--- src/cfml/system/services/ServerService.cfc | 42 ++++++++++++------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index 591ba37a1..11683bcfe 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -63,9 +63,9 @@ component aliases="start" { * @HTTPEnable enable HTTP * @SSLEnable enable SSL * @SSLPort SSL port number - * @SSLCert SSL certificate - * @SSLKey SSL key (required if SSLCert specified) - * @SSLKeyPass SSL key passphrase (required if SSLCert specified) + * @SSLCertFile Path to SSL certificate file + * @SSLKeyFile Path to SSL key file (required if SSLCert specified) + * @SSLKeyPass SSL key passphrase * @rewritesEnable enable URL rewriting (default false) * @rewritesConfig optional URL rewriting config file path * @heapSize The max heap size in megabytes you would like this server to start with, it defaults to 512mb @@ -100,8 +100,8 @@ component aliases="start" { Boolean HTTPEnable, Boolean SSLEnable, Numeric SSLPort, - String SSLCert, - String SSLKey, + String SSLCertFile, + String SSLKeyFile, String SSLKeyPass, Boolean rewritesEnable, String rewritesConfig, diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 157390662..f7e13cb97 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -208,6 +208,13 @@ component accessors="true" singleton { return fileSystemUtil.resolvePath( thisLibDir ); } ); } + if( !isNull( serverProps.SSLCertFile ) ) { + serverProps.SSLCertFile = fileSystemUtil.resolvePath( serverProps.SSLCertFile ); + } + if( !isNull( serverProps.SSLKeyFile ) ) { + serverProps.SSLKeyFile = fileSystemUtil.resolvePath( serverProps.SSLKeyFile ); + } + // Look up the server that we're starting var serverDetails = resolveServerDetails( arguments.serverProps ); @@ -371,10 +378,10 @@ component accessors="true" singleton { case "SSLPort": serverJSON[ 'web' ][ 'SSL' ][ 'port' ] = serverProps[ prop ]; break; - case "SSLCert": + case "SSLCertFile": serverJSON[ 'web' ][ 'SSL' ][ 'cert' ] = serverProps[ prop ]; break; - case "SSLKey": + case "SSLKeyFile": serverJSON[ 'web' ][ 'SSL' ][ 'key' ] = serverProps[ prop ]; break; case "SSLKeyPass": @@ -470,14 +477,14 @@ component accessors="true" singleton { if( defaults.keyExists( 'trayIcon' ) && len( defaults.trayIcon ) ) { defaults.trayIcon = fileSystemUtil.resolvePath( defaults.trayIcon, defaultwebroot ); } serverInfo.trayIcon = serverProps.trayIcon ?: serverJSON.trayIcon ?: defaults.trayIcon; - serverInfo.SSLEnable = serverProps.SSLEnable ?: serverJSON.web.SSL.enable ?: defaults.web.SSL.enable; - serverInfo.HTTPEnable = serverProps.HTTPEnable ?: serverJSON.web.HTTP.enable ?: defaults.web.HTTP.enable; - serverInfo.SSLPort = serverProps.SSLPort ?: serverJSON.web.SSL.port ?: defaults.web.SSL.port; - serverInfo.SSLCert = serverProps.SSLCert ?: serverJSON.web.SSL.cert ?: defaults.web.SSL.cert; - serverInfo.SSLKey = serverProps.SSLKey ?: serverJSON.web.SSL.key ?: defaults.web.SSL.key; - serverInfo.SSLKeyPass = serverProps.SSLKeyPass ?: serverJSON.web.SSL.keyPass ?: defaults.web.SSL.keyPass; - serverInfo.rewritesEnable = serverProps.rewritesEnable ?: serverJSON.web.rewrites.enable ?: defaults.web.rewrites.enable; - serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; + serverInfo.SSLEnable = serverProps.SSLEnable ?: serverJSON.web.SSL.enable ?: defaults.web.SSL.enable; + serverInfo.HTTPEnable = serverProps.HTTPEnable ?: serverJSON.web.HTTP.enable ?: defaults.web.HTTP.enable; + serverInfo.SSLPort = serverProps.SSLPort ?: serverJSON.web.SSL.port ?: defaults.web.SSL.port; + serverInfo.SSLCertFile = serverProps.SSLCertFile ?: serverJSON.web.SSL.certSSLCertFile ?: defaults.web.SSL.certSSLCertFile; + serverInfo.SSLKeyFile = serverProps.SSLKeyFile ?: serverJSON.web.SSL.keyFile ?: defaults.web.SSL.keyFile; + serverInfo.SSLKeyPass = serverProps.SSLKeyPass ?: serverJSON.web.SSL.keyPass ?: defaults.web.SSL.keyPass; + serverInfo.rewritesEnable = serverProps.rewritesEnable ?: serverJSON.web.rewrites.enable ?: defaults.web.rewrites.enable; + serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; // Clean up spaces in welcome file list serverInfo.welcomeFiles = serverInfo.welcomeFiles.listMap( function( i ){ return trim( i ); } ); @@ -829,11 +836,14 @@ component accessors="true" singleton { .append( '--ssl-enable' ).append( serverInfo.SSLEnable ) .append( '--ssl-port' ).append( serverInfo.SSLPort ); } - if( serverInfo.SSLEnable && serverInfo.SSLCert != "" ) { + if( serverInfo.SSLEnable && serverInfo.SSLCertFile.len() ) { args - .append( '--ssl-cert' ).append( serverInfo.SSLCert ) - .append( '--ssl-key' ).append( serverInfo.SSLKey ) - .append( '--ssl-keypass' ).append( serverInfo.SSLKeyPass ); + .append( '--ssl-cert' ).append( serverInfo.SSLCertFile ) + .append( '--ssl-key' ).append( serverInfo.SSLKeyFile ); + // Not all certs require a password + if( serverInfo.SSLKeyPass.len() ) { + args.append( '--ssl-keypass' ).append( serverInfo.SSLKeyPass ); + } } // Incorporate rewrites to command @@ -1445,8 +1455,8 @@ component accessors="true" singleton { 'HTTPEnable' : true, 'SSLEnable' : false, 'SSLPort' : 1443, - 'SSLCert' : "", - 'SSLKey' : "", + 'SSLCertFile' : "", + 'SSLKeyFile' : "", 'SSLKeyPass' : "", 'rewritesEnable' : false, 'rewritesConfig' : "", From fd2feb0c543dbfc0998c835dd690c5c33ca5f303 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 11 Mar 2017 02:03:31 -0600 Subject: [PATCH 005/123] CommandBox-597 --- src/cfml/system/services/ServerService.cfc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index f7e13cb97..cd20e6699 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -138,8 +138,8 @@ component accessors="true" singleton { 'ssl' : { 'enable' : d.web.ssl.enable ?: false, 'port' : d.web.ssl.port ?: 1443, - 'cert' : d.web.ssl.cert ?: '', - 'key' : d.web.ssl.key ?: '', + 'certFile' : d.web.ssl.certFile ?: '', + 'keyFile' : d.web.ssl.keyFile ?: '', 'keyPass' : d.web.ssl.keyPass ?: '' }, 'rewrites' : { @@ -379,7 +379,7 @@ component accessors="true" singleton { serverJSON[ 'web' ][ 'SSL' ][ 'port' ] = serverProps[ prop ]; break; case "SSLCertFile": - serverJSON[ 'web' ][ 'SSL' ][ 'cert' ] = serverProps[ prop ]; + serverJSON[ 'web' ][ 'SSL' ][ 'certFile' ] = serverProps[ prop ]; break; case "SSLKeyFile": serverJSON[ 'web' ][ 'SSL' ][ 'key' ] = serverProps[ prop ]; @@ -480,7 +480,7 @@ component accessors="true" singleton { serverInfo.SSLEnable = serverProps.SSLEnable ?: serverJSON.web.SSL.enable ?: defaults.web.SSL.enable; serverInfo.HTTPEnable = serverProps.HTTPEnable ?: serverJSON.web.HTTP.enable ?: defaults.web.HTTP.enable; serverInfo.SSLPort = serverProps.SSLPort ?: serverJSON.web.SSL.port ?: defaults.web.SSL.port; - serverInfo.SSLCertFile = serverProps.SSLCertFile ?: serverJSON.web.SSL.certSSLCertFile ?: defaults.web.SSL.certSSLCertFile; + serverInfo.SSLCertFile = serverProps.SSLCertFile ?: serverJSON.web.SSL.certFile ?: defaults.web.SSL.certFile; serverInfo.SSLKeyFile = serverProps.SSLKeyFile ?: serverJSON.web.SSL.keyFile ?: defaults.web.SSL.keyFile; serverInfo.SSLKeyPass = serverProps.SSLKeyPass ?: serverJSON.web.SSL.keyPass ?: defaults.web.SSL.keyPass; serverInfo.rewritesEnable = serverProps.rewritesEnable ?: serverJSON.web.rewrites.enable ?: defaults.web.rewrites.enable; @@ -1455,10 +1455,10 @@ component accessors="true" singleton { 'HTTPEnable' : true, 'SSLEnable' : false, 'SSLPort' : 1443, - 'SSLCertFile' : "", - 'SSLKeyFile' : "", + 'SSLCertFile' : "", + 'SSLKeyFile' : "", 'SSLKeyPass' : "", - 'rewritesEnable' : false, + 'rewritesEnable' : false, 'rewritesConfig' : "", 'heapSize' : 512, 'directoryBrowsing' : true, From f63c7c7046a9921a184976be515a46a00f8de1d9 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 14 Mar 2017 13:23:49 -0400 Subject: [PATCH 006/123] Use Callable Interface instead of super class (#118) Not all the jGit commands extend `GitCommand` (like `InitCommand`), but all of them implement `Callable`. --- src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java b/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java index ae2c5cc6e..a2cfcd871 100644 --- a/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java +++ b/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java @@ -26,7 +26,7 @@ public class CommandCaller { * @return Whatever results that come back from the Jgit command's calling * @throws Exception */ - public Object call( GitCommand command ) throws Exception { + public Object call( Callable command ) throws Exception { try { From 37d1da7bdc2c7c4b51ec1309d4f2cf00c0e782ef Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Tue, 14 Mar 2017 22:17:54 -0400 Subject: [PATCH 007/123] Add import for Callable (#119) I don't know how to run the build locally. Test for me, pretty please? :-) --- src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java b/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java index a2cfcd871..f796e4450 100644 --- a/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java +++ b/src/java/com/ortussolutions/commandbox/jgit/CommandCaller.java @@ -13,6 +13,7 @@ package com.ortussolutions.commandbox.jgit; import org.eclipse.jgit.api.GitCommand; +import java.util.concurrent.Callable; import java.lang.Exception; public class CommandCaller { From 12cc9820c41e3c9a24386102152bdf40f897f69d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 22 Mar 2017 10:55:18 -0500 Subject: [PATCH 008/123] COMMANDBOX-599 --- .../server-commands/commands/server/start.cfc | 2 ++ src/cfml/system/services/ServerService.cfc | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index 11683bcfe..f6db5e7cb 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -69,6 +69,7 @@ component aliases="start" { * @rewritesEnable enable URL rewriting (default false) * @rewritesConfig optional URL rewriting config file path * @heapSize The max heap size in megabytes you would like this server to start with, it defaults to 512mb + * @minHeapSize The min heap size in megabytes you would like this server to start with * @directoryBrowsing Enable/Disabled directory browsing, defaults to true * @JVMArgs Additional JVM args to use when starting the server. Use "server status --verbose" to debug * @runwarArgs Additional Runwar options to use when starting the server. Use "server status --verbose" to debug @@ -106,6 +107,7 @@ component aliases="start" { Boolean rewritesEnable, String rewritesConfig, Numeric heapSize, + Numeric minHeapSize, Boolean directoryBrowsing, String JVMArgs, String runwarArgs, diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index cd20e6699..7a71768e8 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -119,7 +119,8 @@ component accessors="true" singleton { // Duplicate so onServerStart interceptors don't actually change config settings via refernce. 'trayOptions' : duplicate( d.trayOptions ?: [] ), 'jvm' : { - 'heapSize' : d.jvm.heapSize ?: 512, + 'heapSize' : d.jvm.heapSize ?: 512, + 'minHeapSize' : d.jvm.minHeapSize ?: 0, 'args' : d.jvm.args ?: '' }, 'web' : { @@ -404,7 +405,10 @@ component accessors="true" singleton { break; case "heapSize": serverJSON[ 'JVM' ][ 'heapSize' ] = serverProps[ prop ]; - break; + break; + case "minHeapSize": + serverJSON[ 'JVM' ][ 'minHeapSize' ] = serverProps[ prop ]; + break; case "JVMArgs": serverJSON[ 'JVM' ][ 'args' ] = serverProps[ prop ]; break; @@ -496,6 +500,8 @@ component accessors="true" singleton { serverInfo.rewritesConfig = serverProps.rewritesConfig ?: serverJSON.web.rewrites.config ?: defaults.web.rewrites.config; serverInfo.heapSize = serverProps.heapSize ?: serverJSON.JVM.heapSize ?: defaults.JVM.heapSize; + serverInfo.minHeapSize = serverProps.minHeapSize ?: serverJSON.JVM.minHeapSize ?: defaults.JVM.minHeapSize; + serverInfo.directoryBrowsing = serverProps.directoryBrowsing ?: serverJSON.web.directoryBrowsing ?: defaults.web.directoryBrowsing; // Global aliases are always added on top of server.json (but don't overwrite) @@ -756,9 +762,15 @@ component accessors="true" singleton { return parser.unwrapQuotes( i.replace( '\=', '=', 'all' ).replace( '\\', '\', 'all' ) ) ; }); // Add in heap size and java agent - argTokens - .append( '-Xmx#serverInfo.heapSize#m' ) - .append( '-Xms#serverInfo.heapSize#m' ); + argTokens.append( '-Xmx#serverInfo.heapSize#m' ); + + if( val( serverInfo.minHeapSize ) ) { + if( serverInfo.minHeapSize > serverInfo.heapSize ) { + consoleLogger.warn( 'Your JVM min heap size [#serverInfo.minHeapSize#] is set larger than your max size [#serverInfo.heapSize#]! Reducing the Min to prevent errors.' ); + } + argTokens.append( '-Xms#min( serverInfo.minHeapSize, serverInfo.heapSize )#m' ); + } + if( len( trim( javaAgent ) ) ) { argTokens.append( javaagent ); } args @@ -1460,7 +1472,8 @@ component accessors="true" singleton { 'SSLKeyPass' : "", 'rewritesEnable' : false, 'rewritesConfig' : "", - 'heapSize' : 512, + 'heapSize' : 512, + 'minHeapSize' : 0, 'directoryBrowsing' : true, 'JVMargs' : "", 'runwarArgs' : "", From e99ccad4a5866a856d6e625358114e2e18a33393 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Mar 2017 16:10:30 -0500 Subject: [PATCH 009/123] COMMANDBOX-600 --- .../testbox-commands/commands/testbox/run.cfc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index 2b82fa728..78d0000ee 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -85,10 +85,11 @@ component { // run it now baby! try{ - var results = new Http( url=testBoxURL ).send().getPrefix(); - } catch( any e ){ - log.error( "Error executing tests: #e.message# #e.detail#", e ); - return error( 'Error executing tests: #CR# #e.message##CR##e.detail#' ); + // Throw on error means this command will fail if the actual test runner blows up-- possibly on a compilation issue. + Http url=testBoxURL throwonerror=true result='local.results' ; + } catch( any e ){ + logger.error( "Error executing tests: #e.message# #e.detail#", e ); + return error( 'Error executing tests: #CR# #e.message##CR##e.detail##CR##local.results.fileContent ?: ''#' ); } // Do we have an output file From 96546e9f7bcd8722c2b86831489480b1e3ca133d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Mar 2017 16:12:30 -0500 Subject: [PATCH 010/123] COMMANDBOX-601 --- src/cfml/system/Shell.cfc | 2 +- src/cfml/system/util/Formatter.cfc | 29 +++++++++++++++++++++-------- src/cfml/system/util/Print.cfc | 7 ++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index 655a98f84..3bd088554 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -553,7 +553,7 @@ component accessors="true" singleton { variables.reader.print( variables.print.whiteOnRedLine( 'ERROR (#variables.version#)' ) ); variables.reader.println(); - variables.reader.print( variables.print.boldRedText( variables.formatterUtil.HTML2ANSI( arguments.err.message ) ) ); + variables.reader.print( variables.print.boldRedText( variables.formatterUtil.HTML2ANSI( arguments.err.message, 'boldRed' ) ) ); variables.reader.println(); if( structKeyExists( arguments.err, 'detail' ) ) { diff --git a/src/cfml/system/util/Formatter.cfc b/src/cfml/system/util/Formatter.cfc index 853768e6a..152b6994d 100644 --- a/src/cfml/system/util/Formatter.cfc +++ b/src/cfml/system/util/Formatter.cfc @@ -33,15 +33,25 @@ component singleton { * Converts HTML into ANSI text * @html.hint HTML to convert **/ - function HTML2ANSI( required html ) { + function HTML2ANSI( required html, additionalFormatting='' ) { var text = html; if( len( trim( text ) ) == 0 ) { return ""; - } - text = ansifyHTML( text, "b", "bold" ); - text = ansifyHTML( text, "strong", "bold" ); - text = ansifyHTML( text, "em", "underline" ); + } + + // Trim all lines. leading/trailing whitespace in HTML is not useful + text = text.listToArray( chr( 13 ) & chr( 10 ) ).map( function( i ) { + return trim( i ); + } ).toList( chr( 10 ) ); + + // Remove style and script blocks + text = reReplaceNoCase(text, "","","all"); + text = reReplaceNoCase(text, "]*>.*","","all"); + + text = ansifyHTML( text, "b", "bold", additionalFormatting ); + text = ansifyHTML( text, "strong", "bold", additionalFormatting ); + text = ansifyHTML( text, "em", "underline", additionalFormatting ); // Replace br tags (and any whitespace/line breaks after them) with a CR text = reReplaceNoCase( text , "]*>\s*", CR, 'all' ); @@ -53,9 +63,12 @@ component singleton { text = replace(text,match,blockText,"one"); } - // Remove remaining HTML // If you have any < characters in your string that aren't HTML, this will truncate the text text = reReplaceNoCase(text, "<.*?>","","all"); + + text = reReplaceNoCase(text, "[\n]{2,}",chr( 10 ) & chr( 10 ),"all"); + + // Turn any escaped HTML entities into their true form text = unescapeHTML( text ); @@ -68,13 +81,13 @@ component singleton { * @tag.hint HTML tag name to replace * @ansiCode.hint ANSI code to replace tag with **/ - function ansifyHTML(text,tag,ansiCode) { + function ansifyHTML(text, tag, ansiCode, additionalFormatting) { var t=tag; var matches = REMatch('(?i)<#t#[ ^>]*>(.+?)', text); for(var match in matches) { // This doesn't really work inside of a larger string that you are applying formatting to // The end of the boldText clears all formatting, and the rest of the string is just plain. - var boldtext = print[ ansiCode ]( reReplaceNoCase(match,"<#t#[^>]*>(.+?)","\1") ); + var boldtext = print[ ansiCode ]( reReplaceNoCase(match,"<#t#[^>]*>(.+?)","\1") ) & print.text( '', additionalFormatting, true ); text = replace(text,match,boldtext,"one"); } return text; diff --git a/src/cfml/system/util/Print.cfc b/src/cfml/system/util/Print.cfc index c0c176083..753f1cfcf 100644 --- a/src/cfml/system/util/Print.cfc +++ b/src/cfml/system/util/Print.cfc @@ -102,6 +102,8 @@ component { var text = arrayLen(missingMethodArguments) ? missingMethodArguments[ 1 ] : ''; // Additional formatting text var methodName &= arrayLen(missingMethodArguments) > 1 ? missingMethodArguments[ 2 ] : ''; + // Don't turn off ANSI formatting at the end + var noEnd = arrayLen(missingMethodArguments) > 2 ? missingMethodArguments[ 3 ] : false; // Carve it up until it's gone while( len( methodName ) ) { @@ -167,7 +169,10 @@ component { // Don't mess with the string if we didn't format it if( len( ANSIString ) ) { - text = ANSIString & text & getANSIAttribute( this.ANSIAttributes["off"] ); + text = ANSIString & text; + if( !noEnd ) { + text &= getANSIAttribute( this.ANSIAttributes["off"] ); + } } // Add a CR if this was supposed to be a line From 5b88a2ad537ca66721ea57497f7b51ce8ce2f717 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Mar 2017 17:17:33 -0500 Subject: [PATCH 011/123] COMMANDBOX-602 --- src/cfml/system/box.json | 6 +- .../modules/JSONPrettyPrint/ModuleConfig.cfc | 10 +++ .../system/modules/JSONPrettyPrint/README.md | 32 +++++++ .../system/modules/JSONPrettyPrint/box.json | 38 +++++++++ .../models/JSONPrettyPrint.cfc | 84 +++++++++++++++++++ src/cfml/system/util/Formatter.cfc | 69 +-------------- 6 files changed, 171 insertions(+), 68 deletions(-) create mode 100644 src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc create mode 100644 src/cfml/system/modules/JSONPrettyPrint/README.md create mode 100644 src/cfml/system/modules/JSONPrettyPrint/box.json create mode 100644 src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc diff --git a/src/cfml/system/box.json b/src/cfml/system/box.json index b2a67b8b7..dc5b32d0a 100644 --- a/src/cfml/system/box.json +++ b/src/cfml/system/box.json @@ -6,7 +6,8 @@ "dependencies":{ "string-similarity":"^1.0.0", "semver":"^1.0.0", - "globber":"^1.0.0" + "globber":"^1.0.0", + "JSONPrettyPrint":"^1.0.0" }, "devDependencies":{ @@ -14,6 +15,7 @@ "installPaths":{ "string-similarity":"modules\\string-similarity", "semver":"modules\\semver", - "globber":"modules\\globber" + "globber":"modules\\globber", + "JSONPrettyPrint":"modules\\JSONPrettyPrint" } } \ No newline at end of file diff --git a/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc b/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc new file mode 100644 index 000000000..c0cf40145 --- /dev/null +++ b/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc @@ -0,0 +1,10 @@ +component { + + this.name = "JSONPrettyPrint"; + this.author = ""; + this.webUrl = "https://github.com//JSONPrettyPrint"; + + function configure() { + // + } +} \ No newline at end of file diff --git a/src/cfml/system/modules/JSONPrettyPrint/README.md b/src/cfml/system/modules/JSONPrettyPrint/README.md new file mode 100644 index 000000000..5f446c180 --- /dev/null +++ b/src/cfml/system/modules/JSONPrettyPrint/README.md @@ -0,0 +1,32 @@ +Pretty print JSON objects witbh line breaks and indentation to make it more human readable. +If you have an app that writes JSON files that humans need to easily be able to read, run the JSON through this library first. It doesn't modify the data at all-- only the whitespace. + +## Installation + +``` +CommandBox> install JSONPrettyPrint +``` + +## Usage + +``` +var formatted = getInstance( 'JSONPrettyPrint' ).formatJSON( '{ "foo" : "bar" }' ); +``` + +Or pass a complex CFML object and it will serialize for you. + +``` +var formatted = getInstance( 'JSONPrettyPrint' ).formatJSON( { foo : 'bar' } ); +``` + +The `JSONPrettyPrint` is a threadsafe singleton and suitable for injection. Inject the library like so: + +``` +component { + property name='JSONPrettyPrint' inject; + + function writeJSON( required JSON, required path ) { + fileWrite( path, JSONPrettyPrint.formatJSON( JSON ) ); + } +} +``` \ No newline at end of file diff --git a/src/cfml/system/modules/JSONPrettyPrint/box.json b/src/cfml/system/modules/JSONPrettyPrint/box.json new file mode 100644 index 000000000..9fa4a9e26 --- /dev/null +++ b/src/cfml/system/modules/JSONPrettyPrint/box.json @@ -0,0 +1,38 @@ +{ + "name":"JSONPrettyPrint", + "version":"1.0.0", + "author":"", + "location":"Ortus-Solutions/JSONPrettyPrint#v1.0.0", + "homepage":"https://github.com/Ortus-Solutions/JSONPrettyPrint", + "documentation":"https://github.com/Ortus-Solutions/JSONPrettyPrint", + "repository":{ + "type":"git", + "URL":"https://github.com/Ortus-Solutions/JSONPrettyPrint" + }, + "bugs":"https://github.com/Ortus-Solutions/JSONPrettyPrint/issues", + "slug":"JSONPrettyPrint", + "shortDescription":"Pretty print JSON objects", + "description":"Pretty print JSON objects", + "type":"modules", + "dependencies":{ + + }, + "devDependencies":{ + "coldbox":"^4.3.0+188", + "testbox":"^2.4.0+80" + }, + "installPaths":{ + "testbox":"testbox", + "coldbox":"tests\\resources\\app\\coldbox" + }, + "scripts":{ + "postVersion":"package set location='Ortus-Solutions/JSONPrettyPrint#v`package version`'", + "onRelease":"forgebox use ortus && publish", + "postPublish":"!git push && !git push --tags" + }, + "ignore":[ + "**/.*", + "test", + "tests" + ] +} \ No newline at end of file diff --git a/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc b/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc new file mode 100644 index 000000000..f0b1e042e --- /dev/null +++ b/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc @@ -0,0 +1,84 @@ +/** +********************************************************************************* +* Copyright Since 2014 by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano +* +*/ +component accessors="true" singleton alias='JSONPrettyPrint' { + + /** + * Pretty JSON + * @json.hint A string containing JSON, or a complex value that can be serialized to JSON + **/ + public function formatJson( json ) { + + // Overload this method to accept a struct or array + if( !isSimpleValue( arguments.json ) ) { + arguments.json = serializeJSON( arguments.json ); + } + + var retval = createObject("java","java.lang.StringBuilder").init(''); + var str = json; + var pos = 0; + var strLen = str.length(); + var indentStr = ' '; + var newLine = chr( 13 ) & chr( 10 ); + var char = ''; + var inQuote = false; + var isEscaped = false; + + for (var i=0; i Date: Thu, 23 Mar 2017 17:22:35 -0500 Subject: [PATCH 012/123] COMMANDBOX-15 --- src/cfml/system/box.json | 2 +- .../system/modules/globber/ModuleConfig.cfc | 13 +- src/cfml/system/modules/globber/box.json | 27 ++- .../system/modules/globber/models/Globber.cfc | 116 +++++++++ .../globber/models/PathPatternMatcher.cfc | 39 ++- src/cfml/system/modules/globber/readme.md | 54 ++++- .../system/util/testPathPatternMatcher.cfc | 224 ------------------ 7 files changed, 224 insertions(+), 251 deletions(-) create mode 100644 src/cfml/system/modules/globber/models/Globber.cfc delete mode 100644 tests/cfml/system/util/testPathPatternMatcher.cfc diff --git a/src/cfml/system/box.json b/src/cfml/system/box.json index dc5b32d0a..9f742318a 100644 --- a/src/cfml/system/box.json +++ b/src/cfml/system/box.json @@ -6,7 +6,7 @@ "dependencies":{ "string-similarity":"^1.0.0", "semver":"^1.0.0", - "globber":"^1.0.0", + "globber":"^2.0.0", "JSONPrettyPrint":"^1.0.0" }, "devDependencies":{ diff --git a/src/cfml/system/modules/globber/ModuleConfig.cfc b/src/cfml/system/modules/globber/ModuleConfig.cfc index b402a68d0..c2be0a683 100644 --- a/src/cfml/system/modules/globber/ModuleConfig.cfc +++ b/src/cfml/system/modules/globber/ModuleConfig.cfc @@ -1,7 +1,10 @@ component { - - function configure() { - - } - + + this.name = "globber"; + this.author = ""; + this.webUrl = "https://github.com//globber"; + + function configure() { + binder.map( 'globber' ).toDSL( 'globber@globber' ); + } } \ No newline at end of file diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index f652c9815..1f3b69d36 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,8 @@ { "name":"Globber", - "version":"1.0.0", + "version":"2.0.0", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v1.0.0", + "location":"Ortus-Solutions/globber#v2.0.0", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ @@ -12,5 +12,26 @@ "bugs":"https://github.com/Ortus-Solutions/globber/issues", "slug":"globber", "shortDescription":"I am a utility to match file system path patterns.", - "type":"modules" + "type":"modules", + "dependencies":{ + + }, + "devDependencies":{ + "coldbox":"^4.3.0+188", + "testbox":"^2.4.0+80" + }, + "installPaths":{ + "testbox":"testbox", + "coldbox":"tests\\resources\\app\\coldbox" + }, + "scripts":{ + "postVersion":"package set location='Ortus-Solutions/globber#v`package version`'", + "onRelease":"forgebox use ortus && publish", + "postPublish":"!git push && !git push --tags" + }, + "ignore":[ + "**/.*", + "test", + "tests" + ] } \ No newline at end of file diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc new file mode 100644 index 000000000..f23ea53f0 --- /dev/null +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -0,0 +1,116 @@ +/** +********************************************************************************* +* Copyright Since 2014 by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood +* +* I represent a single globbing pattern and provide a fluent API to access the matching files +* Unlike the PathPatternMatcher, which only handles comparisons of patterns, this model +* actually interacts with the file system to resolve a pattern to a list of real file system +* resources. +* +*/ +component accessors="true" { + // DI + property name='pathPatternMatcher' inject='pathPatternMatcher@globber'; + + /** The file globbing pattern to match. */ + property name='pattern' default=''; + /** Array of real file system resources that match the pattern */ + property name='matchArray'; + /** "file", "dir", or "all" (default) */ + // property name='type'; + + + function init() { + return this; + } + + /** + * Override setter to ensure consistent slashe in pattern + */ + function setPattern( required string pattern ) { + variables.pattern = arguments.pattern.replace( '\', '/', 'all' ); + return this; + } + + /** + * Pass a closure to this function to have it + * applied to each paths matched by the pattern. + */ + function apply( udf ) { + ensureMatches(); + getMatchArray().each( udf ); + return this; + } + + /** + * Get array of matched file system paths + */ + function matches() { + ensureMatches(); + return getMatchArray(); + } + + /** + * Make sure the matchArray has been loaded. + */ + private function ensureMatches() { + if( isNull( getMatchArray() ) ) { + process(); + } + } + + /** + * Load matching file from the file system + */ + private function process() { + local.thisPattern = getPattern(); + if( !thisPattern.len() ) { + throw( 'Cannot glob empty pattern.' ); + } + + // If there's no wildcard, this is not a glob, so just pass it in as the only matched path + if( !thisPattern contains '*' && !thisPattern contains '?' ) { + setMatchArray( [ pattern ] ); + return; + } + + // To optimize this as much as possible, we want to get a directory listing as deep as possible so we process a few files as we can. + // Find the deepest folder that doesn't have a wildcard in it. + var baseDir = ''; + var i = 0; + while( ++i <= thisPattern.listLen( '/' ) ) { + var token = thisPattern.listGetAt( i, '/' ); + if( token contains '*' || token contains '?' ) { + break; + } + baseDir = baseDir.listAppend( token, '/' ); + } + + if( !baseDir.len() ) { + baseDir = '/'; + } + + var recurse = false; + if( thisPattern contains '**' ) { + recurse = true; + } + + setMatchArray( + directoryList ( + filter=function( path ){ + if( pathPatternMatcher.matchPattern( thisPattern, path, true ) ) { + return true; + } + return false; + }, + recurse=local.recurse, + path=baseDir + ) + ); + + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc index 414f400a7..df0ab8ac3 100644 --- a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc +++ b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc @@ -1,9 +1,9 @@ /** ********************************************************************************* -* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* Copyright Since 2014 by Ortus Solutions, Corp * www.coldbox.org | www.ortussolutions.com ******************************************************************************** -* @author Brad Wood, Luis Majano, Denny Valliant +* @author Brad Wood * * I am a utility to match file system path patterns * @@ -21,6 +21,9 @@ * * Use a double ** to match zero or more characters including slashes. This allows a pattern to span directories Ex: * - a/** /z will match a/z and a/b/z and a/b/c/z +* +* A question mark matches a single non-slash character +* - /h?t matches hat but not ham or h/t * */ component accessors="true" singleton { @@ -31,16 +34,19 @@ component accessors="true" singleton { /** * Match a single path to a single pattern. Returns true if the path matches the pattern, otherwise false. - * @pattern.hint The pattern to match against the path - * @path.hint The file system path to test. Can be a file or directory. Direcories MUST end with a trailing slash + * @pattern The pattern to match against the path + * @path The file system path to test. Can be a file or directory. Direcories MUST end with a trailing slash + * @exact True if the full path needs to match. False to match inside a path */ - boolean function matchPattern( required string pattern, required string path ) { + boolean function matchPattern( required string pattern, required string path, boolean exact=false) { // Normalize slashes arguments.pattern = replace( arguments.pattern, '\', '/', 'all' ); arguments.path = replace( arguments.path, '\', '/', 'all' ); - // Start all paths with / - arguments.path = ( arguments.path.startsWith( '/' ) ? arguments.path : '/' & arguments.path ); + if( !exact ) { + // Start all paths with / + arguments.path = ( arguments.path.startsWith( '/' ) ? arguments.path : '/' & arguments.path ); + } // build a regex based on the pattern var regex = arguments.pattern; @@ -54,23 +60,32 @@ component accessors="true" singleton { regex = replace( regex, '**', '__anything_', 'all' ); // Single * matches anything BUT slash regex = replace( regex, '*', '__anythingButSlash__', 'all' ); + // ? matches any single non-slash character + regex = replace( regex, '?', '__singleNonSlash__', 'all' ); + // Switch placeholders for actual regex - regex = replace( regex, '__zeroOrMoreDirs_', '/.*', 'all' ); + regex = replace( regex, '__zeroOrMoreDirs_', '(/.*/|/)', 'all' ); regex = replace( regex, '__anything_', '.*', 'all' ); regex = replace( regex, '__anythingButSlash__', '[^/]*', 'all' ); + regex = replace( regex, '__singleNonSlash__', '[^/]', 'all' ); // If pattern starts with slash - if( regex.startsWith( '/' )) { + if( regex.startsWith( '/' ) || exact ) { // add a ^ to match start of string regex = '^' & regex; } else { // Otherwise, anything can precede this pattern regex = '.*' & regex; } - // Anything can follow this pattern - regex &= '.*'; + if( exact ) { + regex &= '$'; + // Anything can follow this pattern + } else { + regex &= '.*'; + } - //writeDump(regex);abort; + // writeDump(regex); + // writeDump(arguments.path); return ( reFindNoCase( regex, arguments.path ) > 0 ); } diff --git a/src/cfml/system/modules/globber/readme.md b/src/cfml/system/modules/globber/readme.md index b8bb459f7..22f8435ce 100644 --- a/src/cfml/system/modules/globber/readme.md +++ b/src/cfml/system/modules/globber/readme.md @@ -1,26 +1,68 @@ -# Globber +[![Build Status](https://travis-ci.org/Ortus-Solutions/globber.svg?branch=master)](https://travis-ci.org/Ortus-Solutions/globber) I am a utility to match file system path patterns (globbing) in the same manner as Unix file systems. +## Installation + +Run the following in CommandBox: + +``` +install globber +``` + +## Usage + +Inject the path pattern matcher service/Globber or get it from WireBox. + +### Path Pattern Matcher + +This service is a singleton that handles path matching but doesn't actually touch the file system. + +``` +var pathPatternMatcher = wirebox.getInstance( 'PathPatternMatcher@globber' ); +pathPatternMatcher.matchPattern( '/foo/*', '/foo/bar' ); +pathPatternMatcher.matchPatterns( [ '/foo/*', '**.txt' ], '/foo/bar' ); +``` + End a pattern with a slash to only match a directory. Start a pattern with a slash to start in the root. Ex: + * `foo` wil match any file or folder in the directory tree * `/foo` will only match a file or folder in the root * `foo/` will only match a directory anywhere in the directory tree * `/foo/` will only match a folder in the root Use a single * to match zero or more characters INSIDE a file or folder name (won't match a slash) Ex: + * `foo*` will match any file or folder starting with "foo" * `foo*.txt` will match any file or folder starting with "foo" and ending with .txt * `*foo` will match any file or folder ending with "foo" * `a/*/z` will match `a/b/z` but not `a/b/c/z` Use a double ** to match zero or more characters including slashes. This allows a pattern to span directories Ex: + * `a/**/z` will match `a/z` and `a/b/z` and `a/b/c/z` -## Usage +A question mark matches a single non-slash character + +* `/h?t` matches `hat` but not `ham` or `h/t` + +### Globber +This transient represents a single globbing pattern and provide a fluent API to access the matching files. Unlike the PathPatternMatcher, which only handles comparisons of patterns, this model actually interacts with the file system to resolve a pattern to a list of real file system resources. + +Finds any text files recursivley below the `myFolder` directory whos name end with `bar`. +``` +var results = wirebox.getInstance( 'globber' ) + .setPattern( 'C:/myFolder/**/*bar.txt' ) + matches(); +``` + +Apply a closure to a markdown files in a directory. +``` +wirebox.getInstance( 'globber' ) + .setPattern( 'C:/myFolder/*.md' ) + apply( function( path ) { + fileDelete( path ); + } ); ``` -var globber = wirebox.getInstance( 'PathPatternMatcher@globber' ); -globber.matchPattern( '/foo/*', '/foo/bar' ); -globber.matchPatterns( [ '/foo/*', '**.txt' ], '/foo/bar' ); -``` \ No newline at end of file + diff --git a/tests/cfml/system/util/testPathPatternMatcher.cfc b/tests/cfml/system/util/testPathPatternMatcher.cfc deleted file mode 100644 index 8bc26bd23..000000000 --- a/tests/cfml/system/util/testPathPatternMatcher.cfc +++ /dev/null @@ -1,224 +0,0 @@ -component name="TestPathPatternMatcher" extends="mxunit.framework.TestCase" { - - public void function setup() { - PathPatternMatcher = application.wirebox.getInstance( 'PathPatternMatcher' ); - } - - // End a pattern with a slash to only match a directory. Start a pattern with a slash to start in the root. - - // foo will match any file or folder in the directory tree - public void function testSimpleString() { - assertTrue( PathPatternMatcher.matchPattern( 'a', 'a/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'c', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd', 'a/b/c/d/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( 'a', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'c', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd', 'a/b/c/d' ) ); - } - - - // /foo will only match a file or folder in the root - public void function testLeadingSlash() { - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/b', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/b', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/d', 'a/b/c/d/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/b', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/b', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/d', 'a/b/c/d' ) ); - } - - // foo/ will only match a directory anywhere in the directory tree - public void function testTrailingSlash() { - assertTrue( PathPatternMatcher.matchPattern( 'a/', 'a/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b/', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'c/', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd/', 'a/b/c/d/' ) ); - - assertFalse( PathPatternMatcher.matchPattern( 'a/', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b/', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'c/', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'd/', 'a/b/c/d' ) ); - } - - // /foo/ will only match a folder in the root - public void function testLeadingAndTrailingSlash() { - assertTrue( PathPatternMatcher.matchPattern( '/a/', 'a/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/b/', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/c/', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/d/', 'a/b/c/d/' ) ); - - assertFalse( PathPatternMatcher.matchPattern( '/a/', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/b/', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/c/', 'a/b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/d/', 'a/b/c/d' ) ); - } - - // Use a single * to match zero or more characters INSIDE a file or folder name (won't match a slash) - - // foo* will match any file or folder starting with "foo" - public void function testTrailingSingleAstrisk() { - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'a/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'abc/' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'a*', 'xyz/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'abc/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*', 'a/bxyz/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*', 'a/b/c/def/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'abc' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*', 'abc/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*', 'a/bxyz/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*', 'a/b/c/def' ) ); - } - - // foo*.txt will match any file or folder starting with "foo" and ending with .txt - public void function testInsideSingleAstrisk() { - assertTrue( PathPatternMatcher.matchPattern( 'a*.txt', 'a.txt/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*.txt', 'abc.txt/' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'a*.txt', 'xyz.txt/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*z', 'az/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*z', 'abcz/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*z', 'a/bz/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*z', 'a/bxyz/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*z', 'a/b/c/dz/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*z', 'a/b/c/defz/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( 'a*.txt', 'a.txt' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*.txt', 'abc.txt' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'a*.txt', 'xyz.txt' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*z', 'az/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a*z', 'abcz/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*z', 'a/bz/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'b*z', 'a/bxyz/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*z', 'a/b/c/dz' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'd*z', 'a/b/c/defz' ) ); - } - - // *foo will match any file or folder ending with "foo" - public void function testLeadingSingleAstrisk() { - assertTrue( PathPatternMatcher.matchPattern( '*a.txt', 'a.txt/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*a.txt', 'cba.txt/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '*a.txt', 'xyz.txt/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*a', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'xyz/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'abcxyz/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/xyz/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/abcxyz/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/b/c/xyz/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/b/c/abcxyz/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( '*a.txt', 'a.txt' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*a.txt', 'cba.txt' ) ); - assertFalse( PathPatternMatcher.matchPattern( '*a.txt', 'xyz.txt' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*a', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'xyz/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'abcxyz/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/xyz/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/abcxyz/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/b/c/xyz' ) ); - assertTrue( PathPatternMatcher.matchPattern( '*xyz', 'a/b/c/abcxyz' ) ); - } - - // a/*/z will match a/b/z but not a/b/c/z - public void function testSingleAstrisk() { - assertTrue( PathPatternMatcher.matchPattern( 'a/*/z', 'a/b/z/' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'a/*/z', 'a/b/c/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/*/z', 'a/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/*/z', 'a/z/foo/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/*', 'a/b/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( 'a/*/z', 'a/b/z/' ) ); - assertFalse( PathPatternMatcher.matchPattern( 'a/*/z', 'a/b/c/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/*/z', 'a/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/*/z', 'a/z/foo/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/*', 'a/b/' ) ); - } - - // Use a double ** to match zero or more characters including slashes. This allows a pattern to span directories - - // a/**/z will match a/z and a/b/z and a/b/c/z - public void function testDoubleAstrisk() { - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/b/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/b/c/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/b/c/z/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/z/foo/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/b/c/z/foo/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/**', 'a/b/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/**', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo', 'foo/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo/bar', 'foo/bar/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo/bar', 'a/b/foo/bar/' ) ); - - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/b/z' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/z' ) ); - assertTrue( PathPatternMatcher.matchPattern( 'a/**/z', 'a/b/c/z' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/z' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/b/c/z' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/z/foo' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/**/z', 'a/b/c/z/foo' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/**', 'a/b' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/**', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo', 'foo' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo/bar', 'foo/bar' ) ); - assertTrue( PathPatternMatcher.matchPattern( '**/foo/bar', 'a/b/foo/bar' ) ); - } - - // Normalized slashes - public void function testNormalizedSlashes() { - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a\' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a', 'a\b/c\d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '\b', 'a/b/c/d/' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a/b', 'a/b/c/d/' ) ); - assertFalse( PathPatternMatcher.matchPattern( '\d', 'a\b\c\d\' ) ); - - assertTrue( PathPatternMatcher.matchPattern( '\a', 'a' ) ); - assertTrue( PathPatternMatcher.matchPattern( '\a', 'a\b/c/d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/b', 'a/b/c/d' ) ); - assertTrue( PathPatternMatcher.matchPattern( '/a\b', 'a/b/c\d' ) ); - assertFalse( PathPatternMatcher.matchPattern( '/d', 'a\b\c\d' ) ); - } - - // Array of patterns - public void function testArrayOfPatterns() { - - assertTrue( PathPatternMatcher.matchPatterns( - [ - 'a/b/c/foo.txt', - 'box.json', - '/logs' - ], - 'box.json' - ) ); - - assertFalse( PathPatternMatcher.matchPatterns( - [ - 'a/b/c/foo.txt', - 'box.json', - '/logs' - ], - 'ColdBox.cfc' - ) ); - } -} \ No newline at end of file From 43d1fe26892d747573f126866553852f4ac82f45 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Mar 2017 23:46:03 -0500 Subject: [PATCH 013/123] COMMANDBOX-15 --- src/cfml/system/BaseCommand.cfc | 11 +++ src/cfml/system/modules/globber/box.json | 4 +- .../system/modules/globber/models/Globber.cfc | 80 +++++++++++++---- .../globber/models/PathPatternMatcher.cfc | 4 +- src/cfml/system/modules/globber/readme.md | 31 +++++-- .../system-commands/commands/delete.cfc | 86 +++++++++---------- .../system-commands/commands/dir.cfc | 30 +++---- src/cfml/system/services/CommandService.cfc | 40 ++++++++- src/cfml/system/util/FileSystem.cfc | 3 +- 9 files changed, 198 insertions(+), 91 deletions(-) diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index b52473fed..d9c3165eb 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -176,4 +176,15 @@ component accessors="true" singleton { .run(); } + /** + * Return a new globber + **/ + function globber( pattern='' ) { + var globber = wirebox.getInstance( 'Globber' ); + if( pattern.len() ) { + globber.setPattern( arguments.pattern ); + } + return globber; + } + } \ No newline at end of file diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index 1f3b69d36..ee9c7bcd7 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,8 @@ { "name":"Globber", - "version":"2.0.0", + "version":"2.0.2", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v2.0.0", + "location":"Ortus-Solutions/globber#v2.0.2", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index f23ea53f0..63079a46d 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -17,13 +17,42 @@ component accessors="true" { /** The file globbing pattern to match. */ property name='pattern' default=''; - /** Array of real file system resources that match the pattern */ - property name='matchArray'; - /** "file", "dir", or "all" (default) */ - // property name='type'; + /** query of real file system resources that match the pattern */ + property name='matchQuery'; + /** Return matches as a query instead of an array */ + property name='format' default='array'; + /** Sort to use */ + property name='sort' default='type, name'; + /** Directory the list was pulled from */ + property name='baseDir' default=''; function init() { + variables.format = 'array'; + return this; + } + + /** + * Return results as query + */ + function asQuery() { + setFormat( 'query' ); + return this; + } + + /** + * Return results as array + */ + function asArray() { + setFormat( 'array' ); + return this; + } + + /** + * Return results as array + */ + function withSort( thisSort ) { + setSort( thisSort ); return this; } @@ -40,8 +69,7 @@ component accessors="true" { * applied to each paths matched by the pattern. */ function apply( udf ) { - ensureMatches(); - getMatchArray().each( udf ); + matches().each( udf ); return this; } @@ -50,14 +78,21 @@ component accessors="true" { */ function matches() { ensureMatches(); - return getMatchArray(); + if( getFormat() == 'query' ) { + return getMatchQuery(); + } else { + return getMatchQuery().reduce( function( arr, row ) { + // Turn all the slashes the right way for this OS + return arr.append( row.directory & '/' & row.name & ( row.type == 'Dir' ? '/' : '' ) ); + }, [] ); + } } /** - * Make sure the matchArray has been loaded. + * Make sure the MatchQuery has been loaded. */ private function ensureMatches() { - if( isNull( getMatchArray() ) ) { + if( isNull( getMatchQuery() ) ) { process(); } } @@ -70,24 +105,28 @@ component accessors="true" { if( !thisPattern.len() ) { throw( 'Cannot glob empty pattern.' ); } - - // If there's no wildcard, this is not a glob, so just pass it in as the only matched path - if( !thisPattern contains '*' && !thisPattern contains '?' ) { - setMatchArray( [ pattern ] ); - return; - } - + // To optimize this as much as possible, we want to get a directory listing as deep as possible so we process a few files as we can. // Find the deepest folder that doesn't have a wildcard in it. var baseDir = ''; var i = 0; - while( ++i <= thisPattern.listLen( '/' ) ) { + // Skip last token + while( ++i < thisPattern.listLen( '/' ) ) { var token = thisPattern.listGetAt( i, '/' ); if( token contains '*' || token contains '?' ) { break; } baseDir = baseDir.listAppend( token, '/' ); } + // Unix paths need the leading slash put back + if( thisPattern.startsWith( '/' ) ) { + baseDir = '/' & baseDir; + } + + // Windows drive letters need trailing slash. + if( baseDir.listLen( '/' ) == 1 && baseDir contains ':' ) { + baseDir = baseDir & '/'; + } if( !baseDir.len() ) { baseDir = '/'; @@ -98,7 +137,7 @@ component accessors="true" { recurse = true; } - setMatchArray( + setMatchQuery( directoryList ( filter=function( path ){ if( pathPatternMatcher.matchPattern( thisPattern, path, true ) ) { @@ -106,10 +145,13 @@ component accessors="true" { } return false; }, + listInfo='query', recurse=local.recurse, - path=baseDir + path=baseDir, + sort=getSort() ) ); + setBaseDir( baseDir ); } diff --git a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc index df0ab8ac3..2b0a18421 100644 --- a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc +++ b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc @@ -84,8 +84,8 @@ component accessors="true" singleton { regex &= '.*'; } - // writeDump(regex); - // writeDump(arguments.path); + // writeDump(regex); + // writeDump(arguments.path); return ( reFindNoCase( regex, arguments.path ) > 0 ); } diff --git a/src/cfml/system/modules/globber/readme.md b/src/cfml/system/modules/globber/readme.md index 22f8435ce..72cbffcce 100644 --- a/src/cfml/system/modules/globber/readme.md +++ b/src/cfml/system/modules/globber/readme.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/Ortus-Solutions/globber.svg?branch=master)](https://travis-ci.org/Ortus-Solutions/globber) -I am a utility to match file system path patterns (globbing) in the same manner as Unix file systems. +I am a utility to match file system path patterns (globbing) in a similar manner as Unix file systems or `.gitignore` syntax. ## Installation @@ -50,19 +50,40 @@ A question mark matches a single non-slash character This transient represents a single globbing pattern and provide a fluent API to access the matching files. Unlike the PathPatternMatcher, which only handles comparisons of patterns, this model actually interacts with the file system to resolve a pattern to a list of real file system resources. -Finds any text files recursivley below the `myFolder` directory whos name end with `bar`. +Returns an array of all text files recursively below the `myFolder` directory whose name end with `bar`. ``` var results = wirebox.getInstance( 'globber' ) .setPattern( 'C:/myFolder/**/*bar.txt' ) - matches(); + .matches(); ``` -Apply a closure to a markdown files in a directory. +Apply a closure to all markdown files in a directory. ``` wirebox.getInstance( 'globber' ) .setPattern( 'C:/myFolder/*.md' ) - apply( function( path ) { + .apply( function( path ) { fileDelete( path ); } ); ``` +#### Get data as query + +You can get a query back instead of an array by adding `.asQuery()` to your DSL. The also affects the datatype you `apply()` closure runs against. +The query columns match what comes from the `directoryList()` fucntion. +``` +var qryResults = globber + .setPattern( baseDir & '/**' ) + .asQuery() + .matches(); +``` + +#### Sort data + +You may sort the data using the same column names you'd get back from the query (even if you're getting an array) by using the `withSort()` function. + +``` +var qryResults = globber + .setPattern( baseDir & '/**' ) + .withSort( 'type asc, name desc' ) + .matches(); +``` \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/delete.cfc b/src/cfml/system/modules_app/system-commands/commands/delete.cfc index 400269377..b5f37e315 100644 --- a/src/cfml/system/modules_app/system-commands/commands/delete.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/delete.cfc @@ -21,60 +21,60 @@ component aliases="rm,del" { /** - * @path.hint file or directory to delete + * @path.hint file or directory to delete. Globbing patters allowed such as *.txt * @force.hint Force deletion without asking * @recurse.hint Delete sub directories **/ - function run( required path, Boolean force=false, Boolean recurse=false ) { + function run( required Globber path, Boolean force=false, Boolean recurse=false ) { - // Make path canonical and absolute - arguments.path = fileSystemUtil.resolvePath( arguments.path ); - - // It's a directory - if( directoryExists( arguments.path ) ) { - - var subMessage = arguments.recurse ? ' and all its subdirectories' : ''; - - if( arguments.force || confirm( "Delete #path##subMessage#? [y/n]" ) ) { + path.apply( function( thisPath ) { + // It's a directory + if( directoryExists( thisPath ) ) { + + var subMessage = recurse ? ' and all its subdirectories' : ''; - if( directoryList( arguments.path ).len() && !arguments.recurse ) { - return error( 'Directory [#arguments.path#] is not empty! Use the "recurse" parameter to override' ); - } - // Catch this to gracefully handle where the OS or another program - // has the folder locked. - try { - directoryDelete( arguments.path, recurse ); - print.greenLine( "Deleted #arguments.path#" ); - } catch( any e ) { - error( '#e.message##CR#The folder is possibly locked by another program.' ); - logger.error( '#e.message# #e.detail#' , e.stackTrace ); + if( force || confirm( "Delete #thisPath##subMessage#? [y/n]" ) ) { + + if( directoryList( thisPath ).len() && !recurse ) { + return error( 'Directory [#thisPath#] is not empty! Use the "recurse" parameter to override' ); + } + // Catch this to gracefully handle where the OS or another program + // has the folder locked. + try { + directoryDelete( thisPath, recurse ); + print.greenLine( "Deleted #thisPath#" ); + } catch( any e ) { + error( '#e.message##CR#The folder is possibly locked by another program.' ); + logger.error( '#e.message# #e.detail#' , e.stackTrace ); + } + } else { + print.redLine( "Cancelled!" ); } + + + // It's a file + } else if( fileExists( thisPath ) ){ + + if( force || confirm( "Delete #thisPath#? [y/n]" ) ) { + + // Catch this to gracefully handle where the OS or another program + // has the file locked. + try { + fileDelete( thisPath ); + print.greenLine( "Deleted #thisPath#" ); + } catch( any e ) { + error( '#e.message##CR#The file is possibly locked by another program.' ); + logger.error( '#e.message# #e.detail#' , e.stackTrace ); + } } else { print.redLine( "Cancelled!" ); } - - // It's a file - } else if( fileExists( arguments.path ) ){ - - if( arguments.force || confirm( "Delete #path#? [y/n]" ) ) { - - // Catch this to gracefully handle where the OS or another program - // has the file locked. - try { - fileDelete( arguments.path ); - print.greenLine( "Deleted #arguments.path#" ); - } catch( any e ) { - error( '#e.message##CR#The file is possibly locked by another program.' ); - logger.error( '#e.message# #e.detail#' , e.stackTrace ); - } - } else { - print.redLine( "Cancelled!" ); + } else { + return error( "File/directory does not exist: #thisPath#" ); } - - } else { - return error( "File/directory does not exist: #arguments.path#" ); - } + + } ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/dir.cfc b/src/cfml/system/modules_app/system-commands/commands/dir.cfc index 223abe852..25d12961b 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -15,26 +15,24 @@ component aliases="ls,ll,directory" { /** - * @directory.hint The directory to list the contents of + * @directory.hint The directory to list the contents of or a file Globbing path to filter on * @recurse.hint Include nested files and folders **/ - function run( String directory="", Boolean recurse=false ) { - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); + function run( Globber directory=globber( getCWD() ), Boolean recurse=false ) { + + // If the user gives us an existing directory foo, change it to the + // glob pattern foo/* or foo/** if doing a recursive listing. + if( directoryExists( directory.getPattern() ) ){ + directory.setPattern( directory.getPattern() & '*' & ( recurse ? '*' : '' ) ) + } - var results = directoryList( arguments.directory, arguments.recurse, "query" ); - // TODO: Add ability to re-sort this based on user input - query name="local.results" dbtype="query" { - echo(" - SELECT * - FROM results - ORDER BY type, name - "); - } + var results = directory + .asQuery() + .matches(); for( var x=1; x lte results.recordcount; x++ ) { - var printCommand = ( results.type[ x ] eq "File" ? "green" : "purple" ); + var printCommand = ( results.type[ x ] eq "File" ? "green" : "white" ); print[ printCommand & "line" ]( results.type[ x ] & " " & @@ -42,7 +40,7 @@ component aliases="ls,ll,directory" { results.attributes[ x ] & " " & numberFormat( results.size[ x ], "999999999" ) & " " & dateTimeFormat( results.dateLastModified[ x ], "MMM dd,yyyy HH:mm:ss" ) & " " & - cleanRecursiveDir( arguments.directory, results.directory[ x ] ) & results.name[ x ] + cleanRecursiveDir( arguments.directory.getBaseDir(), results.directory[ x ] ) & results.name[ x ] ); } @@ -55,7 +53,7 @@ component aliases="ls,ll,directory" { * Cleanup directory recursive nesting */ private function cleanRecursiveDir( required directory, required incoming ){ - var prefix = ( replacenocase( arguments.incoming, arguments.directory, "" ) ); + var prefix = ( replacenocase( expandPath( arguments.incoming ), expandPath( arguments.directory ), "" ) ); return ( len( prefix ) ? reReplace( prefix, "^(/|\\)", "" ) & "/" : "" ); } diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 46bc94640..634c689e7 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -11,6 +11,8 @@ component accessors="true" singleton { // DI Properties property name='shell' inject='Shell'; + property name='wirebox' inject='wirebox'; + property name="fileSystemUtil" inject='FileSystem'; property name='parser' inject='Parser'; property name='system' inject='System@constants'; property name='cr' inject='cr@constants'; @@ -265,12 +267,15 @@ component accessors="true" singleton { // Make sure we have all required params. parameterInfo.namedParameters = ensureRequiredParams( parameterInfo.namedParameters, commandParams ); - // Ensure supplied params match the correct type - validateParams( parameterInfo.namedParameters, commandParams ); - // Evaluate parameter expressions evaluateExpressions( parameterInfo ); + // Create globbing patterns + createGlobs( parameterInfo, commandParams ); + + // Ensure supplied params match the correct type + validateParams( parameterInfo.namedParameters, commandParams ); + // Reset the printBuffer commandInfo.commandReference.CFC.reset(); @@ -833,6 +838,34 @@ component accessors="true" singleton { return userNamedParams; } + /** + * Check for Globber parameters and create actual Globber object out of them + **/ + private function createGlobs( parameterInfo, commandParams ) { + // Loop over user-supplied params + for( var paramName in parameterInfo.namedParameters ) { + + // If this is an expected param + functionIndex = commandParams.find( function( i ) { + return i.name == paramName; + } ); + + if( functionIndex ) { + var paramData = commandParams[ functionIndex ]; + // And it's of type Globber + if( ( paramData.type ?: 'any' ) == 'Globber' ) { + + // Overwrite it with an actual Globber instance seeded with the original canonical path as the pattern. + parameterInfo.namedParameters[ paramName ] = wirebox.getInstance( 'Globber' ) + .setPattern( + fileSystemUtil.resolvePath( + parameterInfo.namedParameters[ paramName ] + ) + ); + } + } + } + } /** * Make sure all params are the correct type @@ -843,6 +876,7 @@ component accessors="true" singleton { // If it's required and hasn't been supplied... if( userNamedParams.keyExists( param.name ) && param.keyExists( "type" ) + && param.type != 'Globber' && !isValid( param.type, userNamedParams[ param.name ] ) ){ throw( message='Parameter [#param.name#] has a value of [#userNamedParams[ param.name ]#] which is not of type [#param.type#].', type="commandException"); diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 1e2fbc184..6abf51d3b 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -66,9 +66,10 @@ component accessors="true" singleton { } // This will standardize the name and calculate stuff like ../../ - return oPath.getCanonicalPath(); + return getCanonicalPath( oPath.toString() ); } catch ( any e ) { + rethrow; return arguments.basePath & '/' & path; } From ab09b49cbe3dcadd8648ba3b3dee55e87fe63c1e Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 00:09:55 -0500 Subject: [PATCH 014/123] COMMANDBOX-15 --- .../system-commands/commands/dir.cfc | 2 +- .../system-commands/commands/touch.cfc | 60 +++++++++++-------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/dir.cfc b/src/cfml/system/modules_app/system-commands/commands/dir.cfc index 25d12961b..3971826a7 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -23,7 +23,7 @@ component aliases="ls,ll,directory" { // If the user gives us an existing directory foo, change it to the // glob pattern foo/* or foo/** if doing a recursive listing. if( directoryExists( directory.getPattern() ) ){ - directory.setPattern( directory.getPattern() & '*' & ( recurse ? '*' : '' ) ) + directory.setPattern( directory.getPattern() & '*' & ( recurse ? '*' : '' ) ); } // TODO: Add ability to re-sort this based on user input diff --git a/src/cfml/system/modules_app/system-commands/commands/touch.cfc b/src/cfml/system/modules_app/system-commands/commands/touch.cfc index 2398ea32a..cf2c0a1e0 100644 --- a/src/cfml/system/modules_app/system-commands/commands/touch.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/touch.cfc @@ -22,40 +22,50 @@ component aliases="new" { /** - * @file File to create + * @file File or globbing pattern. Creates if not existing, otherwise updates timestamp * @force If forced, then file will be recreated even if it exists * @open Open the file after creating it **/ function run( - required file, + required Globber file, boolean force=false, boolean open=false ) { - arguments.file = fileSystemUtil.resolvePath( arguments.file ); - - var oFile = createObject( "java", "java.io.File" ).init( arguments.file ); - var fileName = listLast( arguments.file, "/" ); - - // if we have a force, recreate the file - if( arguments.force and oFile.existS() ){ - oFile.delete(); - } + // Get matching paths + var matches = file.matches(); - // check for update or creation - if( !oFile.exists() ){ - oFile.createNewFile(); - print.line( "#fileName# created!" ); - } else { - oFile.setLastModified( now().getTime() ); - print.line( "#fileName# last modified bit updated!" ); + // If no paths were found and the pattern isn't a glob, just use the pattern (it's a new file). + if( !matches.len() && !( file.getPattern() contains '*' ) && !( file.getPattern() contains '?' ) ) { + matches.append( file.getPattern() ); } - - // Open file for the user - if( arguments.open ){ - // Defer to the "edit" command. - command( 'edit' ) - .params( arguments.file ) - .run(); + + for( var theFile in matches ) { + + var oFile = createObject( "java", "java.io.File" ).init( theFile ); + var fileName = listLast( theFile, "/" ); + + // if we have a force, recreate the file + if( arguments.force and oFile.exists() ){ + oFile.delete(); + } + + // check for update or creation + if( !oFile.exists() ){ + oFile.createNewFile(); + print.line( "#fileName# created!" ); + } else { + oFile.setLastModified( now().getTime() ); + print.line( "#fileName# last modified bit updated!" ); + } + + // Open file for the user + if( arguments.open ){ + // Defer to the "edit" command. + command( 'edit' ) + .params( theFile ) + .run(); + } + } } From 5d2e72d2bf5f75d574d4dd8d5764ce1f3db8f129 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 00:10:49 -0500 Subject: [PATCH 015/123] Update globber --- src/cfml/system/modules/globber/box.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index ee9c7bcd7..d703b0fe2 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,8 @@ { "name":"Globber", - "version":"2.0.2", + "version":"2.0.3", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v2.0.2", + "location":"Ortus-Solutions/globber#v2.0.3", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ From 3db559e8fa86bc8aebbf860f649c9a21c8d24691 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 00:33:06 -0500 Subject: [PATCH 016/123] Update Globber --- src/cfml/system/modules/globber/box.json | 4 ++-- src/cfml/system/modules/globber/models/Globber.cfc | 7 +++++++ .../system/modules_app/system-commands/commands/mv.cfc | 3 +-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index d703b0fe2..051aafc2d 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,8 @@ { "name":"Globber", - "version":"2.0.3", + "version":"2.0.5", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v2.0.3", + "location":"Ortus-Solutions/globber#v2.0.5", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index 63079a46d..4e8927ad3 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -88,6 +88,13 @@ component accessors="true" { } } + /** + * Get count of matched files + */ + function count() { + return matches().len(); + } + /** * Make sure the MatchQuery has been loaded. */ diff --git a/src/cfml/system/modules_app/system-commands/commands/mv.cfc b/src/cfml/system/modules_app/system-commands/commands/mv.cfc index 9c3fdf03c..723734284 100644 --- a/src/cfml/system/modules_app/system-commands/commands/mv.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/mv.cfc @@ -28,10 +28,9 @@ component aliases="rename" { * @path.hint The file or directory source to rename * @newPath.hint The new name of the file or directory **/ - function run( required path, required newPath ) { + function run( required Globber path, required newPath ) { // Make path canonical and absolute - arguments.path = fileSystemUtil.resolvePath( arguments.path ); arguments.newPath = fileSystemUtil.resolvePath( arguments.newPath ); // It's a directory From d2bc3d7e955ba01c0767c35339543b27bf7c3a76 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 01:26:02 -0500 Subject: [PATCH 017/123] COMMANDBOX-15 --- src/cfml/system/modules/globber/box.json | 4 +-- .../system/modules/globber/models/Globber.cfc | 5 +-- .../globber/models/PathPatternMatcher.cfc | 11 ++++-- .../system-commands/commands/dir.cfc | 2 +- .../system-commands/commands/mv.cfc | 34 ++++++++++++------- .../system-commands/commands/touch.cfc | 2 +- src/cfml/system/services/CommandService.cfc | 12 ++++--- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index 051aafc2d..9a5251653 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,8 @@ { "name":"Globber", - "version":"2.0.5", + "version":"2.0.6", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v2.0.5", + "location":"Ortus-Solutions/globber#v2.0.6", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index 4e8927ad3..5bf74d84e 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -108,7 +108,8 @@ component accessors="true" { * Load matching file from the file system */ private function process() { - local.thisPattern = getPattern(); + local.thisPattern = getPattern().replace( '\', '/', 'all' ); + if( !thisPattern.len() ) { throw( 'Cannot glob empty pattern.' ); } @@ -147,7 +148,7 @@ component accessors="true" { setMatchQuery( directoryList ( filter=function( path ){ - if( pathPatternMatcher.matchPattern( thisPattern, path, true ) ) { + if( pathPatternMatcher.matchPattern( thisPattern, path & ( directoryExists( path ) ? '/' : '' ), true ) ) { return true; } return false; diff --git a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc index 2b0a18421..19c7d6160 100644 --- a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc +++ b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc @@ -68,6 +68,12 @@ component accessors="true" singleton { regex = replace( regex, '__anything_', '.*', 'all' ); regex = replace( regex, '__anythingButSlash__', '[^/]*', 'all' ); regex = replace( regex, '__singleNonSlash__', '[^/]', 'all' ); + + // If the pattern doesn't come with an explicit ending slash, add an optional one + // so we can match ending files OR folders + if( !regex.endsWith( '/' ) ) { + regex &= '/?'; + } // If pattern starts with slash if( regex.startsWith( '/' ) || exact ) { @@ -84,8 +90,9 @@ component accessors="true" singleton { regex &= '.*'; } - // writeDump(regex); - // writeDump(arguments.path); + + //systemoutput(regex, true); + //systemoutput(arguments.path, true); return ( reFindNoCase( regex, arguments.path ) > 0 ); } diff --git a/src/cfml/system/modules_app/system-commands/commands/dir.cfc b/src/cfml/system/modules_app/system-commands/commands/dir.cfc index 3971826a7..60622b30f 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -40,7 +40,7 @@ component aliases="ls,ll,directory" { results.attributes[ x ] & " " & numberFormat( results.size[ x ], "999999999" ) & " " & dateTimeFormat( results.dateLastModified[ x ], "MMM dd,yyyy HH:mm:ss" ) & " " & - cleanRecursiveDir( arguments.directory.getBaseDir(), results.directory[ x ] ) & results.name[ x ] + cleanRecursiveDir( arguments.directory.getBaseDir(), results.directory[ x ] ) & results.name[ x ] & ( results.type[ x ] == "Dir" ? "/" : "" ) ); } diff --git a/src/cfml/system/modules_app/system-commands/commands/mv.cfc b/src/cfml/system/modules_app/system-commands/commands/mv.cfc index 723734284..883e9d5b3 100644 --- a/src/cfml/system/modules_app/system-commands/commands/mv.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/mv.cfc @@ -31,21 +31,29 @@ component aliases="rename" { function run( required Globber path, required newPath ) { // Make path canonical and absolute - arguments.newPath = fileSystemUtil.resolvePath( arguments.newPath ); + local.newPath = fileSystemUtil.resolvePath( arguments.newPath ); - // It's a directory - if( directoryExists( arguments.path ) ) { - // rename directory - directoryRename( arguments.path, arguments.newPath, true ); - print.greenLine( "Directory renamed/moved to #arguments.newPath#" ); - // It's a file - } else if( fileExists( arguments.path ) ){ - // move file - fileMove( arguments.path, arguments.newPath ); - print.greenLine( "File renamed/moved to #arguments.newPath#" ); - } else { - return error( "File/directory does not exist: #arguments.path#" ); + if( path.count() > 1 && !directoryExists( arguments.newPath ) ) { + error( '[#arguments.newPath#] is not a directory.' ); } + + path.apply( function( thisPath ){ + print.redLine( thisPath ); + // It's a directory + if( directoryExists( thisPath ) ) { + // rename directory + directoryRename( thisPath, newPath, true ); + print.greenLine( "Directory renamed/moved to #newPath#" ); + // It's a file + } else if( fileExists( thisPath ) ){ + // move file + fileMove( thisPath, newPath ); + print.greenLine( "File renamed/moved to #newPath#" ); + } else { + return error( "File/directory does not exist: #thisPath#" ); + } + } ); + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/touch.cfc b/src/cfml/system/modules_app/system-commands/commands/touch.cfc index cf2c0a1e0..4a1ba4364 100644 --- a/src/cfml/system/modules_app/system-commands/commands/touch.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/touch.cfc @@ -35,7 +35,7 @@ component aliases="new" { var matches = file.matches(); // If no paths were found and the pattern isn't a glob, just use the pattern (it's a new file). - if( !matches.len() && !( file.getPattern() contains '*' ) && !( file.getPattern() contains '?' ) ) { + if( !file.count() && !( file.getPattern() contains '*' ) && !( file.getPattern() contains '?' ) ) { matches.append( file.getPattern() ); } diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 634c689e7..f56c67d44 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -856,12 +856,14 @@ component accessors="true" singleton { if( ( paramData.type ?: 'any' ) == 'Globber' ) { // Overwrite it with an actual Globber instance seeded with the original canonical path as the pattern. + var originalPath = parameterInfo.namedParameters[ paramName ].replace( '\', '/', 'all' ); + var newPath = fileSystemUtil.resolvePath( originalPath ).replace( '\', '/', 'all' ); + // Preserve any explicit trailing slashes + if( originalPath.endsWith( '/' ) && !newPath.endsWith( '/' ) ) { + newPath &= '/'; + } parameterInfo.namedParameters[ paramName ] = wirebox.getInstance( 'Globber' ) - .setPattern( - fileSystemUtil.resolvePath( - parameterInfo.namedParameters[ paramName ] - ) - ); + .setPattern( newPath ); } } } From c212a38da02cf2b9556a5c9056591002ef0a6971 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 01:35:13 -0500 Subject: [PATCH 018/123] COMMANDBOX-15 --- .../system-commands/commands/cp.cfc | 39 +++++++++++-------- .../system-commands/commands/mv.cfc | 14 +++---- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/cp.cfc b/src/cfml/system/modules_app/system-commands/commands/cp.cfc index c04c9b5bd..046798fc9 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cp.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cp.cfc @@ -25,26 +25,33 @@ component aliases="copy" { * @recurse.hint If true, copies the subdirectories, otherwise only the files in the source directory. * @filter.hint A directory copy filter string that uses "*" as a wildcard, for example, "*.cfm" **/ - function run( required path, required newPath, boolean recurse=false, string filter="*" ) { + function run( required Globber path, required newPath, boolean recurse=false, string filter="*" ) { // Make path canonical and absolute - arguments.path = fileSystemUtil.resolvePath( arguments.path ); - arguments.newPath = fileSystemUtil.resolvePath( arguments.newPath ); + var thisNewPath = fileSystemUtil.resolvePath( arguments.newPath ); - // It's a directory - if( directoryExists( arguments.path ) ) { - // rename directory - directoryCopy( arguments.path, arguments.newPath, arguments.recurse, arguments.filter, true ); - print.greenLine( "Directory copied to #arguments.newPath#" ); - // It's a file - } else if( fileExists( arguments.path ) ){ - // Copy file - DirectoryCreate( getDirectoryFromPath( arguments.newPath ), true, true ); - fileCopy( arguments.path, arguments.newPath ); - print.greenLine( "File copied to #arguments.newPath#" ); - } else { - return error( "File/directory does not exist: #arguments.path#" ); + if( path.count() > 1 && !directoryExists( thisNewPath ) ) { + error( '[#thisNewPath#] is not a directory.' ); } + + path.apply( function( thisPath ){ + + // It's a directory + if( directoryExists( thisPath ) ) { + // rename directory + directoryCopy( thisPath, thisNewPath, arguments.recurse, arguments.filter, true ); + print.greenLine( "Directory copied to #thisNewPath#" ); + // It's a file + } else if( fileExists( thisPath ) ){ + // Copy file + DirectoryCreate( getDirectoryFromPath( thisNewPath ), true, true ); + fileCopy( thisPath, thisNewPath ); + print.greenLine( "File copied to #thisNewPath#" ); + } else { + return error( "File/directory does not exist: #thisPath#" ); + } + + } ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/mv.cfc b/src/cfml/system/modules_app/system-commands/commands/mv.cfc index 883e9d5b3..e9ba61809 100644 --- a/src/cfml/system/modules_app/system-commands/commands/mv.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/mv.cfc @@ -31,10 +31,10 @@ component aliases="rename" { function run( required Globber path, required newPath ) { // Make path canonical and absolute - local.newPath = fileSystemUtil.resolvePath( arguments.newPath ); + var thisNewPath = fileSystemUtil.resolvePath( arguments.newPath ); - if( path.count() > 1 && !directoryExists( arguments.newPath ) ) { - error( '[#arguments.newPath#] is not a directory.' ); + if( path.count() > 1 && !directoryExists( thisNewPath ) ) { + error( '[#thisNewPath#] is not a directory.' ); } path.apply( function( thisPath ){ @@ -42,13 +42,13 @@ component aliases="rename" { // It's a directory if( directoryExists( thisPath ) ) { // rename directory - directoryRename( thisPath, newPath, true ); - print.greenLine( "Directory renamed/moved to #newPath#" ); + directoryRename( thisPath, thisNewPath, true ); + print.greenLine( "Directory renamed/moved to #thisNewPath#" ); // It's a file } else if( fileExists( thisPath ) ){ // move file - fileMove( thisPath, newPath ); - print.greenLine( "File renamed/moved to #newPath#" ); + fileMove( thisPath, thisNewPath ); + print.greenLine( "File renamed/moved to #thisNewPath#" ); } else { return error( "File/directory does not exist: #thisPath#" ); } From f7b5041355a7ab8968559cd15f8292de036802ed Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 01:38:44 -0500 Subject: [PATCH 019/123] COMMANDBOX-15 --- .../system-commands/commands/edit.cfc | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/edit.cfc b/src/cfml/system/modules_app/system-commands/commands/edit.cfc index 165f119b9..41206a12e 100644 --- a/src/cfml/system/modules_app/system-commands/commands/edit.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/edit.cfc @@ -14,20 +14,22 @@ component aliases="open" { /** * @path.hint Path to open natively. **/ - function run( path='' ) { + function run( Globber path=globber( getCWD() ) ) { + + path.apply( function( thisPath ) { + + if( !fileExists( thisPath ) AND !directoryExists( thisPath ) ){ + return error( "Path: #thisPath# does not exist, cannot open it!" ); + } + + if( fileSystemUtil.openNatively( thisPath ) ){ + print.line( "Resource Opened!" ); + } else { + error( "Unsupported OS, cannot open path." ); + }; + + } ); - // Make path canonical and absolute - arguments.path = fileSystemUtil.resolvePath( arguments.path ); - - if( !fileExists( arguments.path ) AND !directoryExists( arguments.path ) ){ - return error( "Path: #arguments.path# does not exist, cannot open it!" ); - } - - if( fileSystemUtil.openNatively( arguments.path ) ){ - print.line( "Resource Opened!" ); - } else { - error( "Unsupported OS, cannot open path." ); - }; } } \ No newline at end of file From aeb62ee89d964fc5baaff365a2ec9ef13f0de4b0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 01:48:27 -0500 Subject: [PATCH 020/123] Chicken, meet egg. --- src/cfml/system/services/ServerService.cfc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 7a71768e8..334d6cc55 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -91,7 +91,7 @@ component accessors="true" singleton { // Init server config if not found if( !fileExists( variables.serverConfig ) ){ - setServers( {} ); + initServers(); } // Init custom server location if not exists if( !directoryExists( variables.customServerDirectory ) ){ @@ -1282,6 +1282,15 @@ component accessors="true" singleton { } + /** + * Create initial server JSON + **/ + function initServers(){ + lock name="serverservice.serverconfig" type="exclusive" throwOnTimeout="true" timeout="10"{ + fileWrite( serverConfig, '{}' ); + } + } + /** * persist servers * @servers.hint struct of serverInfos From 1d8c26ee8a5460ed1d4a59fb5ed0c7aa976cad93 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 24 Mar 2017 01:56:35 -0500 Subject: [PATCH 021/123] COMMANDBOX-15 --- .../system-commands/commands/cat.cfc | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/cat.cfc b/src/cfml/system/modules_app/system-commands/commands/cat.cfc index 248e362dc..d3c2fc6b6 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cat.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cat.cfc @@ -29,7 +29,7 @@ component aliases="type" { * @file3.hint File to concatenate to previous file(s) * @file4.hint File to concatenate to previous file(s) **/ - function run( required file1, file2, file3, file4 ) { + function run( required Globber file1, Globber file2, Globber file3, Globber file4 ) { var buffer = ''; @@ -38,21 +38,31 @@ component aliases="type" { if( !isNull( file ) ) { - // Make file canonical and absolute - file = fileSystemUtil.resolvePath( file ); - - if( !fileExists( file ) ){ - return error( "File: #file# does not exist!" ); - } + if( isSimpleValue( file ) ) { + // Make file canonical and absolute + file = fileSystemUtil.resolvePath( file ); + + if( !fileExists( file ) ){ + return error( "File: #file# does not exist!" ); + } + + if( buffer.len() ) { buffer &= CR } + buffer &= fileRead( file ); - buffer &= fileRead( file ); + } else { + + file.apply( function( thisFile ) { + if( buffer.len() ) { buffer &= CR } + buffer &= fileRead( thisFile ); + } ); + + } } } - return buffer; } From 3c89b68502afdf18fc0959a506cca63876faf19e Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 15 Apr 2017 16:28:00 -0500 Subject: [PATCH 022/123] COMMANDBOX-513 --- .../server-commands/commands/server/start.cfc | 6 +++-- src/cfml/system/services/ServerService.cfc | 27 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index f6db5e7cb..ed306e14a 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -82,7 +82,7 @@ component aliases="start" { * @console Start this server in the forground console process and wait until Ctrl-C is pressed to stop it. * @welcomeFiles A comma-delimited list of default files to load when visiting a directory (index.cfm,index.htm,etc) * @serverHomeDirectory The folder where the CF engine WAR should be extracted - + * @restMappings A comma-delimited list of REST mappings in the form of /api/*,/rest/*. Empty string to disable. **/ function run( String name, @@ -118,7 +118,9 @@ component aliases="start" { Numeric startTimeout, Boolean console, String welcomeFiles, - String serverHomeDirectory + String serverHomeDirectory, + String restMappings, + Boolean trace ){ // This is a common mis spelling diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 334d6cc55..8b588a4f8 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -155,9 +155,10 @@ component accessors="true" singleton { 'serverConfigDir' : d.app.serverConfigDir ?: '', 'webXML' : d.app.webXML ?: '', 'standalone' : d.app.standalone ?: false, - 'WARPath' : d.app.WARPath ?: "", - 'cfengine' : d.app.cfengine ?: "", - 'serverHomeDirectory' : d.app.serverHomeDirectory ?: "" + 'WARPath' : d.app.WARPath ?: '', + 'cfengine' : d.app.cfengine ?: '', + 'restMappings' : d.app.cfengine ?: '', + 'serverHomeDirectory' : d.app.serverHomeDirectory ?: '' }, 'runwar' : { 'args' : d.runwar.args ?: '' @@ -352,6 +353,9 @@ component accessors="true" singleton { case "cfengine": serverJSON[ 'app' ][ 'cfengine' ] = serverProps[ prop ]; break; + case "restMappings": + serverJSON[ 'app' ][ 'restMappings' ] = serverProps[ prop ]; + break; case "WARPath": // This path is canonical already. var thisFile = replace( serverProps[ 'WARPath' ], '\', '/', 'all' ); @@ -427,6 +431,7 @@ component accessors="true" singleton { // Setup serverinfo according to params // Hand-entered values take precendence, then settings saved in server.json, and finally defaults. // The big servers.json is only used to keep a record of the last values the server was started with + serverInfo.trace = serverProps.trace ?: serverJSON.trace ?: defaults.trace; serverInfo.debug = serverProps.debug ?: serverJSON.debug ?: defaults.debug; serverInfo.openbrowser = serverProps.openbrowser ?: serverJSON.openbrowser ?: defaults.openbrowser; serverInfo.host = serverProps.host ?: serverJSON.web.host ?: defaults.web.host; @@ -555,7 +560,7 @@ component accessors="true" singleton { serverInfo.cfengine = serverProps.cfengine ?: serverJSON.app.cfengine ?: defaults.app.cfengine; - + serverInfo.restMappings = serverProps.restMappings ?: serverJSON.app.restMappings ?: defaults.app.restMappings; // relative rewrite config path in server.json is resolved relative to the server.json if( isDefined( 'serverJSON.app.WARPath' ) && len( serverJSON.app.WARPath ) ) { serverJSON.app.WARPath = fileSystemUtil.resolvePath( serverJSON.app.WARPath, defaultServerConfigFileDirectory ); } if( isDefined( 'defaults.app.WARPath' ) && len( defaults.app.WARPath ) ) { defaults.app.WARPath = fileSystemUtil.resolvePath( defaults.app.WARPath, defaultwebroot ); } @@ -787,10 +792,16 @@ component accessors="true" singleton { .append( '--server-name' ).append( serverInfo.name ) .append( '--tray-icon' ).append( serverInfo.trayIcon ) .append( '--tray-config' ).append( trayOptionsPath ) - .append( '--servlet-rest-mappings' ).append( '/rest/*,/api/*' ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); + + if( len( serverInfo.restMappings ) ) { + args.append( '--servlet-rest-mappings' ).append( serverInfo.restMappings ); + } else { + args.append( '--servlet-rest-mappings' ).append( '___DISABLED___' ); + } + if( len( errorPages ) ) { args.append( '--error-pages' ).append( errorPages ); @@ -806,10 +817,9 @@ component accessors="true" singleton { } - // If background, wrap up JVM args to pass through to background servers - // "real" JVM args must come before Runwar args, so creating two variables, once of which will always be empty. + // If background, wrap up JVM args to pass through to background servers. "Real" JVM args must come before Runwar args if( background ) { - var argString = argTokens.toList( ';' ); //.replace( '"', '\"', 'all' ); + var argString = argTokens.toList( ';' ); if( len( argString ) ) { args.append( '--jvm-args=#trim( argString )#' ); } @@ -1487,6 +1497,7 @@ component accessors="true" singleton { 'JVMargs' : "", 'runwarArgs' : "", 'cfengine' : "", + 'restMappings' : "", 'engineName' : "", 'engineVersion' : "", 'WARPath' : "", From 1a850e2af8e120fcc226baa6768594f3135d0145 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 15 Apr 2017 16:29:42 -0500 Subject: [PATCH 023/123] COMMANDBOX-606 --- src/cfml/system/services/ServerService.cfc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 8b588a4f8..00dc12022 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -115,6 +115,7 @@ component accessors="true" singleton { 'startTimeout' : 240, 'stopsocket' : d.stopsocket ?: 0, 'debug' : d.debug ?: false, + 'trace' : d.trace ?: false, 'trayicon' : d.trayicon ?: '', // Duplicate so onServerStart interceptors don't actually change config settings via refernce. 'trayOptions' : duplicate( d.trayOptions ?: [] ), @@ -217,6 +218,9 @@ component accessors="true" singleton { serverProps.SSLKeyFile = fileSystemUtil.resolvePath( serverProps.SSLKeyFile ); } + if( structKeyExists( serverProps, 'trace' ) && serverProps.trace ) { + serverProps.debug = true; + } // Look up the server that we're starting var serverDetails = resolveServerDetails( arguments.serverProps ); @@ -276,7 +280,7 @@ component accessors="true" singleton { // Save hand-entered properties in our server.json for next time for( var prop in serverProps ) { // Ignore null props or ones that shouldn't be saved - if( isNull( serverProps[ prop ] ) || listFindNoCase( 'saveSettings,serverConfigFile,debug,force,console', prop ) ) { + if( isNull( serverProps[ prop ] ) || listFindNoCase( 'saveSettings,serverConfigFile,debug,force,console,trace', prop ) ) { continue; } var configPath = replace( fileSystemUtil.resolvePath( defaultServerConfigFileDirectory ), '\', '/', 'all' ) & '/'; @@ -802,6 +806,9 @@ component accessors="true" singleton { args.append( '--servlet-rest-mappings' ).append( '___DISABLED___' ); } + if( serverInfo.trace ) { + args.append( '--log-level' ).append( 'trace' ); + } if( len( errorPages ) ) { args.append( '--error-pages' ).append( errorPages ); From 9e363bf8624bfb71b0c7a1522b7f3d8428cbaf61 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 18 Apr 2017 23:44:46 -0500 Subject: [PATCH 024/123] Log error with module loading. --- src/cfml/system/services/ModuleService.cfc | 1 + src/cfml/system/services/ServerService.cfc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index a3ae2a352..9f5aedeee 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -262,6 +262,7 @@ } catch( any var e ) { consoleLogger.error( 'There was an error loading module [#arguments.moduleName#]' ); consoleLogger.error( '#e.message##chr( 10 )##e.detail#' ); + instance.logger.error( 'There was an error loading module [#arguments.moduleName#]', e ); return false; } // Verify if module has been disabled diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 00dc12022..5dab22fca 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -800,9 +800,11 @@ component accessors="true" singleton { .append( '--timeout' ).append( serverInfo.startTimeout ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); + // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. if( len( serverInfo.restMappings ) ) { args.append( '--servlet-rest-mappings' ).append( serverInfo.restMappings ); } else { + // This effectively disables it (assuming there's not a real directory or route called "___disabled___") but it's janky args.append( '--servlet-rest-mappings' ).append( '___DISABLED___' ); } From 1e6b2a8956b1a961f79806da2bc4369265faffd6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 20 Apr 2017 23:55:21 -0500 Subject: [PATCH 025/123] COMMANDBOX-560 --- src/cfml/system/services/ServerService.cfc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 5dab22fca..c9f55f5de 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -147,6 +147,10 @@ component accessors="true" singleton { 'rewrites' : { 'enable' : d.web.rewrites.enable ?: false, 'config' : d.web.rewrites.config ?: variables.rewritesDefaultConfig + }, + 'basicAuth' : { + 'enable' : d.web.basicAuth.enable ?: true, + 'users' : d.web.basicAuth.users ?: {} } }, 'app' : { @@ -497,6 +501,8 @@ component accessors="true" singleton { serverInfo.SSLKeyFile = serverProps.SSLKeyFile ?: serverJSON.web.SSL.keyFile ?: defaults.web.SSL.keyFile; serverInfo.SSLKeyPass = serverProps.SSLKeyPass ?: serverJSON.web.SSL.keyPass ?: defaults.web.SSL.keyPass; serverInfo.rewritesEnable = serverProps.rewritesEnable ?: serverJSON.web.rewrites.enable ?: defaults.web.rewrites.enable; + serverInfo.basicAuthEnable = serverJSON.web.basicAuth.enable ?: defaults.web.basicAuth.enable; + serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; // Clean up spaces in welcome file list serverInfo.welcomeFiles = serverInfo.welcomeFiles.listMap( function( i ){ return trim( i ); } ); @@ -880,6 +886,18 @@ component accessors="true" singleton { // Incorporate rewrites to command args.append( '--urlrewrite-enable' ).append( serverInfo.rewritesEnable ); + // Basic auth + if( serverInfo.basicAuthEnable && serverInfo.basicAuthUsers.count() ) { + // Escape commas and equals with backslash + var sanitizeBA = function( i ) { return i.replace( ',', '\,', 'all' ).replace( '=', '\=', 'all' ); }; + var thisBasicAuthUsers = ''; + serverInfo.basicAuthUsers.each( function( i ) { + thisBasicAuthUsers = thisBasicAuthUsers.listAppend( '#sanitizeBA( i )#=#sanitizeBA( serverInfo.basicAuthUsers[ i ] )#' ); + } ); + // user=pass,user2=pass2 + args.append( '--basicauth-users' ).append( thisBasicAuthUsers ); + } + if( serverInfo.rewritesEnable ){ if( !fileExists(serverInfo.rewritesConfig) ){ consoleLogger.error( '.' ); @@ -1500,6 +1518,8 @@ component accessors="true" singleton { 'SSLKeyPass' : "", 'rewritesEnable' : false, 'rewritesConfig' : "", + 'basicAuthEnable' : true, + 'basicAuthUsers' : {}, 'heapSize' : 512, 'minHeapSize' : 0, 'directoryBrowsing' : true, From 7479d52609ffa0e10f1531747de9cabeae33fa2f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 24 Apr 2017 11:10:41 -0500 Subject: [PATCH 026/123] COMMANDBOX-608 --- src/cfml/system/BaseCommand.cfc | 4 +- src/cfml/system/endpoints/ForgeBox.cfc | 22 ++-- .../commands/forgebox/search.cfc | 4 +- .../commands/forgebox/show.cfc | 13 +- .../commands/forgebox/slugcheck.cfc | 3 +- .../commands/forgebox/types.cfc | 5 +- .../commands/package/install.cfc | 3 +- .../server-commands/commands/server/start.cfc | 4 +- src/cfml/system/util/ForgeBox.cfc | 115 +++++++++++------- 9 files changed, 109 insertions(+), 64 deletions(-) diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index d9c3165eb..c9d68fa6d 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -24,15 +24,15 @@ component accessors="true" singleton { * Constructor */ function init() { - var wirebox = application.wirebox; + variables.wirebox = application.wirebox; variables.CR = wirebox.getInstance( "CR@constants" ); variables.formatterUtil = wirebox.getInstance( "Formatter" ); variables.fileSystemUtil = wirebox.getInstance( "FileSystem" ); variables.shell = wirebox.getInstance( "shell" ); variables.print = wirebox.getInstance( "PrintBuffer" ); - variables.wirebox = wirebox; variables.logger = wirebox.getLogBox().getLogger( this ); variables.parser = wirebox.getInstance( "Parser" ); + variables.configService = wirebox.getInstance( "ConfigService" ); hasErrored = false; return this; diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 1fa192406..91dc0c1ea 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -73,12 +73,13 @@ component accessors="true" implements="IEndpointInteractive" singleton { * @return struct { isOutdated, version } */ public function getUpdate( required string package, required string version, boolean verbose=false ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); var slug = parseSlug( arguments.package ); var boxJSONversion = parseVersion( arguments.package ); var result = { - isOutdated = false, - version = '' - }; + isOutdated = false, + version = '' + }; // Only bother checking if we have a version range. If an exact version is stored in // box.json, we're never going to update it anyway. @@ -89,7 +90,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { try { // Verify in ForgeBox - var entryData = forgebox.getEntry( slug ); + var entryData = forgebox.getEntry( slug, APIToken ); } catch( forgebox var e ) { // This can include "expected" errors such as "Email already in use" @@ -140,6 +141,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { required string firstName, required string lastName ){ + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); try { @@ -148,7 +150,8 @@ component accessors="true" implements="IEndpointInteractive" singleton { password = arguments.password, email = arguments.email, FName = arguments.firstName, - LName = arguments.lastName + LName = arguments.lastName, + APIToken = APIToken ); return results.APIToken; @@ -271,9 +274,10 @@ component accessors="true" implements="IEndpointInteractive" singleton { * @entryData Optional struct of entryData which skips the ForgeBox call. */ function findSatisfyingVersion( required string slug, required string version, struct entryData ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); try { // Use passed in entrydata, or go get it from ForgeBox. - arguments.entryData = arguments.entryData ?: forgebox.getEntry( arguments.slug ); + arguments.entryData = arguments.entryData ?: forgebox.getEntry( arguments.slug, APIToken ); } catch( forgebox var e ) { // This can include "expected" errors such as "User not authenticated" throw( e.message, 'endpointException', e.detail ); @@ -330,11 +334,13 @@ component accessors="true" implements="IEndpointInteractive" singleton { */ private function getPackage( slug, version, verbose=false ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); + try { // Info consoleLogger.warn( "Verifying package '#slug#' in ForgeBox, please wait..." ); - var entryData = forgebox.getEntry( slug ); + var entryData = forgebox.getEntry( slug, APIToken ); // Verbose info if( arguments.verbose ){ @@ -359,7 +365,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { consoleLogger.info( "Installing version [#arguments.version#]." ); try { - forgeBox.recordInstall( arguments.slug, arguments.version ); + forgeBox.recordInstall( arguments.slug, arguments.version, APIToken ); } catch( forgebox var e ) { consoleLogger.warn( e.message & CR & e.detail ); } diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc index 5a93a2bc1..c518272f7 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc @@ -23,8 +23,10 @@ component { try { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); + // Get the entries - var entries = forgebox.getEntries( searchTerm = arguments.searchText ); + var entries = forgebox.getEntries( searchTerm = arguments.searchText, APIToken=APIToken ); // entrylink,createdate,lname,isactive,installinstructions,typename,version,hits,coldboxversion,sourceurl,slug,homeurl,typeslug, // downloads,entryid,fname,changelog,updatedate,downloadurl,title,entryrating,summary,username,description diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc index 55f8a0e8d..9c453fcee 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc @@ -58,6 +58,7 @@ component aliases="show" { number maxRows, slug ){ + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); print.yellowLine( "Contacting ForgeBox, please wait..." ).toConsole(); @@ -83,7 +84,7 @@ component aliases="show" { // If there's not a slug supplied, see if that works if( !len( slug ) ) { try { - var entryData = forgebox.getEntry( orderBy ); + var entryData = forgebox.getEntry( orderBy, APIToken ); slug = orderBy; } catch( any e ) { if( e.detail contains 'The entry slug sent is invalid' ) { @@ -118,7 +119,7 @@ component aliases="show" { if( len( slug ) ) { // We might have gotten this above - var entryData = entryData ?: forgebox.getEntry( slug ); + var entryData = entryData ?: forgebox.getEntry( slug, APIToken ); // numberOfRatings,boxjson,isActive,typeName,version,hits,sourceURL,slug,createdDate,typeSlug,downloads,updatedDate,entryID, // ratings,versions,avgRating,downloadURL,changelog,installs,title,user,description,summary,homeURL if( !entryData.isActive ) { @@ -183,7 +184,7 @@ component aliases="show" { // List of entries } else { // Get the entries - var entries = forgebox.getEntries( orderBy, maxRows, startRow, typeLookup ); + var entries = forgebox.getEntries( orderBy=orderBy, maxRows=maxRows, startRow=startRow, typeSlug=typeLookup, APIToken=APIToken ); // entrylink,createdate,lname,isactive,installinstructions,typename,version,hits,coldboxversion,sourceurl,slug,homeurl,typeslug, // downloads,entryid,fname,changelog,updatedate,downloadurl,title,entryrating,summary,username,description @@ -218,10 +219,11 @@ component aliases="show" { // Auto-complete function lookupType( type ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); var typeLookup = ''; // See if they entered a type name or slug - for( var thistype in forgebox.getCachedTypes() ) { + for( var thistype in forgebox.getCachedTypes( APIToken=APIToken ) ) { if( thisType.typeName == type || thisType.typeSlug == type ) { typeLookup = thisType.typeSlug; break; @@ -235,9 +237,10 @@ component aliases="show" { // Auto-complete list of types function typeComplete( result = [] ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); // Loop over types and append all active ForgeBox entries - for( var thistype in forgebox.getCachedTypes() ) { + for( var thistype in forgebox.getCachedTypes( APIToken=APIToken ) ) { arguments.result.append( thisType.typeSlug ); } diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc index 68c960ba3..b8273cf14 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc @@ -16,12 +16,13 @@ component { * @slug.hint The slug to verify in ForgeBox */ function run( required slug ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); if( !len( arguments.slug ) ) { return error( "Slug cannot be an empty string" ); } - var exists = forgebox.isSlugAvailable( arguments.slug ); + var exists = forgebox.isSlugAvailable( arguments.slug, APIToken ); if( exists ){ print.greenBoldLine( "The slug '#arguments.slug#' does not exist in ForgeBox and can be used!" ); diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc index 8c4fe5d9f..60511a798 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc @@ -15,7 +15,8 @@ component { /** * Run Command */ - function run( ) { + function run() { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); // typetotal,typename,typeid,typeslug print.line() @@ -23,7 +24,7 @@ component { .line() .blackOnWhiteLine( 'Name(Number of Packages) (slug)' ); - for( var type in forgeBox.getCachedTypes() ) { + for( var type in forgeBox.getCachedTypes( APIToken=APIToken ) ) { print.boldText( type.typeName & "(#type.numberOfActiveEntries#)" ) .line( ' (#type.typeSlug#)' ); } diff --git a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc index 163cf4da2..ec0ed9452 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc @@ -158,8 +158,9 @@ component aliases="install" { return []; } try { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); // Get auto-complete options - return forgebox.slugSearch( arguments.paramSoFar ); + return forgebox.slugSearch( paramSoFar=arguments.paramSoFar, APIToken=APIToken ); } catch( forgebox var e ) { // Gracefully handle ForgeBox issues print diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index ed306e14a..f12963f21 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -161,9 +161,11 @@ component aliases="start" { */ function cfengineNameComplete( string paramSoFar ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); + try { // Get auto-complete options - return forgebox.slugSearch( arguments.paramSoFar, 'cf-engines' ); + return forgebox.slugSearch( arguments.paramSoFar, 'cf-engines', APIToken ); } catch( forgebox var e ) { // Gracefully handle ForgeBox issues print diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 637d538c7..4dc0bd56b 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -61,11 +61,16 @@ or just add DEBUG to the root logger + var results = ""; // Invoke call - results = makeRequest(resource="types"); + results = makeRequest( + resource="types", + headers = { + 'x-api-token' : arguments.APIToken + } ); // error if( results.response.error ){ @@ -79,9 +84,10 @@ or just add DEBUG to the root logger + if( isSimpleValue( variables.types ) OR arguments.force ){ - variables.types = getTypes(); + variables.types = getTypes( APIToken ); } return variables.types; @@ -95,6 +101,7 @@ or just add DEBUG to the root logger + var results = ""; var params = { @@ -106,7 +113,12 @@ or just add DEBUG to the root logger }; // Invoke call - results = makeRequest(resource="entries",parameters=params); + results = makeRequest( + resource="entries", + parameters=params, + headers = { + 'x-api-token' : arguments.APIToken + }); // error if( results.response.error ){ throw( "Error making ForgeBox REST Call", 'forgebox', results.response.messages.toList() ); @@ -119,11 +131,16 @@ or just add DEBUG to the root logger + var results = ""; // Invoke call - results = makeRequest(resource="entry/#arguments.slug#"); + results = makeRequest( + resource="entry/#arguments.slug#", + headers = { + 'x-api-token' : arguments.APIToken + }); // error if( results.response.error ){ @@ -137,11 +154,16 @@ or just add DEBUG to the root logger + var results = ""; // Invoke call - results = makeRequest(resource="slug-check/#arguments.slug#"); + results = makeRequest( + resource="slug-check/#arguments.slug#", + headers = { + 'x-api-token' : arguments.APIToken + }); // error if( results.response.error ){ @@ -152,35 +174,6 @@ or just add DEBUG to the root logger - - - - - - - - - - - - - - - - - /** @@ -191,9 +184,16 @@ or just add DEBUG to the root logger required string password, required string email, required string fName, - required string lName ) { + required string lName, + string APIToken='' ) { - var results = makeRequest( resource="register", parameters=arguments, method='post' ); + var results = makeRequest( + resource="register", + parameters=arguments, + method='post', + headers = { + 'x-api-token' : arguments.APIToken + } ); // error if( results.response.error ){ @@ -208,7 +208,12 @@ or just add DEBUG to the root logger */ function whoami( required string APIToken ) { - var results = makeRequest( resource="users/whoami/#APIToken#", method='get' ); + var results = makeRequest( + resource="users/whoami/#APIToken#", + method='get', + headers = { + 'x-api-token' : arguments.APIToken + } ); // error if( results.response.error ){ @@ -310,14 +315,21 @@ or just add DEBUG to the root logger */ function recordInstall( required string slug, - string version='' ) { + string version='', + string APIToken='' ) { var thisResource = "install/#arguments.slug#"; if( len( arguments.version ) ) { thisResource &= "/#arguments.version#"; } - var results = makeRequest( resource=thisResource, method='post' ); + var results = makeRequest( + resource=thisResource, + method='post', + headers = { + 'x-api-token' : arguments.APIToken + } + ); // error if( results.response.error ){ @@ -332,14 +344,20 @@ or just add DEBUG to the root logger */ function recordDownload( required string slug, - string version ) { + string version, + string APIToken='' ) { var thisResource = "install/#arguments.slug#"; if( len( arguments.version ) ) { thisResource &= "/#arguments.version#"; } - var results = makeRequest( resource=thisResource, method='post' ); + var results = makeRequest( + resource=thisResource, + method='post', + headers = { + 'x-api-token' : arguments.APIToken + } ); // error if( results.response.error ){ @@ -353,11 +371,22 @@ or just add DEBUG to the root logger /** * Autocomplete for slugs */ - function slugSearch( required string searchTerm, string typeSlug = '' ) { + function slugSearch( + required string searchTerm, + string typeSlug = '', + string APIToken='' ) { var thisResource = "slugs/#arguments.searchTerm#"; - var results = makeRequest( resource=thisResource, method='get', parameters={ typeSlug : arguments.typeSlug } ); + var results = makeRequest( + resource=thisResource, + method='get', + parameters={ + typeSlug : arguments.typeSlug + }, + headers = { + 'x-api-token' : arguments.APIToken + } ); // error if( results.response.error ){ From a18e004eee3d3aca748ca33a2fcf80f45a3b02ff Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 24 Apr 2017 11:33:52 -0500 Subject: [PATCH 027/123] COMMANDBOX-608 --- .../modules_app/package-commands/commands/package/install.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc index ec0ed9452..b16955a54 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc @@ -160,7 +160,7 @@ component aliases="install" { try { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); // Get auto-complete options - return forgebox.slugSearch( paramSoFar=arguments.paramSoFar, APIToken=APIToken ); + return forgebox.slugSearch( searchTerm=arguments.paramSoFar, APIToken=APIToken ); } catch( forgebox var e ) { // Gracefully handle ForgeBox issues print From ee1a5abb7af4f94d6b62f981f781a67b88a3aa4c Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 25 Apr 2017 15:40:52 -0500 Subject: [PATCH 028/123] Missing doc --- .../modules_app/coldbox-commands/commands/coldbox/reinit.cfc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc index 1f9ad00b8..b310185dd 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc @@ -17,7 +17,8 @@ component aliases="fwreinit" { property name="formatter" inject="formatter"; /** - * @password.hint The FWReinit password + * @password The FWReinit password + * @name Name of the CommandBox server to reinit **/ function run( password="1", name="" ){ var serverInfo = serverService.getServerInfoByDiscovery( getCWD(), arguments.name ); From cfe868baf6b7229539883ce60174019aa1ea87a0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 25 Apr 2017 15:45:30 -0500 Subject: [PATCH 029/123] Typo --- .../package-commands/commands/endpoint/unpublish.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc b/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc index 61f09be9f..e81985e1d 100644 --- a/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc @@ -28,7 +28,7 @@ component { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); var boxJSON = packageService.readPackageDescriptor( arguments.directory ); - if( !arguments.force && !confirm( 'Are you sure you want to unpublish? This is descrtuctive and can''t be undone.' ) ) { + if( !arguments.force && !confirm( 'Are you sure you want to unpublish? This is destructive and can''t be undone. (y/n)' ) ) { error( 'Cancelled!' ); } From 9e5832de39a7022cdda260ca5601ce800a686274 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 26 Apr 2017 09:33:40 -0500 Subject: [PATCH 030/123] Bump for new runwar version --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 2237a9469..49655d22b 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.4.8 +cfml.loader.version=1.4.9 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 From 55ba142f4d79eb3463f097f5cc74cec444ea3156 Mon Sep 17 00:00:00 2001 From: coldwell Date: Sat, 29 Apr 2017 10:51:37 -0500 Subject: [PATCH 031/123] https://english.stackexchange.com/questions/56480/difference-between-uncompress-and-decompress (#120) I blame @lmajano - I think he wrote that line, lol. Nice work @coldwell --- src/cfml/system/endpoints/File.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/endpoints/File.cfc b/src/cfml/system/endpoints/File.cfc index 975cc1df0..3e5b1edf9 100644 --- a/src/cfml/system/endpoints/File.cfc +++ b/src/cfml/system/endpoints/File.cfc @@ -37,7 +37,7 @@ component accessors="true" implements="IEndpoint" singleton { var packagePath = fileSystemUtil.resolvePath( "#variables.tempDir#/#createUUID()#" ); // Unzip to temp directory - consoleLogger.info( "Uncompressing..."); + consoleLogger.info( "Decompressing..."); zip action="unzip" file="#package#" destination="#packagePath#" overwrite="true"; From a3a7aaa92353d15a6cda8157e572259503ff6600 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 2 May 2017 18:09:08 -0500 Subject: [PATCH 032/123] COMMANDBOX-610 #resolve Finalize box.json testbox runner options --- .../testbox-commands/commands/testbox/run.cfc | 81 ++++++++++++------- .../models/TestingService.cfc | 64 +++++++++++++++ src/cfml/system/services/PackageService.cfc | 42 ---------- 3 files changed, 114 insertions(+), 73 deletions(-) create mode 100644 src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index 78d0000ee..bef5b605a 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -15,29 +15,28 @@ component { // DI property name="packageService" inject="PackageService"; + property name="testingService" inject="TestingService@testbox-commands"; /** * Ability to execute TestBox tests - * @runner.hint The URL or shortname of the runner to use, if it uses a short name we look in your box.json - * @bundles.hint The path or list of paths of the spec bundle CFCs to run and test - * @directory.hint The directory mapping to test: directory = the path to the directory using dot notation (myapp.testing.specs) - * @recurse.hint Recurse the directory mapping or not, by default it does - * @reporter.hint The type of reporter to use for the results, by default is uses our 'simple' report. You can pass in a core reporter string type or a class path to the reporter to use. - * @reporterOptions.hint A JSON struct literal of options to pass into the reporter - * @labels.hint The list of labels that a suite or spec must have in order to execute. - * @options.hint A JSON struct literal of configuration options that are optionally used to configure a runner. - * @testBundles.hint A list or array of bundle names that are the ones that will be executed ONLY! - * @testSuites.hint A list of suite names that are the ones that will be executed ONLY! - * @testSpecs.hint A list of test names that are the ones that will be executed ONLY! - * @outputFile.hint We will store the results in this output file as well as presenting it to you. + * @runner The URL or shortname of the runner to use, if it uses a short name we look in your box.json + * @bundles The path or list of paths of the spec bundle CFCs to run and test + * @directory The directory mapping to test: directory = the path to the directory using dot notation (myapp.testing.specs) + * @recurse Recurse the directory mapping or not, by default it does + * @reporter The type of reporter to use for the results, by default is uses our 'simple' report. You can pass in a core reporter string type or a class path to the reporter to use. + * @labels The list of labels that a suite or spec must have in order to execute. + * @options A JSON struct literal of configuration options that are optionally used to configure a runner. + * @testBundles A list or array of bundle names that are the ones that will be executed ONLY! + * @testSuites A list of suite names that are the ones that will be executed ONLY! + * @testSpecs A list of test names that are the ones that will be executed ONLY! + * @outputFile We will store the results in this output file as well as presenting it to you. **/ function run( string runner="", string bundles, string directory, - boolean recurse=true, - string reporter="text", - string reporterOptions, + boolean recurse, + string reporter="", string labels, string options, string testBundles, @@ -45,13 +44,14 @@ component { string testSpecs, string outputFile ){ - var runnerURL = ''; - // If a URL is passed, used it + var runnerURL = ''; + + // If a URL is passed, used it as an override if( left( arguments.runner, 4 ) == 'http' ) { runnerURL = arguments.runner; // Otherwise, try to get one from box.json } else { - runnerURL = packageService.getTestBoxRunner( getCWD(), arguments.runner ); + runnerURL = testingService.getTestBoxRunner( getCWD(), arguments.runner ); // Validate runner if( !len( runnerURL ) ){ return error( '(#arguments.runner#) it not a valid runner in your box.json. Runners found are: #packageService.readPackageDescriptor( getCWD() ).testbox.runner.toString()#' ); @@ -63,20 +63,39 @@ component { return error( '[#runnerURL#] it not a valid URL, or does not match a runner slug in your box.json.' ); } - var testboxURL = runnerURL & "?recurse=#arguments.recurse#&reporter=#arguments.reporter#"; - // Do we have bundles - if( !isNull( arguments.bundles ) ){ testboxURL &= "&bundles=#arguments.bundles#"; } - // Do we have directory - if( !isNull( arguments.bundles ) ){ testboxURL &= "&directory=#arguments.directory#"; } - // Do we have labels - if( !isNull( arguments.labels ) ){ testboxURL &= "&labels=#arguments.labels#"; } - // Do we have testBundles - if( !isNull( arguments.testBundles ) ){ testboxURL &= "&testBundles=#arguments.testBundles#"; } - // Do we have testSuites - if( !isNull( arguments.testSuites ) ){ testboxURL &= "&labels=#arguments.testSuites#"; } - // Do we have testSpecs - if( !isNull( arguments.testSpecs ) ){ testboxURL &= "&labels=#arguments.testSpecs#"; } + // Default runner builder + var testboxURL = runnerURL & "?"; + // Runner options overridable by arguments and box options + var RUNNER_OPTIONS = { + "reporter" : "text", + "recurse" : true, + "bundles" : "", + "directory" : "", + "labels" : "", + "testBundles" : "", + "testSuites" : "", + "testSpecs" : "" + }; + + // Get testbox options from package descriptor + var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox; + // Build out runner options + for( var thisOption in RUNNER_OPTIONS ){ + // Check argument overrides + if( !isNull( arguments[ thisOption ] ) && len( arguments[ thisOption ] ) ){ + testboxURL &= "&#thisOption#=#arguments[ thisOption ]#"; + } + // Check runtime options now + else if( boxOptions.keyExists( thisOption ) && len( boxOptions[ thisOption ]) ){ + testboxURL &= "&#thisOption#=#boxOptions[ thisOption ]#"; + } + // Defaults + else if( len( RUNNER_OPTIONS[ thisOption ] ) ) { + testboxURL &= "&#thisOption#=#RUNNER_OPTIONS[ thisOption ]#"; + } + } + // Advice we are running print.boldCyanLine( "Executing tests via #testBoxURL#, please wait..." ) .blinkingRed( "Please wait...") diff --git a/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc b/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc new file mode 100644 index 000000000..222f2e62a --- /dev/null +++ b/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc @@ -0,0 +1,64 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I handle working with TestBox +*/ +component accessors="true" singleton { + + // DI + property name="packageService" inject="PackageService"; + + /** + * Constructor + */ + function init(){ + return this; + } + + /** + * Gets a TestBox runner URL from box.json with an optional slug to look up. If no slug is passed, the first runner will be used + * @directory The directory that is the root of the package + * @slug An optional runner slug to look for in the list of runners + */ + public function getTestBoxRunner( required string directory, string slug='' ) { + // Get box.json, create empty if it doesn't exist + var boxJSON = packageService.readPackageDescriptor( arguments.directory ); + // Get reference to appropriate depenency struct + var runners = boxJSON.testbox.runner; + var runnerURL = ''; + + // If there is a slug and runners is an array, look it up + if ( len( arguments.slug ) && isArray( runners ) ){ + for( var thisRunner in runners ){ + // Does the string passed in match the slug of this runner? If so, return it + if( structKeyExists( thisRunner, arguments.slug ) ) { + return thisRunner[ arguments.slug ]; + } + } + // If we got here, we could not find slug, advice back with an empty runner + return ''; + } + + // Just get the first one we can find + + // simple runner? + if( isSimpleValue( runners ) ){ + return runners; + } + + // Array of runners? + if( isArray( runners ) ) { + // get the first definition in the list to use + var firstRunner = runners[ 1 ]; + return firstRunner[ listFirst( structKeyList( firstRunner ) ) ]; + } + + // We failed to find anything + return ''; + } + +} \ No newline at end of file diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 1684e374a..5c9a15b6a 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -782,48 +782,6 @@ component accessors="true" singleton { } } - /** - * Gets a TestBox runner URL from box.json with an optional slug to look up. If no slug is passed, the first runner will be used - * @directory The directory that is the root of the package - * @slug An optional runner slug to look for in the list of runners - */ - public function getTestBoxRunner( required string directory, string slug='' ) { - // Get box.json, create empty if it doesn't exist - var boxJSON = readPackageDescriptor( arguments.directory ); - // Get reference to appropriate depenency struct - var runners = boxJSON.testbox.runner; - var runnerURL = ''; - - // If there is a slug and runners is an array, look it up - if ( len( arguments.slug ) && isArray( runners ) ){ - for( var thisRunner in runners ){ - // Does the string passed in match the slug of this runner? If so, return it - if( structKeyExists( thisRunner, arguments.slug ) ) { - return thisRunner[ arguments.slug ]; - } - } - // If we got here, we could not find slug, advice back with an empty runner - return ''; - } - - // Just get the first one we can find - - // simple runner? - if( isSimpleValue( runners ) ){ - return runners; - } - - // Array of runners? - if( isArray( runners ) ) { - // get the first definition in the list to use - var firstRunner = runners[ 1 ]; - return firstRunner[ listFirst( structKeyList( firstRunner ) ) ]; - } - - // We failed to find anything - return ''; - } - /** * Get the default package description, AKA box.json * @defaults A struct of default values to be merged into the empty, default document From db55a7a4bbc4df6f930c76c722866df7be69833f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 3 May 2017 00:21:23 -0500 Subject: [PATCH 033/123] COMMANDBOX-610 More testbox defaults --- src/cfml/system/config/box.json.txt | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/cfml/system/config/box.json.txt b/src/cfml/system/config/box.json.txt index f2a6fb60e..cd21edbc4 100644 --- a/src/cfml/system/config/box.json.txt +++ b/src/cfml/system/config/box.json.txt @@ -37,16 +37,15 @@ runner : [ { "default": "" } ], - labels : [], - reporter :"", - reporterResults : "", - bundles :[ "" ], - directory: { mapping : "", recurse: true }, - watchers :[], - notify : { - emails : [], - growl : "", - URL : "" - } + "labels" : "", + "reporter : "", + "bundles" : "test.specs", + "recurse" : true, + "directory" : "", + "testBundles" : "", + "testSuites" : "", + "testSpecs" : "", + "Watchers" : [] + } } \ No newline at end of file From aed9c3aba19c53b3080fc251f94672250a12d2d0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 00:29:52 -0500 Subject: [PATCH 034/123] Luis missed a double quote --- src/cfml/system/config/box.json.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/config/box.json.txt b/src/cfml/system/config/box.json.txt index cd21edbc4..bf32743b2 100644 --- a/src/cfml/system/config/box.json.txt +++ b/src/cfml/system/config/box.json.txt @@ -38,7 +38,7 @@ { "default": "" } ], "labels" : "", - "reporter : "", + "reporter" : "", "bundles" : "test.specs", "recurse" : true, "directory" : "", From e2d49deb2c6164c159773a7069feb23b96e405a4 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 01:24:50 -0500 Subject: [PATCH 035/123] Initial watcher implementation --- src/cfml/system/util/Watch.cfc | 188 +++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/cfml/system/util/Watch.cfc diff --git a/src/cfml/system/util/Watch.cfc b/src/cfml/system/util/Watch.cfc new file mode 100644 index 000000000..0b2521e83 --- /dev/null +++ b/src/cfml/system/util/Watch.cfc @@ -0,0 +1,188 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I am a watcher that will run code any time files in a directory change. +* I am intended to be used as a transient. Create a new instance of me for each watch operation. +*/ +component accessors=true { + // DI + property name='shell' inject='shell'; + property name='print' inject='PrintBuffer'; + property name='pathPatternMatcher' inject='provider:pathPatternMatcher@globber'; + property name='fileSystemUtil' inject='FileSystem'; + + // Properties + property name='changeHash' type='string'; + property name='watcherRun' type='boolean'; + property name='pathsToWatch' type='array'; + property name='changeUDF' type='function'; + property name='baseDirectory' type='string'; + property name='delayMS' type='number'; + + function onDIComplete() { + setBaseDirectory( shell.pwd() ); + setDelayMS( 500 ); + // Watch all files recursivley by default + setPathsToWatch( [ '**' ] ); + } + + /** + * Pass in an array of file globbing paths or any numberof string globbing arguments. + */ + public function paths() { + setPathsToWatch( [] ); + for( var arg in arguments ) { + var thisPattern = arguments[ arg ]; + pathsToWatch.append( thisPattern, isArray( thisPattern ) ); + } + } + + /** + * Pass in the base directory that the globbing patterns are relative to + */ + public function inDirectory( baseDirectory ) { + setBaseDirectory( arguments.baseDirectory ); + } + + /** + * Pass in the number of miliseconds to wait between polls + */ + public function withDelay( delayMS ) { + setDelayMS( arguments.delayMS ); + } + + /** + * Pass in a UDF refernce to be executed when the watcher senses a chnage on the file system + */ + public function onChange( changeUDF ) { + setChangeUDF( arguments.changeUDF ); + } + + /** + * Call to start the watcher. This method will block until the user ends it with Ctrl+C + */ + public function start() { + + setChangeHash( calculateHashes() ); + setWatcherRun( true ); + + print + .line() + .boldRedLine( "Watching Files..." ) + .toConsole(); + + try { + var threadName = 'watcher#createUUID()#'; + thread action="run" name="#threadname#" priority="HIGH"{ + try{ + // Run until we exit out of the watcher + while( getWatcherRun() ){ + // Verify if we have a change + if( changeDetected() ){ + + // Fire onChange listener + var thisChangeUDF = getChangeUDF(); + thisChangeUDF(); + + } else { + // Sleep and test again. + sleep( getDelayMS() ); + } + } + } catch( any e ) { + // Print out error message from exception and continue watching + print.printRedBoldLine( "An exception has ocurred: #e.message# #e.detail#" ) + .line( e.stacktrace ) + .line() + .printGreenLine( "Starting watcher again..." ) + .line() + .toConsole(); + } + } // end thread + + while( true ){ + // Wipe out prompt so it doesn't redraw if the user hits enter + shell.getReader().setPrompt( '' ); + // Detect user pressing Ctrl-C + // Any other characters captured will be ignored + var line = shell.getReader().readLine(); + if( line == 'q' ) { + break; + } else { + print + .boldGreenLine( 'To exit press Ctrl-C or "q" followed the enter key.' ) + .toConsole(); + } + } + + + // user wants to exit, they've pressed Ctrl-C + } catch ( jline.console.UserInterruptException e ) { + + print + .printLine( "" ) + .printBoldRedLine( "Stopping..." ) + .toConsole(); + + // make sure the thread exits + setWatcherRun( false ); + // Wait until the thread finishes its last draw + thread action="join" name=threadName; + // Something horrible went wrong + } catch ( any e ) { + // make sure the thread exits + setWatcherRun( false ); + // Wait until the thread finishes its last draw + thread action="join" name=threadName; + rethrow; + } finally{ + shell.setPrompt(); + } + + // make sure the thread exits + setWatcherRun( false ); + // Wait until the thread finishes + thread action="join" name=threadName; + + } + + + private function calculateHashes() { + var globPatterns = getPathsToWatch(); + var thisBaseDir = fileSystemUtil.resolvePath( getBaseDirectory() ); + + var fileListing = directoryList( + thisBaseDir, + true, + "query", + function( path ) { + // This will normalize the slashes to match + arguments.path = fileSystemUtil.resolvePath( arguments.path ); + + // cleanup path so we just get what's inside the base dir + var thisPath = replacenocase( arguments.path, thisBaseDir, "" ); + + // Does this path match one of our glob patterns + return pathPatternMatcher.matchPatterns( globPatterns, thisPath ); + }, + "DateLastModified desc" ); + + var directoryHash = hash( serializeJSON( fileListing ) ); + + return directoryHash; + } + + private function changeDetected() { + var newHash = calculateHashes(); + if( getChangeHash() == newHash ){ + return false; + } + setChangeHash( newHash ); + return true; + } + +} \ No newline at end of file From b838ed1deae8ba4fd03b268ecf4d7e96bb419427 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 01:29:02 -0500 Subject: [PATCH 036/123] Check for UDF --- src/cfml/system/util/Watch.cfc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cfml/system/util/Watch.cfc b/src/cfml/system/util/Watch.cfc index 0b2521e83..57aeeab83 100644 --- a/src/cfml/system/util/Watch.cfc +++ b/src/cfml/system/util/Watch.cfc @@ -67,6 +67,10 @@ component accessors=true { */ public function start() { + if( isNull( getChangeUDF() ) ) { + throw( "No onChange UDF specified. There's nothing to do!" ); + } + setChangeHash( calculateHashes() ); setWatcherRun( true ); From 9d2a9326caee223e5aa92f7ab3482c0706b442ec Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 16:12:44 -0500 Subject: [PATCH 037/123] Add conventinence method for watch() --- src/cfml/system/BaseCommand.cfc | 7 +++++++ .../testbox-commands/commands/testbox/watch.cfc | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index c9d68fa6d..4b92aec5b 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -113,6 +113,13 @@ component accessors="true" singleton { function command( required name ) { return getinstance( name='CommandDSL', initArguments={ name : arguments.name } ); } + + /** + * Create a directory watcher. Call its DSL to configure it. + **/ + function watch() { + return getinstance( 'watch' ); + } /** * Use if if your command wants to give controlled feedback to the user without raising diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index dce2a8c4e..bc2c79186 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -7,7 +7,14 @@ component { * **/ function run( ) { - print.line( "Command not implemented!" ); + watch() + .paths( '**.cfc' ) + .inDirectory( getCWD() ) + .onChange( function() { + command( 'testbox run' ) + .run(); + } ) + .start(); } } \ No newline at end of file From e04c32510e0912df975fdabe39a9402d67560650 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 16:14:48 -0500 Subject: [PATCH 038/123] Chainability --- src/cfml/system/util/Watch.cfc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cfml/system/util/Watch.cfc b/src/cfml/system/util/Watch.cfc index 57aeeab83..998f52241 100644 --- a/src/cfml/system/util/Watch.cfc +++ b/src/cfml/system/util/Watch.cfc @@ -39,6 +39,7 @@ component accessors=true { var thisPattern = arguments[ arg ]; pathsToWatch.append( thisPattern, isArray( thisPattern ) ); } + return this; } /** @@ -46,6 +47,7 @@ component accessors=true { */ public function inDirectory( baseDirectory ) { setBaseDirectory( arguments.baseDirectory ); + return this; } /** @@ -53,6 +55,7 @@ component accessors=true { */ public function withDelay( delayMS ) { setDelayMS( arguments.delayMS ); + return this; } /** @@ -60,6 +63,7 @@ component accessors=true { */ public function onChange( changeUDF ) { setChangeUDF( arguments.changeUDF ); + return this; } /** @@ -152,6 +156,7 @@ component accessors=true { // Wait until the thread finishes thread action="join" name=threadName; + return this; } From dc7e2f909e41519eca87e5792b0ce10088a135c2 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 16:16:32 -0500 Subject: [PATCH 039/123] Rename watcher --- src/cfml/system/BaseCommand.cfc | 2 +- src/cfml/system/util/{Watch.cfc => Watcher.cfc} | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) rename src/cfml/system/util/{Watch.cfc => Watcher.cfc} (96%) diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index 4b92aec5b..b55d338ea 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -118,7 +118,7 @@ component accessors="true" singleton { * Create a directory watcher. Call its DSL to configure it. **/ function watch() { - return getinstance( 'watch' ); + return getinstance( 'watcher' ); } /** diff --git a/src/cfml/system/util/Watch.cfc b/src/cfml/system/util/Watcher.cfc similarity index 96% rename from src/cfml/system/util/Watch.cfc rename to src/cfml/system/util/Watcher.cfc index 998f52241..ff0981212 100644 --- a/src/cfml/system/util/Watch.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -7,6 +7,16 @@ * * I am a watcher that will run code any time files in a directory change. * I am intended to be used as a transient. Create a new instance of me for each watch operation. +* +* +* getIsntance( 'watcher' ) +* .paths( '**.cfc' ) +* .inDirectory( getCWD() ) +* .onChange( function() { +* command( 'testbox run' ) +* .run(); +* } ) +* .start(); */ component accessors=true { // DI From 797e616d5714b2b81fdf4172bb639586f507566b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 May 2017 22:23:17 -0500 Subject: [PATCH 040/123] Typo --- src/cfml/system/util/Watcher.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index ff0981212..dd794236b 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -9,7 +9,7 @@ * I am intended to be used as a transient. Create a new instance of me for each watch operation. * * -* getIsntance( 'watcher' ) +* getInstance( 'watcher' ) * .paths( '**.cfc' ) * .inDirectory( getCWD() ) * .onChange( function() { From 56503f9e7363d40d0176dbe2229c94021d9d9719 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 4 May 2017 11:50:40 -0500 Subject: [PATCH 041/123] COMMANDBOX-611 --- src/cfml/system/Shell.cfc | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index 3bd088554..5a31f763f 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -302,9 +302,7 @@ component accessors="true" singleton { * Get the temp dir in a safe manner */ string function getTempDir(){ - lock name="commandbox.tempdir" timeout="10" type="readOnly" throwOnTimeout="true"{ - return variables.tempDir; - } + return variables.tempDir; } /** @@ -312,31 +310,14 @@ component accessors="true" singleton { * @directory.hint directory to use **/ Shell function setTempDir( required directory ){ - lock name="commandbox.tempdir" timeout="10" type="exclusive" throwOnTimeout="true"{ - - // Delete temp dir - var clearTemp = directoryExists( arguments.directory ) ? directoryDelete( arguments.directory, true ) : ""; - - // Re-create it. Try 3 times. - var tries = 0; - try { - tries++; - directoryCreate( arguments.directory ); - } catch (any e) { - if( tries <= 3 ) { - variables.logger.info( 'Error creating temp directory [#arguments.directory#]. Trying again in 500ms.', 'Number of tries: #tries#' ); - // Wait 500 ms and try again. OS could be locking the dir - sleep( 500 ); - retry; - } else { - variables.logger.info( 'Error creating temp directory [#arguments.directory#]. Giving up now.', 'Tried #tries# times.' ); - printError( e ); - } - } - - // set now that it is created. - variables.tempdir = arguments.directory; - } + + // Create it if it's not there. + if( !directoryExists( arguments.directory ) ) { + directoryCreate( arguments.directory ); + } + + // set now that it is created. + variables.tempdir = arguments.directory; return this; } From 59c55bf4dcfc7a276fe446254f4f80e6ea83cb25 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 4 May 2017 16:10:40 -0500 Subject: [PATCH 042/123] COMMANDBOX-612 --- .../testbox-commands/commands/testbox/run.cfc | 64 +++++--- .../testbox-commands/models/CLIRenderer.cfc | 138 ++++++++++++++++++ 2 files changed, 182 insertions(+), 20 deletions(-) create mode 100644 src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index bef5b605a..8cc9a5dd1 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -16,6 +16,7 @@ component { // DI property name="packageService" inject="PackageService"; property name="testingService" inject="TestingService@testbox-commands"; + property name="CLIRenderer" inject="CLIRenderer@testbox-commands"; /** * Ability to execute TestBox tests @@ -30,6 +31,7 @@ component { * @testSuites A list of suite names that are the ones that will be executed ONLY! * @testSpecs A list of test names that are the ones that will be executed ONLY! * @outputFile We will store the results in this output file as well as presenting it to you. + * @verbose Display extra details inlcuding passing and skipped tests. **/ function run( string runner="", @@ -42,7 +44,8 @@ component { string testBundles, string testSuites, string testSpecs, - string outputFile + string outputFile, + boolean verbose=true ){ var runnerURL = ''; @@ -68,7 +71,7 @@ component { // Runner options overridable by arguments and box options var RUNNER_OPTIONS = { - "reporter" : "text", + "reporter" : "json", "recurse" : true, "bundles" : "", "directory" : "", @@ -96,10 +99,8 @@ component { } } - // Advice we are running + // Advise we are running print.boldCyanLine( "Executing tests via #testBoxURL#, please wait..." ) - .blinkingRed( "Please wait...") - .printLine() .toConsole(); // run it now baby! @@ -120,23 +121,46 @@ component { print.boldGreenLine( "Report written to #arguments.outputFile#!" ); } - results.fileContent = reReplace( trim( results.fileContent ), '[\r\n]+', CR, 'all' ); + results.fileContent = trim( results.fileContent ); - // Print accordingly to results - if( ( results.responseheader[ "x-testbox-totalFail" ] ?: 0 ) eq 0 AND - ( results.responseheader[ "x-testbox-totalError" ] ?: 0 ) eq 0 ){ - // print OK report - print.green( " " & results.filecontent ); - } else if( results.responseheader[ "x-testbox-totalFail" ] gt 0 ){ - // print Failure report - setExitCode( 1 ); - print.yellow( " " & results.filecontent ); - } else if( results.responseheader[ "x-testbox-totalError" ] gt 0 ){ - // print Failure report - setExitCode( 1 ); - print.boldRed( " " & results.filecontent ); - } + // Default is to template our own output based on a JSON reponse + if( RUNNER_OPTIONS.reporter == 'json' && isJSON( results.fileContent ) ) { + + var testData = deserializeJSON( results.fileContent ); + + // If any tests failed or errored. + if( testData.totalFail || testData.totalError ) { + // Send back failing exit code to shell + setExitCode( 1 ); + } + + CLIRenderer.render( print, testData, verbose ); + + //systemOutput( getINstance( 'formatter' ).formatJSON( testData ) ); + + // For all other reporters, just dump out whatever we got from the server + } else { + + results.fileContent = reReplace( results.fileContent, '[\r\n]+', CR, 'all' ); + // Print accordingly to results + if( ( results.responseheader[ "x-testbox-totalFail" ] ?: 0 ) eq 0 AND + ( results.responseheader[ "x-testbox-totalError" ] ?: 0 ) eq 0 ){ + // print OK report + print.green( " " & results.filecontent ); + } else if( results.responseheader[ "x-testbox-totalFail" ] gt 0 ){ + // print Failure report + setExitCode( 1 ); + print.yellow( " " & results.filecontent ); + } else if( results.responseheader[ "x-testbox-totalError" ] gt 0 ){ + // print Failure report + setExitCode( 1 ); + print.boldRed( " " & results.filecontent ); + } + + + } + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc new file mode 100644 index 000000000..fde597aa1 --- /dev/null +++ b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc @@ -0,0 +1,138 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I render TestBox data out for the CLI +*/ +component { + + variables.HEADER_CELL_CHARS = 7; + variables.COLOR = { + PASS : 'green', + SKIP : 'yellow', + ERROR : 'boldRed', + FAIL : 'boldRed', + NORMAL : 'NORMAL' + }; + + /** + * @print a print buffer to use + * @testData test results from TestBox + * @verbose Display information about passing and skipped specs + */ + function render( print, testData, verbose ) { + + var thisColor = getAggregatedColor( testData.totalError, testData.totalFail, 0 ); + print + .line("TestBox " & ( !isNull( testData.version ) ? "v#testData.version#" : "" ) ) + .line( "---------------------------------------------------------------------------------", thisColor ) + .line( "| Passed | Failed | Errored | Skipped | Time | Bundles | Suites | Specs |", thisColor ) + .line( "---------------------------------------------------------------------------------", thisColor ) + .line( "| #headerCell(testData.totalPass)# | #headerCell(testData.totalFail)# | #headerCell(testData.totalError)# | #headerCell(testData.totalSkipped)# | #headerCell(testData.totalDuration & ' ms')# | #headerCell(testData.totalBundles)# | #headerCell(testData.totalSuites)# | #headerCell(testData.totalSpecs)# |", thisColor ) + .line( "---------------------------------------------------------------------------------", thisColor); + + if ( arrayLen( testData.labels ) ) { + print.line("->[Labels Applied: #arrayToList( testData.labels )#]"); + } + var didPrint = false; + for ( thisBundle in testData.bundleStats ) { + + + if ( ( thisBundle.totalFail + thisBundle.totalError ) == 0 && !verbose) { + continue; + } + + var thisColor = getAggregatedColor( thisBundle.totalError, thisBundle.totalFail, 0 ); + print + .line("=================================================================================", thisColor ) + .line( "#thisBundle.path# (#thisBundle.totalDuration# ms) [Suites/Specs: #thisBundle.totalSuites#/#thisBundle.totalSpecs#]", thisColor ) + .line( "[Passed: #thisBundle.totalPass#] [Failed: #thisBundle.totalFail#] [Errors: #thisBundle.totalError#] [Skipped: #thisBundle.totalSkipped#]", thisColor ) + .line( "---------------------------------------------------------------------------------", thisColor); + + if ( !isSimpleValue( thisBundle.globalException ) ) { + + print.line("GLOBAL BUNDLE EXCEPTION", COLOR.ERROR ) + .line( "-> #thisBundle.globalException.type#:#thisBundle.globalException.message#:#thisBundle.globalException.detail#", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) + .line( "STACKTRACE", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) + .line( "#thisBundle.globalException.stacktrace#", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) + .line( "END STACKTRACE", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ); + } + for ( suiteStats in thisBundle.suiteStats ) { + didPrint = genSuiteReport( suiteStats, thisBundle, 0, print, verbose ); + } + } + + // Skip this redundant line if no specs printed above in the previous suite + if( didPrint ) { + print.line("---------------------------------------------------------------------------------" ); + } + print + .text( "Passed", COLOR.PASS ).text( " || " ) + .text( "Skipped", COLOR.SKIP ).text( " || " ) + .text( "Exception/Error", COLOR.ERROR ).text( " || " ) + .text( "Failure", COLOR.FAIL ) + .line(); + + } + + // Recursive Output + function genSuiteReport(suiteStats, bundleStats, level="0", print, verbose ) { + if ( ( arguments.suiteStats.totalFail + arguments.suiteStats.totalError ) == 0 && !verbose) { + return false; + } + var tabs = repeatString( " ", arguments.level ); + + print.line( "#tabs#+#arguments.suiteStats.name# #chr(13)#", getAggregatedColor( arguments.suiteStats.totalError, arguments.suiteStats.totalFail, ( arguments.suiteStats.status == 'skipped' ? 1 : 0 ) ) ); + + var printedAtLeastOneLine = false; + for ( local.thisSpec in arguments.suiteStats.specStats ) { + + if ( ListFindNoCase("failed,exception,error", local.thisSpec.status) == 0 && !verbose ) { + continue; + } + + printedAtLeastOneLine = true; + var thisColor = getAggregatedColor( ( local.thisSpec.status == "error" ? 1 : 0 ), ( local.thisSpec.status == "failed" ? 1 : 0 ), ( local.thisSpec.status == "skipped" ? 1 : 0 ) ); + print.line("#repeatString( " ", arguments.level+1 )##local.thisSpec.name# (#local.thisSpec.totalDuration# ms) #chr(13)#", thisColor ); + + if ( local.thisSpec.status == "failed" ) { + print.line("#repeatString( " ", arguments.level+2 )#-> Failure: #local.thisSpec.failMessage##chr(13)#", COLOR.FAIL ); + } + if ( local.thisSpec.status == "error" ) { + print.line("#repeatString( " ", arguments.level+2 )#-> Error: #local.thisSpec.error.message##chr(13)#", COLOR.ERROR ) + .line( "#repeatString( " ", arguments.level+2 )#-> Exception Trace: #local.thisSpec.error.stackTrace# #chr(13)##chr(13)#", COLOR.ERROR ); + } + } + if ( arrayLen( arguments.suiteStats.suiteStats ) ) { + for ( local.nestedSuite in arguments.suiteStats.suiteStats ) { + var didPrint = genSuiteReport( local.nestedSuite, arguments.bundleStats, arguments.level+1, print, verbose ) + printedAtLeastOneLine = printedAtLeastOneLine || didPrint; + } + } + return printedAtLeastOneLine; + } + + private function headerCell( text ) { + return Left( arguments.text & RepeatString( " ", HEADER_CELL_CHARS), HEADER_CELL_CHARS); + } + + private function getAggregatedColor( errors=0, failures=0, skips=0 ) { + if( errors ) { + return COLOR.ERROR; + } else if( failures ) { + return COLOR.FAIL; + } else if( skips ) { + return COLOR.SKIP; + } else{ + return COLOR.PASS; + } + } + +} \ No newline at end of file From 8478fa60cd2036ec3f87a76204032aca19af0f91 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 4 May 2017 16:19:49 -0500 Subject: [PATCH 043/123] COMMANDBOX-612 --- src/cfml/system/config/box.json.txt | 1 + .../modules_app/testbox-commands/commands/testbox/run.cfc | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/config/box.json.txt b/src/cfml/system/config/box.json.txt index bf32743b2..b0a50a3fa 100644 --- a/src/cfml/system/config/box.json.txt +++ b/src/cfml/system/config/box.json.txt @@ -45,6 +45,7 @@ "testBundles" : "", "testSuites" : "", "testSpecs" : "", + "verbose" : true, "Watchers" : [] } diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index 8cc9a5dd1..0d791c0b3 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -45,7 +45,7 @@ component { string testSuites, string testSpecs, string outputFile, - boolean verbose=true + boolean verbose ){ var runnerURL = ''; @@ -134,7 +134,7 @@ component { setExitCode( 1 ); } - CLIRenderer.render( print, testData, verbose ); + CLIRenderer.render( print, testData, arguments.verbose ?: boxOptions.verbose ?: true ); //systemOutput( getINstance( 'formatter' ).formatJSON( testData ) ); From da5486a6308a2eea9a4a0fb148b1e91da83b299b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 4 May 2017 21:13:26 -0500 Subject: [PATCH 044/123] Cleaned up CLI output for tests --- .../testbox-commands/commands/testbox/watch.cfc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index bc2c79186..6aec96541 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -7,12 +7,17 @@ component { * **/ function run( ) { + + // Clear screen + command( 'cls' ).run(); + + // Start watcher watch() .paths( '**.cfc' ) .inDirectory( getCWD() ) .onChange( function() { - command( 'testbox run' ) - .run(); + command( 'cls' ).run(); + command( 'testbox run' ).run(); } ) .start(); } From 4383ebfa0bb073fd79e91ddc96427053151d3baf Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 4 May 2017 21:13:35 -0500 Subject: [PATCH 045/123] Made pretty --- .../testbox-commands/models/CLIRenderer.cfc | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc index fde597aa1..777c800a2 100644 --- a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc +++ b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc @@ -14,8 +14,7 @@ component { PASS : 'green', SKIP : 'yellow', ERROR : 'boldRed', - FAIL : 'boldRed', - NORMAL : 'NORMAL' + FAIL : 'boldRed' }; /** @@ -50,7 +49,7 @@ component { .line("=================================================================================", thisColor ) .line( "#thisBundle.path# (#thisBundle.totalDuration# ms) [Suites/Specs: #thisBundle.totalSuites#/#thisBundle.totalSpecs#]", thisColor ) .line( "[Passed: #thisBundle.totalPass#] [Failed: #thisBundle.totalFail#] [Errors: #thisBundle.totalError#] [Skipped: #thisBundle.totalSkipped#]", thisColor ) - .line( "---------------------------------------------------------------------------------", thisColor); + .line( "---------------------------------------------------------------------------------", thisColor ); if ( !isSimpleValue( thisBundle.globalException ) ) { @@ -71,19 +70,23 @@ component { // Skip this redundant line if no specs printed above in the previous suite if( didPrint ) { - print.line("---------------------------------------------------------------------------------" ); + print.line("---------------------------------------------------------------------------------", thisColor ); + } + + if( verbose ) { + print + .text( "Passed", COLOR.PASS ).text( " || " ) + .text( "Skipped", COLOR.SKIP ).text( " || " ) + .text( "Exception/Error", COLOR.ERROR ).text( " || " ) + .text( "Failure", COLOR.FAIL ) + .line(); } - print - .text( "Passed", COLOR.PASS ).text( " || " ) - .text( "Skipped", COLOR.SKIP ).text( " || " ) - .text( "Exception/Error", COLOR.ERROR ).text( " || " ) - .text( "Failure", COLOR.FAIL ) - .line(); } // Recursive Output function genSuiteReport(suiteStats, bundleStats, level="0", print, verbose ) { + if ( ( arguments.suiteStats.totalFail + arguments.suiteStats.totalError ) == 0 && !verbose) { return false; } From 359ae7d40606cf563538b9956613afa954eb3eb5 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 5 May 2017 17:39:28 -0500 Subject: [PATCH 046/123] COMMANDBOX-613 --- src/cfml/system/util/CommandDSL.cfc | 33 ++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/util/CommandDSL.cfc b/src/cfml/system/util/CommandDSL.cfc index 64d7007e9..23f8689a9 100644 --- a/src/cfml/system/util/CommandDSL.cfc +++ b/src/cfml/system/util/CommandDSL.cfc @@ -19,6 +19,7 @@ component accessors=true { property name='flags'; property name='append'; property name='overwrite'; + property name='workingDirectory'; // DI @@ -42,6 +43,7 @@ component accessors=true { setFlags( [] ); setAppend( '' ); setOverwrite( '' ); + setWorkingDirectory( '' ); return this; } @@ -106,6 +108,14 @@ component accessors=true { setOverwrite( '"#parser.escapeArg( arguments.path )#"' ); return this; } + + /** + * Sets the directory to run the command in + **/ + function inWorkingDirectory( required workingDirectory ) { + setWorkingDirectory( arguments.workingDirectory ); + return this; + } /** * Pipe additional commands @@ -168,11 +178,28 @@ component accessors=true { shell.callCommand( 'echo "#parser.escapeArg( getCommandString() )#"' ); } + var originalCWD = shell.getPWD(); + if( getWorkingDirectory().len() ) { + shell.cd( getWorkingDirectory() ); + } + if( structkeyExists( arguments, 'piped' ) ) { - return shell.callCommand( getTokens(), arguments.returnOutput, arguments.piped ); + var result = shell.callCommand( getTokens(), arguments.returnOutput, arguments.piped ); } else { - return shell.callCommand( getTokens(), arguments.returnOutput ); - } + var result = shell.callCommand( getTokens(), arguments.returnOutput ); + } + + var postCommandCWD = shell.getPWD(); + + // Only change back if the executed command didn't change the CWD + if( getWorkingDirectory().len() && postCommandCWD == getWorkingDirectory() ) { + shell.cd( originalCWD ); + } + + if( !isNull( local.result ) ) { + return local.result; + } + } } \ No newline at end of file From e884312f8a91718a473de2538fb8691c9f5a5f22 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 5 May 2017 18:10:23 -0500 Subject: [PATCH 047/123] COMMANDBOX-614 --- .../system-commands/commands/cd.cfc | 2 +- .../commands/testbox/watch.cfc | 58 ++++++++++++++++--- src/cfml/system/services/CommandService.cfc | 10 ++-- src/cfml/system/util/Watcher.cfc | 4 +- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/cd.cfc b/src/cfml/system/modules_app/system-commands/commands/cd.cfc index 019f903f8..a19150de2 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cd.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cd.cfc @@ -18,7 +18,7 @@ component { **/ function run( directory="" ) { - // This will make each directory canonical and absolute + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); if( !directoryExists( arguments.directory ) ) { diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index 6aec96541..09b46cfa3 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -1,23 +1,65 @@ /** - * Description of command + * Watch the files in a directory and run the default TestBox suite on any file change. + * + * {code} + * testbox watch + * {code} + * + * In order for this command to work, you need to have started your server and configured the + * URL to the test runner in your box.json. + * + * {code} + * server set testbox.runner=http://localhost:8080/tests/runner.cfm + * server start + * testbox watch + * {code} + * + * If you need more control over what tests run and their output, you can set additional options in your box.json + * which will be picked up automatically by "testbox run" whe it fires. + * + * {code} + * server set testbox.verbose=false + * server set testbox.labels=foo + * server set testbox.testSuites=bar + * {code} + * + * This command will run in the foreground until you stop it. When you are ready to shut down the watcher, press Ctrl+C. + * **/ component { /** - * + * @paths Command delimeted list of file globbing paths to watch relative to "directory". + * @delay How may miliseconds to wait before polling for changes + * @directory The directory to watch for changes. "testbox run" is executed in this folder as well. **/ - function run( ) { + function run( + string paths='**.cfc', + number delay=500, + string directory='' + ) { - // Clear screen + arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); + + // Tabula rasa command( 'cls' ).run(); // Start watcher watch() - .paths( '**.cfc' ) - .inDirectory( getCWD() ) + .paths( paths.listToArray() ) + .inDirectory( directory ) + .withDelay( delay ) .onChange( function() { - command( 'cls' ).run(); - command( 'testbox run' ).run(); + + // Clear the screen + command( 'cls' ) + .run(); + + // Run the tests in the target directory + command( 'testbox run' ) + .inWorkingDirectory( directory ) + .run(); + } ) .start(); } diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index f56c67d44..632280495 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -322,17 +322,15 @@ component accessors="true" singleton { } else { shell.printError( e ); } - // Unwind the stack and cancell all commands in the chain. + // Unwind the stack to the closest catch } else { - // Clean up a bit - instance.callStack.clear(); rethrow; } + } finally { + // Remove it from the stack + instance.callStack.deleteAt( 1 ); } - // Remove it from the stack - instance.callStack.deleteAt( 1 ); - // If the command didn't return anything, grab its print buffer value if( isNull( result ) ){ result = commandInfo.commandReference.CFC.getResult(); diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index dd794236b..33780d004 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -114,11 +114,13 @@ component accessors=true { } catch( any e ) { // Print out error message from exception and continue watching print.printRedBoldLine( "An exception has ocurred: #e.message# #e.detail#" ) - .line( e.stacktrace ) + //.line( e.stacktrace ) .line() .printGreenLine( "Starting watcher again..." ) .line() .toConsole(); + + retry; } } // end thread From 1b59fceda7db08fcf7094b2a8b53c861a164212d Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 14:54:07 -0500 Subject: [PATCH 048/123] detect if ? is already in runner, else skip it. --- .../modules_app/testbox-commands/commands/testbox/run.cfc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index 0d791c0b3..e7d04de76 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -66,8 +66,11 @@ component { return error( '[#runnerURL#] it not a valid URL, or does not match a runner slug in your box.json.' ); } - // Default runner builder - var testboxURL = runnerURL & "?"; + // Default runner builder and add ? if not detected + var testboxURL = runnerURL; + if( !find( "?", testboxURL ) ){ + testboxURL &= "?"; + } // Runner options overridable by arguments and box options var RUNNER_OPTIONS = { @@ -157,7 +160,6 @@ component { setExitCode( 1 ); print.boldRed( " " & results.filecontent ); } - } From 32cce326e4890a6591decd28a9413142714fac97 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 14:55:15 -0500 Subject: [PATCH 049/123] removed length checks to include empty overrides --- .../modules_app/testbox-commands/commands/testbox/run.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index e7d04de76..50877c9c5 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -38,7 +38,7 @@ component { string bundles, string directory, boolean recurse, - string reporter="", + string reporter, string labels, string options, string testBundles, @@ -89,11 +89,11 @@ component { // Build out runner options for( var thisOption in RUNNER_OPTIONS ){ // Check argument overrides - if( !isNull( arguments[ thisOption ] ) && len( arguments[ thisOption ] ) ){ + if( !isNull( arguments[ thisOption ] ) ){ testboxURL &= "&#thisOption#=#arguments[ thisOption ]#"; } // Check runtime options now - else if( boxOptions.keyExists( thisOption ) && len( boxOptions[ thisOption ]) ){ + else if( boxOptions.keyExists( thisOption ) ){ testboxURL &= "&#thisOption#=#boxOptions[ thisOption ]#"; } // Defaults From 06b39d505c8c37645992ff080a39b843a6c8ecf3 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 16:15:15 -0500 Subject: [PATCH 050/123] COMMANDBOX-54 Update testbox watch to integrate to box.json for the watchers array or simple list and the watch delay --- .../commands/testbox/watch.cfc | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index 09b46cfa3..f50e1a5a8 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -27,28 +27,51 @@ * **/ component { + + // DI + property name="packageService" inject="PackageService"; + + variables.WATCH_DELAY = 500; + variables.PATHS = "**.cfc"; /** - * @paths Command delimeted list of file globbing paths to watch relative to "directory". - * @delay How may miliseconds to wait before polling for changes + * @paths Command delimeted list of file globbing paths to watch relative to "directory", defaults to **.cfc + * @delay How may miliseconds to wait before polling for changes, defaults to 500 ms * @directory The directory to watch for changes. "testbox run" is executed in this folder as well. **/ function run( - string paths='**.cfc', - number delay=500, + string paths, + number delay, string directory='' ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); + // Get testbox options from package descriptor + var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox; + + var getOptionsWatchers = function(){ + // Return to List + if( boxOptions.keyExists( "watchers" ) ){ + if( isArray( boxOptions.watchers ) ){ + return boxOptions.watchers.toList(); + } + return boxOptions.watchers; + } + // should return null if not found + } + + // Determine watching patterns, either from arguments or boxoptions or defaults + var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; + // Tabula rasa command( 'cls' ).run(); // Start watcher watch() - .paths( paths.listToArray() ) + .paths( globbingPaths.listToArray() ) .inDirectory( directory ) - .withDelay( delay ) + .withDelay( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ) .onChange( function() { // Clear the screen From 49e14695828ad6b6c59d2558a259addfcd18016e Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 16:32:04 -0500 Subject: [PATCH 051/123] added base directory watcher --- .../testbox-commands/commands/testbox/watch.cfc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index f50e1a5a8..bbe4e1d02 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -42,11 +42,9 @@ component { function run( string paths, number delay, - string directory='' + string directory ) { - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - // Get testbox options from package descriptor var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox; @@ -64,13 +62,18 @@ component { // Determine watching patterns, either from arguments or boxoptions or defaults var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; + // Determine base directory + arguments.directory = fileSystemUtil.resolvePath( + arguments.directory ?: boxOptions.watchBaseDirectory ?: '' + ); + // Tabula rasa command( 'cls' ).run(); // Start watcher watch() .paths( globbingPaths.listToArray() ) - .inDirectory( directory ) + .inDirectory( arguments.directory ) .withDelay( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ) .onChange( function() { @@ -80,7 +83,7 @@ component { // Run the tests in the target directory command( 'testbox run' ) - .inWorkingDirectory( directory ) + .inWorkingDirectory( arguments.directory ) .run(); } ) From fb4f96990de480c2517a0ece83bd30ed4c305028 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 9 May 2017 17:12:44 -0500 Subject: [PATCH 052/123] COMMANDBOX-616 --- .../templates/testing/InterceptorBDDContentScript.txt | 4 ++++ .../coldbox-commands/templates/testing/ModelBDDContent.txt | 4 +++- .../templates/testing/ModelBDDContentScript.txt | 3 +++ .../templates/testing/ORMEntityBDDContent.txt | 4 +++- .../templates/testing/ORMEntityBDDContentScript.txt | 3 +++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules_app/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt b/src/cfml/system/modules_app/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt index c8f4d0b57..224b474cb 100644 --- a/src/cfml/system/modules_app/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt +++ b/src/cfml/system/modules_app/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt @@ -8,6 +8,8 @@ component extends="coldbox.system.testing.BaseInterceptorTest" interceptor="|nam /*********************************** LIFE CYCLE Methods ***********************************/ function beforeAll(){ + super.beforeAll(); + // interceptor configuration properties, if any configProperties = {}; // init and configure interceptor @@ -16,6 +18,8 @@ component extends="coldbox.system.testing.BaseInterceptorTest" interceptor="|nam } function afterAll(){ + // do your own stuff here + super.afterAll(); } /*********************************** BDD SUITES ***********************************/ diff --git a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContent.txt b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContent.txt index 474eada2c..5e4be6f7e 100644 --- a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContent.txt +++ b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContent.txt @@ -8,6 +8,8 @@ responsibility to update the model annotation instantiation path and init your m + + @@ -16,7 +18,7 @@ responsibility to update the model annotation instantiation path and init your m - + diff --git a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContentScript.txt b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContentScript.txt index 2f0b4ce47..784808602 100644 --- a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContentScript.txt +++ b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ModelBDDContentScript.txt @@ -8,6 +8,8 @@ component extends="coldbox.system.testing.BaseModelTest" model="|modelPath|"{ /*********************************** LIFE CYCLE Methods ***********************************/ function beforeAll(){ + super.beforeAll(); + // setup the model super.setup(); @@ -16,6 +18,7 @@ component extends="coldbox.system.testing.BaseModelTest" model="|modelPath|"{ } function afterAll(){ + super.afterAll(); } /*********************************** BDD SUITES ***********************************/ diff --git a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContent.txt b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContent.txt index 18f3e2407..8e5a23ace 100644 --- a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContent.txt +++ b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContent.txt @@ -8,6 +8,8 @@ responsibility to update the model annotation instantiation path and init your m + + @@ -19,7 +21,7 @@ responsibility to update the model annotation instantiation path and init your m - + diff --git a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContentScript.txt b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContentScript.txt index 04bf9854b..f5ea6ee38 100644 --- a/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContentScript.txt +++ b/src/cfml/system/modules_app/coldbox-commands/templates/testing/ORMEntityBDDContentScript.txt @@ -8,6 +8,8 @@ component extends="coldbox.system.testing.BaseModelTest" model="|modelName|"{ /*********************************** LIFE CYCLE Methods ***********************************/ function beforeAll(){ + super.beforeAll(); + // load ColdBox this.loadColdbox = true; @@ -19,6 +21,7 @@ component extends="coldbox.system.testing.BaseModelTest" model="|modelName|"{ } function afterAll(){ + super.afterAll(); } /*********************************** BDD SUITES ***********************************/ From 0ca6fbcfe97b0f63f9688e53f0d94277b41408cc Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 17:21:16 -0500 Subject: [PATCH 053/123] reactivating this, if not, it is impossible to debug watcher exceptions --- src/cfml/system/util/Watcher.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index 33780d004..affad77c9 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -114,7 +114,7 @@ component accessors=true { } catch( any e ) { // Print out error message from exception and continue watching print.printRedBoldLine( "An exception has ocurred: #e.message# #e.detail#" ) - //.line( e.stacktrace ) + .line( e.stacktrace ) .line() .printGreenLine( "Starting watcher again..." ) .line() From 068b4b9790c3d6a6713aa9e57dce3557cef787a5 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 17:30:14 -0500 Subject: [PATCH 054/123] removed base directory to current working directory as per conversiation with @bdw429 --- .../testbox-commands/commands/testbox/watch.cfc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index bbe4e1d02..df9168e21 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -37,12 +37,10 @@ component { /** * @paths Command delimeted list of file globbing paths to watch relative to "directory", defaults to **.cfc * @delay How may miliseconds to wait before polling for changes, defaults to 500 ms - * @directory The directory to watch for changes. "testbox run" is executed in this folder as well. **/ function run( string paths, - number delay, - string directory + number delay ) { // Get testbox options from package descriptor @@ -63,8 +61,8 @@ component { var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; // Determine base directory - arguments.directory = fileSystemUtil.resolvePath( - arguments.directory ?: boxOptions.watchBaseDirectory ?: '' + var currentDirectory = fileSystemUtil.resolvePath( + boxOptions.watchBaseDirectory ?: getCWD() ); // Tabula rasa @@ -73,7 +71,7 @@ component { // Start watcher watch() .paths( globbingPaths.listToArray() ) - .inDirectory( arguments.directory ) + .inDirectory( currentDirectory ) .withDelay( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ) .onChange( function() { @@ -83,7 +81,7 @@ component { // Run the tests in the target directory command( 'testbox run' ) - .inWorkingDirectory( arguments.directory ) + .inWorkingDirectory( currentDirectory ) .run(); } ) From 58d326b0afbcf7903ea4d2c2788800769d464730 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 17:30:52 -0500 Subject: [PATCH 055/123] removed base directory to current working directory as per conversiation with @bdw429 --- .../testbox-commands/commands/testbox/watch.cfc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index df9168e21..29462d33e 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -60,18 +60,13 @@ component { // Determine watching patterns, either from arguments or boxoptions or defaults var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; - // Determine base directory - var currentDirectory = fileSystemUtil.resolvePath( - boxOptions.watchBaseDirectory ?: getCWD() - ); - // Tabula rasa command( 'cls' ).run(); // Start watcher watch() .paths( globbingPaths.listToArray() ) - .inDirectory( currentDirectory ) + .inDirectory( getCWD() ) .withDelay( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ) .onChange( function() { @@ -81,7 +76,7 @@ component { // Run the tests in the target directory command( 'testbox run' ) - .inWorkingDirectory( currentDirectory ) + .inWorkingDirectory( getCWD() ) .run(); } ) From 3c44a7d0f9e0beffa3b02e0233c04af67878494f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 9 May 2017 17:42:58 -0500 Subject: [PATCH 056/123] small update on doc --- .../modules_app/testbox-commands/commands/testbox/watch.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index 29462d33e..a841e85ae 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -35,7 +35,7 @@ component { variables.PATHS = "**.cfc"; /** - * @paths Command delimeted list of file globbing paths to watch relative to "directory", defaults to **.cfc + * @paths Command delimeted list of file globbing paths to watch relative to the working directory, defaults to **.cfc * @delay How may miliseconds to wait before polling for changes, defaults to 500 ms **/ function run( From b9c3718217f682df0975a258fa19d04bc3edb1b6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 16:29:04 -0500 Subject: [PATCH 057/123] COMMANDBOX-615 Improve error handling and argument names --- src/cfml/system/Shell.cfc | 1 + src/cfml/system/config/box.json.txt | 4 +-- .../commands/testbox/watch.cfc | 26 ++++++++++--------- src/cfml/system/util/Watcher.cfc | 21 ++++++++++++--- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index 5a31f763f..f4152a2ea 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -561,6 +561,7 @@ component accessors="true" singleton { } variables.reader.println(); + variables.reader.flush(); return this; } diff --git a/src/cfml/system/config/box.json.txt b/src/cfml/system/config/box.json.txt index b0a50a3fa..eb86324e5 100644 --- a/src/cfml/system/config/box.json.txt +++ b/src/cfml/system/config/box.json.txt @@ -46,7 +46,7 @@ "testSuites" : "", "testSpecs" : "", "verbose" : true, - "Watchers" : [] - + "watchDelay" : 500, + "watchPaths" : "**.cfc" } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index a841e85ae..fb3851bbf 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -9,7 +9,7 @@ * URL to the test runner in your box.json. * * {code} - * server set testbox.runner=http://localhost:8080/tests/runner.cfm + * package set testbox.runner=http://localhost:8080/tests/runner.cfm * server start * testbox watch * {code} @@ -18,9 +18,11 @@ * which will be picked up automatically by "testbox run" whe it fires. * * {code} - * server set testbox.verbose=false - * server set testbox.labels=foo - * server set testbox.testSuites=bar + * package set testbox.verbose=false + * package set testbox.labels=foo + * package set testbox.testSuites=bar + * package set testbox.watchDelay=1000 + * package set testbox.watchPaths=/models/**.cfc * {code} * * This command will run in the foreground until you stop it. When you are ready to shut down the watcher, press Ctrl+C. @@ -35,8 +37,8 @@ component { variables.PATHS = "**.cfc"; /** - * @paths Command delimeted list of file globbing paths to watch relative to the working directory, defaults to **.cfc - * @delay How may miliseconds to wait before polling for changes, defaults to 500 ms + * @paths Command delimited list of file globbing paths to watch relative to the working directory, defaults to **.cfc + * @delay How may milliseconds to wait before polling for changes, defaults to 500 ms **/ function run( string paths, @@ -48,17 +50,17 @@ component { var getOptionsWatchers = function(){ // Return to List - if( boxOptions.keyExists( "watchers" ) ){ - if( isArray( boxOptions.watchers ) ){ - return boxOptions.watchers.toList(); - } - return boxOptions.watchers; + if( boxOptions.keyExists( "watchPaths" ) && boxOptions.watchPaths.len() ){ + return boxOptions.watchPaths; } // should return null if not found + return; } // Determine watching patterns, either from arguments or boxoptions or defaults var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; + // handle non numberic config and put a floor of 150ms + var delayMs = max( val( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ), 150 ); // Tabula rasa command( 'cls' ).run(); @@ -67,7 +69,7 @@ component { watch() .paths( globbingPaths.listToArray() ) .inDirectory( getCWD() ) - .withDelay( arguments.delay ?: boxOptions.watchDelay ?: variables.WATCH_DELAY ) + .withDelay( delayMs ) .onChange( function() { // Clear the screen diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index affad77c9..c378c269d 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -111,15 +111,28 @@ component accessors=true { sleep( getDelayMS() ); } } - } catch( any e ) { - // Print out error message from exception and continue watching - print.printRedBoldLine( "An exception has ocurred: #e.message# #e.detail#" ) - .line( e.stacktrace ) + // Handle "expected" exceptions from commands + } catch( commandException e ) { + shell.printError( { message : e.message, detail: e.detail } ); + + print + .line() + .printGreenLine( "Starting watcher again..." ) + .line() + .toConsole(); + + // Fire the watcher up again. + retry; + } catch( any e ) { + shell.printError( e ); + + print .line() .printGreenLine( "Starting watcher again..." ) .line() .toConsole(); + // Fire the watcher up again. retry; } } // end thread From 036489ff2512dad6d541498d7f025243ed69bbd0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 17:00:48 -0500 Subject: [PATCH 058/123] COMMANDBOX-617 --- .../modules_app/package-commands/commands/package/init.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/modules_app/package-commands/commands/package/init.cfc b/src/cfml/system/modules_app/package-commands/commands/package/init.cfc index 6780561ba..73f8e5e71 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/init.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/init.cfc @@ -54,7 +54,7 @@ component aliases="init" { var directory = getCWD(); // Read current box.json if it exists, otherwise, get a new one - var boxJSON = PackageService.readPackageDescriptor( directory ); + var boxJSON = PackageService.readPackageDescriptorTemplate( directory ); // Don't use these defaults if the existing box.json already has something useful if( len( boxJSON.name ) && arguments.name == 'My Package' ) { @@ -76,7 +76,7 @@ component aliases="init" { var fullPropertyName = 'boxJSON.#arg#'; var propertyValue = arguments[ arg ]; if( isJSON( propertyValue ) ) { - evaluate( '#fullPropertyName# = deserializeJSON( arguments[ arg ] )' ); + evaluate( '#fullPropertyName# = deserializeJSON( arguments[ arg ] )' ); } else { evaluate( '#fullPropertyName# = arguments[ arg ]' ); } @@ -87,6 +87,6 @@ component aliases="init" { PackageService.writePackageDescriptor( boxJSON, directory ); // Info message - print.yellowLine( 'Package Initialized & Created ' & directory & '/box.json' ).toConsole(); + print.yellowLine( 'Package Initialized & Created ' & directory & 'box.json' ).toConsole(); } } \ No newline at end of file From 2765b5d3b5c6c154ec8cc19c2d616f3ef9c807fb Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 17:08:18 -0500 Subject: [PATCH 059/123] COMMANDBOX-617 --- src/cfml/system/services/PackageService.cfc | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 5c9a15b6a..7f21734e9 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -786,13 +786,30 @@ component accessors="true" singleton { * Get the default package description, AKA box.json * @defaults A struct of default values to be merged into the empty, default document */ - public function newPackageDescriptor( struct defaults={} ) { + public function newPackageDescriptor( struct defaults={}, boolean omitDeprecated=false ) { // TODO: Get author info from default CommandBox config // Read the default JSON file and deserialize it. var boxJSON = DeserializeJSON( fileRead( '/commandBox/system/config/box.json.txt' ) ); + // Remove deprecated (or just edge case) properties + // from the box.json template as to not confuse people. + if( arguments.omitDeprecated ) { + + // most packages shouldn't need to set these + boxJSON.delete( 'directory' ) + boxJSON.delete( 'createPackageDirectory' ) + boxJSON.delete( 'packageDirectory' ) + + // These aren't even used + boxJSON.delete( 'engines' ) + boxJSON.delete( 'defaultEngine' ) + + // This went out of style with server.json + boxJSON.delete( 'defaultPort' ); + } + // Replace things passed via parameters boxJSON = boxJSON.append( arguments.defaults ); @@ -811,6 +828,15 @@ component accessors="true" singleton { return newPackageDescriptor( readPackageDescriptorRaw( arguments.directory ) ); } + /** + * Does everything readPackageDescriptor() does, but won't default deprecated box.json proprties. + * @directory The directory to search for the box.json + */ + struct function readPackageDescriptorTemplate( required directory ){ + // Merge this JSON with defaults + return newPackageDescriptor( readPackageDescriptorRaw( arguments.directory ), true ); + } + /** * Get the box.json as data from the passed directory location, if not found * then we return an empty struct. This method will NOT default box.json properties From aadaa4bc80ce1e78f17a29c3cc60498b18a85ed3 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 22:44:49 -0500 Subject: [PATCH 060/123] COMMANDBOX-568 --- src/cfml/system/services/ServerService.cfc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index c9f55f5de..e5c273bc0 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1543,7 +1543,13 @@ component accessors="true" singleton { */ struct function readServerJSON( required string path ) { if( fileExists( path ) ) { - return deserializeJSON( fileRead( path ) ); + var fileContents = fileRead( path ); + if( isJSON( fileContents ) ) { + return deserializeJSON( fileContents ); + } else { + consoleLogger.warn( 'Warning: File is not valid JSON. [#path#]' ); + return {}; + } } else { return {}; } From c2a249a108681e32d0e80730b5159811bb3899a0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 23:25:16 -0500 Subject: [PATCH 061/123] COMMANDBOX-459 --- .../commands/package/clear.cfc | 10 +++++++-- .../commands/package/install.cfc | 12 ++++++++--- .../commands/package/list.cfc | 21 ++++++++++++++----- .../commands/package/outdated.cfc | 20 +++++++++++++----- .../package-commands/commands/package/set.cfc | 13 +++++++++--- .../commands/package/show.cfc | 10 +++++++-- .../commands/package/uninstall.cfc | 14 ++++++++----- .../commands/package/update.cfc | 19 +++++++++++++---- src/cfml/system/services/PackageService.cfc | 4 ++-- 9 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc b/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc index 8c4c3d270..915f0d4ff 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc @@ -16,9 +16,15 @@ component { /** * @property.hint Name of the property to clear * @property.optionsUDF completeProperty + * @system.hint When true, show box.json data in the global CommandBox folder **/ - function run( required string property ) { - var directory = getCWD(); + function run( required string property, boolean system=false ) { + + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } // Check and see if box.json exists if( !packageService.isPackage( directory ) ) { diff --git a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc index b16955a54..719050d7b 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc @@ -104,6 +104,7 @@ component aliases="install" { * @production.hint When calling this command with no ID to install all dependencies, set this to true to ignore devDependencies. * @verbose.hint If set, it will produce much more verbose information about the package installation * @force.hint When set to true, it will force dependencies to be installed whether they already exist or not + * @system.hint When true, install this package into the global CommandBox module's folder **/ function run( string ID='', @@ -112,7 +113,8 @@ component aliases="install" { boolean saveDev=false, boolean production, boolean verbose=false, - boolean force=false + boolean force=false, + boolean system=false ){ // Don't default the dir param since we need to differentiate whether the user actually @@ -128,8 +130,12 @@ component aliases="install" { } - // TODO: climb tree to find root of the site by searching for box.json - arguments.currentWorkingDirectory = getCWD(); + + if( arguments.system ) { + arguments.currentWorkingDirectory = expandPath( '/commandbox' ); + } else { + arguments.currentWorkingDirectory = getCWD(); + } // Make ID an array arguments.IDArray = listToArray( arguments.ID ); diff --git a/src/cfml/system/modules_app/package-commands/commands/package/list.cfc b/src/cfml/system/modules_app/package-commands/commands/package/list.cfc index 941da5876..8abb683e0 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/list.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/list.cfc @@ -27,15 +27,26 @@ component aliases="list" { /** * @verbose.hint Outputs additional informaiton about each package - * @json.hint Outputs results as JSON + * @json.hint Outputs results as JSON + * @system.hint When true, list packages from the global CommandBox module's folder **/ - function run( boolean verbose=false, boolean JSON=false ) { + function run( + boolean verbose=false, + boolean JSON=false, + boolean system=false ) { + + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } + // package check - if( !packageService.isPackage( getCWD() ) ) { - return error( '#getCWD()# is not a package!' ); + if( !packageService.isPackage( directory ) ) { + return error( '#directory# is not a package!' ); } // build dependency tree - var tree = packageService.buildDependencyHierarchy( getCWD() ); + var tree = packageService.buildDependencyHierarchy( directory ); // JSON output if( arguments.JSON ) { diff --git a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc index 8a62cee55..8128e43f0 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc @@ -28,17 +28,27 @@ component aliases="outdated" { /** * @verbose.hint Outputs additional information about each package - * @json.hint Outputs results as JSON + * @json.hint Outputs results as JSON + * @system.hint When true, check the global CommandBox module's folder **/ - function run( boolean verbose=false, boolean JSON=false ) { + function run( + boolean verbose=false, + boolean JSON=false, + boolean system=false ) { if( arguments.JSON ) { arguments.verbose = false; } + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } + // package check - if( !packageService.isPackage( getCWD() ) ) { - return error( '#getCWD()# is not a package!' ); + if( !packageService.isPackage( directory ) ) { + return error( '#directory# is not a package!' ); } // echo output @@ -47,7 +57,7 @@ component aliases="outdated" { } // build dependency tree - var aOutdatedDependencies = packageService.getOutdatedDependencies( directory=getCWD(), print=print, verbose=arguments.verbose ); + var aOutdatedDependencies = packageService.getOutdatedDependencies( directory=directory, print=print, verbose=arguments.verbose ); // JSON output if( arguments.JSON ) { diff --git a/src/cfml/system/modules_app/package-commands/commands/package/set.cfc b/src/cfml/system/modules_app/package-commands/commands/package/set.cfc index 62ee63dfe..ae6a9b718 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/set.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/set.cfc @@ -50,14 +50,21 @@ component { * @_.hint Pass any number of property names in followed by the value to set * @_.optionsUDF completeProperty * @append.hint If setting an array or struct, set to true to append instead of overwriting. + * @system.hint When true, show box.json data in the global CommandBox folder **/ - function run( _, boolean append=false ) { - var thisAppend = arguments.append; - var directory = getCWD(); + function run( _, boolean append=false, boolean system=false ) { + var thisAppend = arguments.append; + + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } // Remove dummy args structDelete( arguments, '_' ); structDelete( arguments, 'append' ); + structDelete( arguments, 'system' ); // Check and see if box.json exists if( !packageService.isPackage( directory ) ) { diff --git a/src/cfml/system/modules_app/package-commands/commands/package/show.cfc b/src/cfml/system/modules_app/package-commands/commands/package/show.cfc index 179241814..123b1072f 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/show.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/show.cfc @@ -34,9 +34,15 @@ component { /** * @property.hint The name of the property to show. Can nested to get "deep" properties * @property.optionsUDF completeProperty + * @system.hint When true, show box.json data in the global CommandBox folder **/ - function run( string property='' ) { - var directory = getCWD(); + function run( string property='', boolean system=false ) { + + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } // Check and see if box.json exists if( !packageService.isPackage( directory ) ) { diff --git a/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc b/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc index d64264a4a..eef12b0c2 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc @@ -28,12 +28,13 @@ component aliases="uninstall" { * @slug.optionsUDF slugComplete * @directory.hint The directory the package is currently installed in including the container folder * @save.hint Remove package as a dependancy in box.json (if it exists) - * @saveDev.hint Remove package as a dev dependancy in box.json (if it exists) + * @system.hint When true, uninstall this package from the global CommandBox module's folder **/ function run( required string slug='', string directory, - boolean save=true + boolean save=true, + boolean system=false ){ // Don't default the dir param since we need to differentiate whether the user actually @@ -48,10 +49,13 @@ component aliases="uninstall" { } } - - // TODO: climb tree to find root of the site by searching for box.json - arguments.currentWorkingDirectory = getCWD(); + if( arguments.system ) { + arguments.currentWorkingDirectory = expandPath( '/commandbox' ); + } else { + arguments.currentWorkingDirectory = getCWD(); + } + // Convert slug to array arguments.slug = listToArray( arguments.slug ); // iterate and uninstall. diff --git a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc index 1517551be..fb7f35cbb 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc @@ -41,12 +41,23 @@ component aliases="update" { * @slug.optionsUDF slugComplete * @verbose Outputs additional information about each package * @force Forces an update without confirmations + * @system.hint When true, update packages in the global CommandBox module's folder **/ - function run( string slug="", boolean verbose=false, boolean force=false ) { + function run( + string slug="", + boolean verbose=false, + boolean force=false, + boolean system=false ) { + + if( arguments.system ) { + var directory = expandPath( '/commandbox' ); + } else { + var directory = getCWD(); + } // package check - if( !packageService.isPackage( getCWD() ) ) { - return error( '#getCWD()# is not a package!' ); + if( !packageService.isPackage( directory ) ) { + return error( '#directory# is not a package!' ); } // echo output @@ -54,7 +65,7 @@ component aliases="update" { // build dependency tree var dependenciesToUpdate = packageService.getOutdatedDependencies( - directory=getCWD(), + directory=directory, print=print, verbose=arguments.verbose, includeSlugs=arguments.slug diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 7f21734e9..1e916269e 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -583,7 +583,7 @@ component accessors="true" singleton { // Is there an install path for this? if( structKeyExists( installPaths, packageName ) ) { - uninstallDirectory = fileSystemUtil.resolvePath( installPaths[ packageName ] ); + uninstallDirectory = fileSystemUtil.resolvePath( installPaths[ packageName ], arguments.currentWorkingDirectory ); } } @@ -655,7 +655,7 @@ component accessors="true" singleton { consoleLogger.debug( "Package [#packageName#] skipped, it doesn't appear to be installed." ); } else { - consoleLogger.error( 'Package [#uninstallDirectory#] not found.' ); + consoleLogger.warn( 'Package [#uninstallDirectory#] not found.' ); } From b9f4bfeef09c90822987b72ea3b00431255c8ee8 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 23:46:44 -0500 Subject: [PATCH 062/123] COMMANDBOX-585 --- .../system-commands/commands/tokenReplace.cfc | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc diff --git a/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc b/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc new file mode 100644 index 000000000..aa2d14cd4 --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc @@ -0,0 +1,46 @@ +/** + * Replace text tokens in one or more files. Token matches are case insensitive. + * . + * {code:bash} + * tokenReplace path=/path/to/file.txt token="@@version@@" replacement=`package version` + * tokenReplace path=/tests/*.cfc token="@@version@@" replacement=`package version` + * {code} + * . + * Use the "verbose" param to see all the files affected + * . + * {code:bash} + * tokenReplace path=file.txt token="foo" replacement="bar" + * {code} + * + **/ +component { + + /** + * @path file(s) to replace tokens in. Globbing patters allowed such as *.txt + * @token The token to search for + * @replacement The replacement text to use + * @verbose Output file names that have been modified + **/ + function run( + required Globber path, + required String token, + required String replacement, + boolean verbose=false ) { + + path.apply( function( thisPath ) { + + // It's a file + if( fileExists( thisPath ) ){ + if( verbose ) { + print.greenLine( thisPath ); + } + var fileContents = fileRead( thisPath ); + if( fileContents.findNoCase( token ) ) { + fileWrite( thisPath, fileContents.replaceNoCase( token, replacement, 'all' ) ); + } + } + + } ); + } + +} \ No newline at end of file From 8e763f11e0ececb4a79456e6bb5fc1cafe11ed03 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 12 May 2017 23:55:18 -0500 Subject: [PATCH 063/123] COMMANDBOX-586 --- .../forgebox-commands/commands/forgebox/publish.cfc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc index cf9bcc55d..e8af02edc 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc @@ -7,13 +7,22 @@ **/ component aliases="publish" { + property name="configService" inject="configService"; + /** * @directory The directory to publish **/ function run( string directory='' - ){ - + ){ + + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); + + if( !APIToken.len() ) { + print.yellowLine( 'Please log into Forgebox to continue' ); + command( 'forgebox login' ).run(); + } + // Default the endpointName arguments.endpointName = 'forgebox'; From a245135a3590056f35b5e28429560c918bab73e8 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 13 May 2017 00:27:39 -0500 Subject: [PATCH 064/123] COMMANDBOX-618 --- src/cfml/system/util/REPLParser.cfc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cfml/system/util/REPLParser.cfc b/src/cfml/system/util/REPLParser.cfc index 0edb84e73..31e8790d2 100644 --- a/src/cfml/system/util/REPLParser.cfc +++ b/src/cfml/system/util/REPLParser.cfc @@ -107,6 +107,9 @@ component accessors="true" singleton { // null if( isNull( result ) ){ return; + // binary + } else if( isBinary( result ) ) { + return '[BINARY]'; // string } else if( isSimpleValue( result ) ) { return result; From f7ce4c2f371134f3a13ab7a5616226d5d95f704e Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 13 May 2017 00:55:33 -0500 Subject: [PATCH 065/123] COMMANDBOX-589 --- .../system-commands/commands/checksum.cfc | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/cfml/system/modules_app/system-commands/commands/checksum.cfc diff --git a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc new file mode 100644 index 000000000..75133e245 --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc @@ -0,0 +1,41 @@ +/** + * Generate checksum for a file. Default is MD5, but SHA-1, SHA-256, and SHA-512 can also be used. + * . + * {code:bash} + * checksum path=file.txt + * checksum path=build.zip SHA-256 + * {code} + * + **/ +component { + + variables.algorithms = 'MD5,SHA1,SHA-1,SHA-256,SHA-512'; + + /** + * @file file to create checksum of + * @algorithm Hashing algorithm to use + * @algorithm.optionsUDF algorithmComplete + **/ + function run( + required String file, + String algorithm='MD5' ) { + + if( !variables.algorithms.listFindNoCase( arguments.algorithm ) ) { + error( 'The hashing algorithm [#arguments.algorithm#] is not supported' ); + } + + arguments.file = filesystemUtil.resolvePath( arguments.file ); + + if( !fileExists( arguments.file ) ) { + error( "File doesn't exist. I can't hash thin air! [#arguments.file#]" ); + } + + print.text( hash( fileReadBinary( arguments.file ), arguments.algorithm ) ); + + } + + function algorithmComplete() { + return variables.algorithms.listToArray(); + } + +} \ No newline at end of file From 118b0f35751cd1700ed8990ff0eb18901787d8d0 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 15 May 2017 17:07:48 -0500 Subject: [PATCH 066/123] support array watch paths --- .../modules_app/testbox-commands/commands/testbox/watch.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index fb3851bbf..130bd3301 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -51,7 +51,7 @@ component { var getOptionsWatchers = function(){ // Return to List if( boxOptions.keyExists( "watchPaths" ) && boxOptions.watchPaths.len() ){ - return boxOptions.watchPaths; + return ( isArray( boxOptions.watchPaths ) ? boxOptions.watchPaths.toList() : boxOptions.watchPaths ); } // should return null if not found return; From c03813bcbdb71eae19f4efc57e25dd3312ae4b30 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 15 May 2017 17:51:46 -0500 Subject: [PATCH 067/123] COMMANDBOX-619 --- .../system-commands/commands/checksum.cfc | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc index 75133e245..525c512d2 100644 --- a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc @@ -1,8 +1,10 @@ /** - * Generate checksum for a file. Default is MD5, but SHA-1, SHA-256, and SHA-512 can also be used. + * Generate checksum for a file or a directory via a globbiner pattern. + * Default is MD5, but SHA-1, SHA-256, and SHA-512 can also be used. * . * {code:bash} * checksum path=file.txt + * checksum path=*.zip * checksum path=build.zip SHA-256 * {code} * @@ -12,25 +14,29 @@ component { variables.algorithms = 'MD5,SHA1,SHA-1,SHA-256,SHA-512'; /** - * @file file to create checksum of + * @path Path of file or globbing pattern to create checksum of * @algorithm Hashing algorithm to use * @algorithm.optionsUDF algorithmComplete **/ function run( - required String file, + required Globber path, String algorithm='MD5' ) { - if( !variables.algorithms.listFindNoCase( arguments.algorithm ) ) { - error( 'The hashing algorithm [#arguments.algorithm#] is not supported' ); + if( !variables.algorithms.listFindNoCase( algorithm ) ) { + error( 'The hashing algorithm [#algorithm#] is not supported' ); } - - arguments.file = filesystemUtil.resolvePath( arguments.file ); - - if( !fileExists( arguments.file ) ) { - error( "File doesn't exist. I can't hash thin air! [#arguments.file#]" ); + + if( !path.count() ) { + error( "File or globbing pattern doesn't exist. I can't hash thin air! [#path.getPattern()#]" ); } - print.text( hash( fileReadBinary( arguments.file ), arguments.algorithm ) ); + // If matching single file, just hash that file + if( path.count() == 1 ) { + print.text( hash( fileReadBinary( path.asArray().matches()[ 1 ] ), algorithm ) ); + // If matching directory, hash the query + } else { + print.text( hash( serializeJSON( path.asQuery().matches() ), algorithm ) ); + } } From ca420a0af79548ce7647db0d95c74b7475db0cad Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 15 May 2017 19:35:17 -0500 Subject: [PATCH 068/123] COMMANDBOX-619 --- .../system-commands/commands/checksum.cfc | 130 ++++++++++++++++-- src/cfml/system/services/CommandService.cfc | 4 +- 2 files changed, 120 insertions(+), 14 deletions(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc index 525c512d2..84bdeb3a9 100644 --- a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc @@ -1,47 +1,153 @@ /** - * Generate checksum for a file or a directory via a globbiner pattern. + * Generate checksum for a file or a directory via a globbing pattern. * Default is MD5, but SHA-1, SHA-256, and SHA-512 can also be used. * . * {code:bash} - * checksum path=file.txt + * checksum file.txt + * checksum build.zip SHA-256 + * {code} + * + * Create a checksum for more than one file in a directory with a file globbing pattern + * . + * {code:bash} * checksum path=*.zip - * checksum path=build.zip SHA-256 + * {code} + * + * Write checksum(s) to a file named after the original file plus a new extension. + * This will create a file called "myFile.zip.md5". + * . + * {code:bash} + * checksum myFile.zip md5 --write + * {code} + * + * Control the file extension like so. (--write is optional when supplying an extension) + * This will create a file called "myFile.zip.hash". + * . + * {code:bash} + * checksum path=myFile.zip extension=hash --write + * {code} + * + * Control the format of the hash with the "format" parameter. + * + * {code:bash} + * - "checksum" (default) -- just the hash + * - "md5sum" -- The format of GNU textutils md5sum + * - "sfv" -- The format of BSDs md5 command + * {code} + * + * Verify a file against an existing hash. Error will be thrown if checksums are different + * . + * {code:bash} + * checksum path=myFile.zip verify=2A95F32028087699CCBEB09AFDA0348C * {code} * **/ component { - variables.algorithms = 'MD5,SHA1,SHA-1,SHA-256,SHA-512'; + variables.algorithms = 'md5,sha1,sha-1,sha-256,sha-512'; + variables.formats = 'checksum,md5sum,sfv'; /** * @path Path of file or globbing pattern to create checksum of * @algorithm Hashing algorithm to use * @algorithm.optionsUDF algorithmComplete + * @extension File extension to write. Using this sets write to true. + * @extension.optionsUDF algorithmComplete + * @format Format to write hash in. checksum, md5sum, or sfv + * @format.optionsUDF formatComplete + * @verify A hash to verify to a file. Error will be thrown if checksums don't match. + * @write Set true to write checksum to a file instead of outputting to console **/ function run( required Globber path, - String algorithm='MD5' ) { + String algorithm='md5', + String extension, + String format='checksum', + String verify='', + Boolean write=false + ) { + // Setting extension, defaults write to on. + if( !isNull( extension ) ) { + write = true; + } + // Default extension is algorithm name + extension = extension ?: algorithm; + // validate format + if( !variables.formats.listFindNoCase( format ) ) { + error( 'The checksum format [#format#] is not supported' ); + } + + // Validate algorithm if( !variables.algorithms.listFindNoCase( algorithm ) ) { error( 'The hashing algorithm [#algorithm#] is not supported' ); } - + + // If file or glog doesn't exist, error. if( !path.count() ) { error( "File or globbing pattern doesn't exist. I can't hash thin air! [#path.getPattern()#]" ); } - // If matching single file, just hash that file - if( path.count() == 1 ) { - print.text( hash( fileReadBinary( path.asArray().matches()[ 1 ] ), algorithm ) ); - // If matching directory, hash the query - } else { - print.text( hash( serializeJSON( path.asQuery().matches() ), algorithm ) ); + // If verifying a hash, only one file can be matched + if( verify.len() && path.count() > 1 ) { + error( 'You can only verify a single hash/file at a time.' ); } + // Loop over matched globbing patterns + path.apply( function( thisPath ){ + var thisHash = hash( fileReadBinary( thisPath ), algorithm ); + + // Verifying incoming hash + if( verify.len() ) { + // Doesn't match + if( compare( thisHash, verify ) != 0 ) { + error( 'File checksum [#thisHash#] does not match incoming verification checksum [#verify#].' ); + // Does match + } else { + print.greenLine( 'Checksum matches [#thisHash#]' ); + return; + } + } + + // Default output format is just the checksum + var formattedHash = thisHash; + + // Match the format of GNU textutils md5sum + if( format == 'md5sum' ) { + var formattedHash = thisHash & ' *' & listLast( thisPath, '/\' ); + // Match the format of BSDs md5 command + } else if( format == 'sfv' ) { + var formattedHash = '(' & listLast( thisPath, '/\' ) & ')' & ' = ' & thisHash; + } + + // If writing file + if( write ) { + fileWrite( thisPath & '.' & extension, formattedHash ); + // If outputting + } else { + + print + .text( formattedHash ) + .toConsole(); + + // If we're doing more than one hash, put a line break in. + if( path.count() > 1 ) { + print.line(); + } + + } + } ); + } function algorithmComplete() { return variables.algorithms.listToArray(); } + function formatComplete() { + return variables.formats.listToArray(); + } + + + } \ No newline at end of file diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 632280495..d9f450f07 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -706,10 +706,10 @@ component accessors="true" singleton { var commandData = createCommandData( fullCFCPath, commandName ); // This will catch nasty parse errors so the shell can keep loading } catch( any e ){ - systemOutput( 'Error registering command [#fullCFCPath#] #CR##e.message# #e.detail ?: ''##CR#Check the logs with [system-log | open] for more info.', true ); + systemOutput( 'Error registering command [#fullCFCPath#]', true ); logger.error( 'Error registering command [#fullCFCPath#]. #e.message# #e.detail ?: ''#', e.stackTrace ); // pretty print the exception - // shell.printError( e ); + shell.printError( e ); return; } From 0057da6c209dbbb58687b8b20537dac60c473067 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 16 May 2017 11:23:26 -0500 Subject: [PATCH 069/123] COMMANDBOX-621 --- src/cfml/system/services/ServerService.cfc | 65 ++++++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index e5c273bc0..6432b98f1 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -908,6 +908,7 @@ component accessors="true" singleton { args.append( '--urlrewrite-file' ).append( serverInfo.rewritesConfig ); } // change status to starting + persist + serverInfo.dateLastStarted = now(); serverInfo.status = "starting"; setServerInfo( serverInfo ); @@ -1121,7 +1122,15 @@ component accessors="true" singleton { if( !len( defaultName ) ) { // If there is still no name, default to the current directory // TODO: I don't care for this because it creates conflicts since many servers could have the name "webroot" on one machine. - defaultName = replace( listLast( defaultwebroot, "\/" ), ':', ''); + defaultName = replace( listLast( defaultwebroot, "\/" ), ':', ''); + + // Don't overlap an existing server name + var originalName = defaultName; + var nameCounter = 1; + while( structCount( getServerInfoByName( defaultName ) ) ) { + defaultName = originalName & ++nameCounter; + } + } // We need a new entry @@ -1306,7 +1315,8 @@ component accessors="true" singleton { function setServerInfo( required struct serverInfo ){ var servers = getServers(); - var webrootHash = hash( arguments.serverInfo.webroot & ucase( arguments.serverInfo.name ) ); + var normalizedWebroot = normalizeWebroot( arguments.serverInfo.webroot ); + var webrootHash = hash( normalizedWebroot & ucase( arguments.serverInfo.name ) ); arguments.serverInfo.id = webrootHash; if( arguments.serverInfo.webroot == "" ){ @@ -1318,6 +1328,16 @@ component accessors="true" singleton { setServers( servers ); } + + function normalizeWebroot( required string webroot ) { + if( webroot contains '/' && !webroot.endsWith( '/' ) ) { + return webroot & '/'; + } + if( webroot contains '\' && !webroot.endsWith( '\' ) ) { + return webroot & '\'; + } + return webroot; + } /** * Create initial server JSON @@ -1347,17 +1367,42 @@ component accessors="true" singleton { lock name="serverservice.serverconfig" type="readOnly" throwOnTimeout="true" timeout="10"{ var results = deserializeJSON( fileRead( variables.serverConfig ) ); var updateRequired = false; + var serverKeys = results.keyArray(); // Loop over each server for some housekeeping - for( var thisKey in results ){ + for( var thisKey in serverKeys ){ + // This server may have gotten deleted already based on the cleanup below. + if( !results.keyExists( thisKey ) ) { + continue; + } + var thisServer = results[ thisKey ]; // Backwards compat-- add in server id if it doesn't exist for older versions of CommandBox - if( isNull( results[ thisKey ].id ) ){ - results[ thisKey ].id = hash( results[ thisKey ].webroot & ucase( results[ thisKey ].name ) ); + if( isNull( thisServer.id ) ){ + var normalizedWebroot = normalizeWebroot( thisServer.webroot ); + thisServer.id = hash( normalizedWebroot & ucase( thisServer.name ) ); updateRequired = true; } + + // Try and clean up orphaned server names that were missing the slash on the path and + // ended up with a different hash. + // I really have no idea how this happens. I can't repro it on-demand. + for( var orphanKey in results ){ + var orphan = results[ orphanKey ]; + // If this is another server with the same name and the same webroot but without a trailing slash... + if( orphan.id != thisServer.id + && orphan.name == thisServer.name + && ( thisServer.webroot.endsWith( '\' ) || thisServer.webroot.endsWith( '/' ) ) + && ( !orphan.webroot.endsWith( '\' ) || !orphan.webroot.endsWith( '/' ) ) + && ( orphan.webroot & '\' == thisServer.webroot || orphan.webroot & '/' == thisServer.webroot ) ) { + // ...kill it dead. + results.delete( orphanKey ); + updateRequired = true; + } + } + // Future-proof server info by guaranteeing that all properties will exist in the // server object as long as they are defined in the newServerInfoStruct() method. - results[ thisKey ].append( newServerInfoStruct(), false ); + thisServer.append( newServerInfoStruct(), false ); } } // If any server didn't have an ID, go ahead and save it now @@ -1476,6 +1521,14 @@ component accessors="true" singleton { serverInfo.id = webrootHash; serverInfo.webroot = arguments.webroot; serverInfo.name = listLast( arguments.webroot, "\/" ); + + // Don't overlap an existing server name + var originalName = serverInfo.name; + var nameCounter = 1; + while( structCount( getServerInfoByName( serverInfo.name ) ) ) { + serverInfo.name = originalName & ++nameCounter; + } + // Store it in server struct servers[ webrootHash ] = serverInfo; } From fd24a5191fa21bca9d853e7875ae52f325450a60 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 16 May 2017 11:28:28 -0500 Subject: [PATCH 070/123] COMMANDBOX-622 --- .../modules_app/server-commands/commands/server/list.cfc | 6 ++++++ .../modules_app/server-commands/commands/server/status.cfc | 3 +++ src/cfml/system/services/ServerService.cfc | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/list.cfc b/src/cfml/system/modules_app/server-commands/commands/server/list.cfc index 503bffcc0..0177039f7 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/list.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/list.cfc @@ -98,6 +98,9 @@ component { } else { print.indentedLine( "webroot: " & thisServerInfo.webroot ); } + if( len( thisServerInfo.dateLastStarted ) ) { + print.indentedLine( 'Last Started: ' & datetimeFormat( thisServerInfo.dateLastStarted ) ); + } print.indentedLine( "HTTPEnable: " & thisServerInfo.HTTPEnable ) .indentedLine( "port: " & thisServerInfo.port ) .indentedLine( "SSLEnable: " & thisServerInfo.SSLEnable ) @@ -131,6 +134,9 @@ component { } else { print.indentedLine( 'Webroot: ' & thisServerInfo.webroot ); } + if( len( thisServerInfo.dateLastStarted ) ) { + print.indentedLine( 'Last Started: ' & datetimeFormat( thisServerInfo.dateLastStarted ) ); + } }// end verbose } // End "filter" if diff --git a/src/cfml/system/modules_app/server-commands/commands/server/status.cfc b/src/cfml/system/modules_app/server-commands/commands/server/status.cfc index 215fe41bc..5e9e2bb17 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/status.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/status.cfc @@ -144,6 +144,9 @@ component aliases='status,server info' { if( len( serverInfo.warPath ) ) { print.indentedLine( 'WAR Path: ' & serverInfo.warPath ); } + if( len( serverInfo.dateLastStarted ) ) { + print.indentedLine( 'Last Started: ' & datetimeFormat( serverInfo.dateLastStarted ) ); + } print.line(); print.indentedLine( 'Last status message: ' ); print.indentedLine( thisServerInfo.statusInfo.result ); diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 6432b98f1..09a3bccde 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1586,7 +1586,8 @@ component accessors="true" singleton { 'serverConfigFile' : "", 'aliases' : {}, 'errorPages' : {}, - 'trayOptions' : {} + 'trayOptions' : {}, + 'dateLastStarted' : '' }; } From 23d9ae856da387a0b52b5431c6cfde78d336db97 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 17 May 2017 23:06:34 -0500 Subject: [PATCH 071/123] COMMANDBOX-623 --- src/cfml/system/services/ServerService.cfc | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 09a3bccde..02f52bede 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -112,6 +112,7 @@ component accessors="true" singleton { return { 'name' : d.name ?: '', 'openBrowser' : d.openBrowser ?: true, + 'openBrowserURL' : d.openBrowserURL ?: '', 'startTimeout' : 240, 'stopsocket' : d.stopsocket ?: 0, 'debug' : d.debug ?: false, @@ -442,6 +443,9 @@ component accessors="true" singleton { serverInfo.trace = serverProps.trace ?: serverJSON.trace ?: defaults.trace; serverInfo.debug = serverProps.debug ?: serverJSON.debug ?: defaults.debug; serverInfo.openbrowser = serverProps.openbrowser ?: serverJSON.openbrowser ?: defaults.openbrowser; + serverInfo.openbrowserURL = serverProps.openbrowserURL ?: serverJSON.openbrowserURL ?: defaults.openbrowserURL; + + serverInfo.host = serverProps.host ?: serverJSON.web.host ?: defaults.web.host; // If the last port we used is taken, remove it from consideration. if( serverInfo.port == 0 || !isPortAvailable( serverInfo.host, serverInfo.port ) ) { serverInfo.delete( 'port' ); } @@ -468,6 +472,17 @@ component accessors="true" singleton { serverInfo.port = getRandomPort( serverInfo.host ); } + // If there's no open URL, let's create a complete one + if( !serverInfo.openbrowserURL.len() ) { + serverInfo.openbrowserURL = serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#'; + // Partial URL like /admin/login.cm + } else if ( left( serverInfo.openbrowserURL, 4 ) != 'http' ) { + if( !serverInfo.openbrowserURL.startsWith( '/' ) ) { + serverInfo.openbrowserURL = '/' & serverInfo.openbrowserURL; + } + serverInfo.openbrowserURL = ( serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#' ) & serverInfo.openbrowserURL; + } + serverInfo.stopsocket = serverProps.stopsocket ?: serverJSON.stopsocket ?: getRandomPort( serverInfo.host ); // relative trayIcon in server.json is resolved relative to the server.json @@ -724,7 +739,7 @@ component accessors="true" singleton { serverInfo.trayOptions.prepend( { 'label':'Open Server Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/CFIDE/administrator/enter.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/server_settings.png' ) } ); } - serverInfo.trayOptions.prepend( { 'label':'Open Browser', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/', 'image' : expandPath('/commandbox/system/config/server-icons/home.png' ) } ); + serverInfo.trayOptions.prepend( { 'label':'Open Browser', 'action':'openbrowser', 'url': serverInfo.openbrowserURL, 'image' : expandPath('/commandbox/system/config/server-icons/home.png' ) } ); serverInfo.trayOptions.prepend( { 'label':'Stop Server', 'action':'stopserver', 'image' : expandPath('/commandbox/system/config/server-icons/stop.png' ) } ); serverInfo.trayOptions.prepend( { 'label': processName, 'disabled':true, 'image' : expandPath('/commandbox/system/config/server-icons/info.png' ) } ); @@ -798,7 +813,7 @@ component accessors="true" singleton { .append( '--processname' ).append( processName ) .append( '--log-dir' ).append( serverInfo.logDir ) .append( '--open-browser' ).append( serverInfo.openbrowser ) - .append( '--open-url' ).append( ( serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#' ) ) + .append( '--open-url' ).append( serverInfo.openbrowserURL ) .append( '--server-name' ).append( serverInfo.name ) .append( '--tray-icon' ).append( serverInfo.trayIcon ) .append( '--tray-config' ).append( trayOptionsPath ) @@ -1587,7 +1602,9 @@ component accessors="true" singleton { 'aliases' : {}, 'errorPages' : {}, 'trayOptions' : {}, - 'dateLastStarted' : '' + 'dateLastStarted' : '', + 'openBrowser' : true, + 'openBrowserURL' : '' }; } From 9d8724c53a764f83edd9f4a3a2daf1de00bf535f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 18 May 2017 00:03:24 -0500 Subject: [PATCH 072/123] COMMANDBOX-590 --- src/cfml/system/BaseCommand.cfc | 33 ++-- src/cfml/system/box.json | 6 +- .../modules/propertyFile/ModuleConfig.cfc | 8 + src/cfml/system/modules/propertyFile/box.json | 27 +++ .../propertyFile/models/PropertyFile.cfc | 154 ++++++++++++++++++ .../system/modules/propertyFile/readme.md | 76 +++++++++ .../commands/propertyFile/clear.cfc | 34 ++++ .../commands/propertyFile/set.cfc | 36 ++++ .../commands/propertyFile/show.cfc | 48 ++++++ 9 files changed, 409 insertions(+), 13 deletions(-) create mode 100644 src/cfml/system/modules/propertyFile/ModuleConfig.cfc create mode 100644 src/cfml/system/modules/propertyFile/box.json create mode 100644 src/cfml/system/modules/propertyFile/models/PropertyFile.cfc create mode 100644 src/cfml/system/modules/propertyFile/readme.md create mode 100644 src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc create mode 100644 src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc create mode 100644 src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index b55d338ea..efd39fc2e 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -120,6 +120,28 @@ component accessors="true" singleton { function watch() { return getinstance( 'watcher' ); } + + /** + * Return a new globber + **/ + function globber( pattern='' ) { + var globber = wirebox.getInstance( 'Globber' ); + if( pattern.len() ) { + globber.setPattern( arguments.pattern ); + } + return globber; + } + + /** + * Return a new PropertyFile instance + **/ + function propertyFile( propertyFilePath='' ) { + var propertyFile = wirebox.getInstance( 'propertyFile@propertyFile' ); + if( propertyFilePath.len() ) { + propertyFile.load( propertyFilePath ); + } + return propertyFile; + } /** * Use if if your command wants to give controlled feedback to the user without raising @@ -183,15 +205,4 @@ component accessors="true" singleton { .run(); } - /** - * Return a new globber - **/ - function globber( pattern='' ) { - var globber = wirebox.getInstance( 'Globber' ); - if( pattern.len() ) { - globber.setPattern( arguments.pattern ); - } - return globber; - } - } \ No newline at end of file diff --git a/src/cfml/system/box.json b/src/cfml/system/box.json index 9f742318a..cfa8d2c2e 100644 --- a/src/cfml/system/box.json +++ b/src/cfml/system/box.json @@ -7,7 +7,8 @@ "string-similarity":"^1.0.0", "semver":"^1.0.0", "globber":"^2.0.0", - "JSONPrettyPrint":"^1.0.0" + "JSONPrettyPrint":"^1.0.0", + "propertyFile":"^1.0.9" }, "devDependencies":{ @@ -16,6 +17,7 @@ "string-similarity":"modules\\string-similarity", "semver":"modules\\semver", "globber":"modules\\globber", - "JSONPrettyPrint":"modules\\JSONPrettyPrint" + "JSONPrettyPrint":"modules\\JSONPrettyPrint", + "propertyFile":"modules\\propertyFile" } } \ No newline at end of file diff --git a/src/cfml/system/modules/propertyFile/ModuleConfig.cfc b/src/cfml/system/modules/propertyFile/ModuleConfig.cfc new file mode 100644 index 000000000..f95e7055a --- /dev/null +++ b/src/cfml/system/modules/propertyFile/ModuleConfig.cfc @@ -0,0 +1,8 @@ +component { + + this.autoMapModels = true; + + function configure(){ + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules/propertyFile/box.json b/src/cfml/system/modules/propertyFile/box.json new file mode 100644 index 000000000..f75167acf --- /dev/null +++ b/src/cfml/system/modules/propertyFile/box.json @@ -0,0 +1,27 @@ +{ + "name":"PropertyFile Util", + "version":"1.1.0", + "author":"Brad Wood", + "location":"bdw429s/PropertyFile#v1.1.0", + "homepage":"https://github.com/bdw429s/PropertyFile/", + "documentation":"https://github.com/bdw429s/PropertyFile/blob/master/readme.md", + "repository":{ + "type":"Git", + "URL":"https://github.com/bdw429s/PropertyFile" + }, + "bugs":"https://github.com/bdw429s/PropertyFile/issues", + "slug":"propertyFile", + "shortDescription":"A library for managing Java property files", + "type":"modules", + "keywords":"java,property,files", + "projectURL":"https://github.com/bdw429s/PropertyFile/", + "scripts":{ + "postVersion":"package set location='bdw429s/PropertyFile#v`package version`'", + "postPublish":"!git push --follow-tags" + }, + "ignore":[ + "**/.*", + "test", + "tests" + ] +} \ No newline at end of file diff --git a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc new file mode 100644 index 000000000..e5d6df223 --- /dev/null +++ b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc @@ -0,0 +1,154 @@ +/** +* I am a new Model Object +*/ +component accessors="true"{ + + // Properties + property name='javaPropertyFile'; + property name='path'; + property name='syncedNames'; + + + /** + * Constructor + */ + PropertyFile function init(){ + setSyncedNames( [] ); + setJavaPropertyFile( createObject( 'java', 'java.util.Properties' ).init() ); + return this; + } + + /** + * load + */ + function load( required string path){ + setPath( arguments.path ); + var fis = CreateObject( 'java', 'java.io.FileInputStream' ).init( expandPath( path ) ); + var BOMfis = CreateObject( 'java', 'org.apache.commons.io.input.BOMInputStream' ).init( fis ); + var propertyFile = getJavaPropertyFile(); + propertyFile.load( BOMfis ); + BOMfis.close(); + + + var props = propertyFile.propertyNames(); + var syncedNames = getSyncedNames(); + while( props.hasMoreElements() ) { + var prop = props.nextElement(); + this[ prop ] = get( prop ); + syncedNames.append( prop ); + } + setSyncedNames( syncedNames ); + + return this; + } + + /** + * store + */ + function store( string path=variables.path ){ + syncProperties(); + + if( !fileExists( arguments.path ) ) { + directoryCreate( getDirectoryFromPath( arguments.path ), true, true ); + fileWrite( arguments.path, '' ); + } + + var fos = CreateObject( 'java', 'java.io.FileOutputStream' ).init( expandPath( arguments.path ) ); + getJavaPropertyFile().store( fos, '' ); + fos.close(); + + return this; + } + + /** + * get + */ + function get( required string name, string defaultValue ){ + if( structKeyExists( arguments, 'defaultValue' ) ) { + return getJavaPropertyFile().getProperty( name, defaultValue ); + } else if( exists( name ) ) { + return getJavaPropertyFile().getProperty( name ); + } else { + throw 'Key [#name#] does not exist in this properties file'; + } + } + + /** + * set + */ + function set( required string name, required string value ){ + getJavaPropertyFile().setProperty( name, value ); + + var syncedNames = getSyncedNames(); + this[ name ] = value; + if( !arrayContains( syncedNames, name ) ){ + syncedNames.append( name ); + } + setSyncedNames( syncedNames ); + + return this; + } + + /** + * clear + */ + function remove( required string name ){ + if( exists( name ) ) { + getJavaPropertyFile().remove( name ); + + var syncedNames = getSyncedNames(); + if( arrayFind( syncedNames, name ) ){ + syncedNames.deleteAt( arrayFind( syncedNames, name ) ); + } + setSyncedNames( syncedNames ); + structDelete( this, name ); + } + return this; + } + + /** + * exists + */ + function exists( required string name ){ + return getJavaPropertyFile().containsKey( name ); + } + + /** + * getAsStruct + */ + function getAsStruct(){ + syncProperties(); + var result = {}; + structAppend( result, getJavaPropertyFile() ); + return result; + } + + /** + * Keeps public properties in sync with Java object + */ + private function syncProperties() { + var syncedNames = getSyncedNames(); + var ignore = listToArray( 'init,load,store,get,set,exists,remove,exists,getAsStruct,$mixed' ); + var propertyFile = getJavaPropertyFile(); + + // This CFC's public properties + for( var prop in this ) { + // Set any new/updated properties in, excluding actual methods and non-simple values + if( !ignore.findNoCase( prop ) && isSimpleValue( this[ prop ] ) ) { + set( prop, this[ prop ] ); + } + } + + // All the properties in the Java object + var props = propertyFile.propertyNames(); + while( props.hasMoreElements() ) { + var prop = props.nextElement(); + // Remove any properties that were deleted off the CFC's public scope + if( !structKeyExists( this, prop ) ) { + remove( prop ); + } + } + + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules/propertyFile/readme.md b/src/cfml/system/modules/propertyFile/readme.md new file mode 100644 index 000000000..e9e51c894 --- /dev/null +++ b/src/cfml/system/modules/propertyFile/readme.md @@ -0,0 +1,76 @@ +# PropertyFile Utility for CFML + +`ProperyFile` is a library to make it is easy to load, modify, and store Java property files from CFML without needing to touch any Java. This library is a single CFC that encapsulates the data and behaviors of a Java properties file in a fluent API. + +```js +getInstance( 'propertyFile' ) + .load( myPath ) + .set( 'myProp', 'myValue' ) + .store(); +``` + +## Read files + +To use, create an instance of `PropertyFile` and call the `load()` method with the full path to the file you wish to load. + +```js +var propertyFile = getInstance( 'propertyFile' ).load( expandPath( 'myFile.properties' ) ); +``` + +## Manipulate properties + +We support two ways of interacting with the file. You can call methods to get/set/remove properties like so: + +```js +propertyFile.set( 'myProp', 'myValue' ); +propertyFile.get( 'myProp' ); +propertyFile.get( 'anotherProp', 'defaultValue' ); +propertyFile.exists( 'questionableProp' ); +``` + +Or you can just use the object directly as a struct and we'll treat the public properties with a dab of fairy dust to keep track of them. This code block does the same as above. + +```js +propertyFile.myProp = 'myValue'; +propertyFile.myProp; +propertyFile.anotherProp ?: 'defaultValue'; +structKeyExists( propertyFile, 'questionableProp' ); +``` + +Note, this method will give you some issues if you happen to have any property names that conflict with built-in method names since they live in the `this` scope too. Also, make sure property names with periods in them are set like `propertyFile[ 'this.is.my.prop' ]` and NOT like `propertyFile.this.is.my.prop`. The latter will create nested structs instead of a single property which isn't what you want. + +## Iterate properties + +If you want to get the properties in an iterable form, use this method: +```js +var myStruct = propertyFile.getAsStruct(); +for( var prop in myStruct ) { + writeDump( myStruct[ prop ] ); +} +``` + +## Store properties + +To write a properties file back to the same file you read it from use this `store()` method with no arguments. + +```js +propertyFile.store(); +``` + +To save what's in memory to a new file (or to save a new properties object that you didn't read in the first place), pass the `path` you want into the `store()` method. + +```js +propertyFile.store( expandPath( 'myNewFile.properties' ) ); +``` + +## Method Chaining + +All methods in the PropertyFile object that don't return an explicit value will return `this` so you can chain calls like so: + +```js +getInstance( 'propertyFile' ) + .load( myPath ) + .set( 'myProp', 'myValue' ) + .set( 'myOtherProp', 'myOtherValue' ) + .store(); +``` diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc new file mode 100644 index 000000000..7109cfb9d --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc @@ -0,0 +1,34 @@ +/** + * Remove a property from a property file. + * . + * {code:bash} + * propertyFile clear my.name + * {code} + * + **/ +component { + + /** + * @propertyFilePath The path to the property file to interact with + * @propertyName The name of the property to clear + **/ + function run( + required string propertyFilePath, + required string propertyName + ) { + + // This will make each directory canonical and absolute + propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); + + // Create and load property file object + propertyFile( propertyFilePath ) + .remove( propertyName ) + .store(); + + print + .greenLine( 'Property removed!' ) + .line( propertyName ); + + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc new file mode 100644 index 000000000..58c7b8bdd --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc @@ -0,0 +1,36 @@ +/** + * Set property into a property file. + * . + * {code:bash} + * propertyFile set name=mySetting + * {code} + * + **/ +component { + + /** + * @propertyFilePath The path to the property file to interact with + * @propertyName The name of the property to set + * @propertyValue The value of the property to set + **/ + function run( + required string propertyFilePath, + required string propertyName, + required string propertyValue + ) { + + // This will make each directory canonical and absolute + propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); + + // Create and load property file object + propertyFile( propertyFilePath ) + .set( propertyName, propertyValue ) + .store(); + + print + .greenLine( 'Property set!' ) + .line( propertyName & ' = ' & propertyValue ); + + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc new file mode 100644 index 000000000..cc2621336 --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc @@ -0,0 +1,48 @@ +/** + * View the contents of a .properties file + * . + * Output a single property, all properties, or all properties as JSON. + * {code:bash} + * propertyFile show + * propertyFile show property.name.here + * propertyFile show --JSON + * {code} + * + **/ +component { + + /** + * @propertyFilePath The path to the property file to interact with + * @propertyName The name of the property to show + * @JSON Return all the properties in the file as JSON + **/ + function run( + required string propertyFilePath, + string propertyName='', + boolean JSON=false + ) { + + // This will make each directory canonical and absolute + propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); + + // Create and load property file object + var propertyFile = propertyFile( propertyFilePath ); + + // JSON output takes precedence + if( JSON ) { + print.text( formatterUtil.formatJson( propertyFile.getAsStruct() ) ); + // Output single property + } else if( propertyName.len() ) { + print.text( propertyFile.get( propertyName ) ); + // Output all properties + } else { + var properties = propertyFile.getAsStruct(); + properties + .each( function( i ) { + print.line( i & ' = ' & properties[ i ] ); + } ); + } + + } + +} \ No newline at end of file From 6ec9847cd3fcfb44f2d9d12141e73ec89aa0f9b1 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 18 May 2017 01:30:27 -0500 Subject: [PATCH 073/123] COMMANDBOX-564 --- src/cfml/system/BaseCommand.cfc | 35 ++++++++- src/cfml/system/services/ModuleService.cfc | 18 +++-- src/cfml/system/util/SystemSettings.cfc | 90 ++++++++++++++++++++++ 3 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 src/cfml/system/util/SystemSettings.cfc diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index efd39fc2e..2f09b22f3 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -19,12 +19,13 @@ component accessors="true" singleton { property name="wirebox"; property name="logger"; property name="parser"; + property name="SystemSettings"; /** * Constructor */ function init() { - variables.wirebox = application.wirebox; + variables.wirebox = application.wirebox; variables.CR = wirebox.getInstance( "CR@constants" ); variables.formatterUtil = wirebox.getInstance( "Formatter" ); variables.fileSystemUtil = wirebox.getInstance( "FileSystem" ); @@ -33,6 +34,7 @@ component accessors="true" singleton { variables.logger = wirebox.getLogBox().getLogger( this ); variables.parser = wirebox.getInstance( "Parser" ); variables.configService = wirebox.getInstance( "ConfigService" ); + variables.SystemSettings = wirebox.getInstance( "SystemSettings" ); hasErrored = false; return this; @@ -204,5 +206,36 @@ component accessors="true" singleton { .params( arguments.theURL ) .run(); } + + /** + * Retrieve a Java System property or env value by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the system properties + */ + function getSystemSetting( required string key, defaultValue ) { + return systemSettings.getSystemSetting( argumentCollection=arguments ); + } + + /** + * Retrieve a Java System property by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the system properties + */ + function getSystemProperty( required string key, defaultValue ) { + return systemSettings.getSystemProperty( argumentCollection=arguments ); + } + + /** + * Retrieve an env value by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the env + */ + function getEnv( required string key, defaultValue ) { + return systemSettings.getEnv( argumentCollection=arguments ); + } + } \ No newline at end of file diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index 9f5aedeee..aa83183d3 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -21,6 +21,7 @@ + @@ -631,13 +632,16 @@ oConfig.getPropertyMixin = mixerUtil.getPropertyMixin; // MixIn Variables - oConfig.injectPropertyMixin( "shell", shell ); - oConfig.injectPropertyMixin( "moduleMapping", mConfig.mapping ); - oConfig.injectPropertyMixin( "modulePath", mConfig.path ); - oConfig.injectPropertyMixin( "logBox", shell.getLogBox() ); - oConfig.injectPropertyMixin( "log", shell.getLogBox().getLogger( oConfig) ); - oConfig.injectPropertyMixin( "wirebox", shell.getWireBox() ); - oConfig.injectPropertyMixin( "binder", shell.getWireBox().getBinder() ); + oConfig.injectPropertyMixin( "shell", shell ); + oConfig.injectPropertyMixin( "moduleMapping", mConfig.mapping ); + oConfig.injectPropertyMixin( "modulePath", mConfig.path ); + oConfig.injectPropertyMixin( "logBox", shell.getLogBox() ); + oConfig.injectPropertyMixin( "log", shell.getLogBox().getLogger( oConfig) ); + oConfig.injectPropertyMixin( "wirebox", shell.getWireBox() ); + oConfig.injectPropertyMixin( "binder", shell.getWireBox().getBinder() ); + oConfig.injectPropertyMixin( "getSystemSetting", systemSettings.getSystemSetting ); + oConfig.injectPropertyMixin( "getSystemProperty", systemSettings.getSystemProperty ); + oConfig.injectPropertyMixin( "getEnv", systemSettings.getEnv ); // Configure the module oConfig.configure(); diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc new file mode 100644 index 000000000..1ba13361a --- /dev/null +++ b/src/cfml/system/util/SystemSettings.cfc @@ -0,0 +1,90 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I handled accessing environment variables and system properties +* +*/ +component singleton { + + variables.system = createObject( "java", "java.lang.System" ); + + /** + * Retrieve a Java System property or env value by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the system properties + */ + function getSystemSetting( required string key, defaultValue ) { + + var value = system.getProperty( arguments.key ); + if ( ! isNull( value ) ) { + return value; + } + + value = system.getEnv( arguments.key ); + if ( ! isNull( value ) ) { + return value; + } + + if ( ! isNull( arguments.defaultValue ) ) { + return arguments.defaultValue; + } + + throw( + type = "SystemSettingNotFound", + message = "Could not find a Java System property or Env setting with key [#arguments.key#]." + ); + } + + /** + * Retrieve a Java System property by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the system properties + */ + function getSystemProperty( required string key, defaultValue ) { + + var value = system.getProperty( arguments.key ); + if ( ! isNull( value ) ) { + return value; + } + + if ( ! isNull( arguments.defaultValue ) ) { + return arguments.defaultValue; + } + + throw( + type = "SystemSettingNotFound", + message = "Could not find a Java System property with key [#arguments.key#]." + ); + } + + /** + * Retrieve an env value by name. + * + * @key The name of the setting to look up. + * @defaultValue The default value to use if the key does not exist in the env + */ + function getEnv( required string key, defaultValue ) { + + var value = system.getEnv( arguments.key ); + if ( ! isNull( value ) ) { + return value; + } + + if ( ! isNull( arguments.defaultValue ) ) { + return arguments.defaultValue; + } + + throw( + type = "SystemSettingNotFound", + message = "Could not find a env property with key [#arguments.key#]." + ); + + } + +} \ No newline at end of file From c564663c6b0c98948a1af1d789f941be6c251026 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 19 May 2017 00:41:15 -0500 Subject: [PATCH 074/123] COMMANDBOX-564 --- src/cfml/system/services/CommandService.cfc | 43 +++++++++++++++++- src/cfml/system/services/PackageService.cfc | 17 +++++-- src/cfml/system/services/ServerService.cfc | 6 ++- src/cfml/system/util/Parser.cfc | 17 ++++++- src/cfml/system/util/SystemSettings.cfc | 50 +++++++++++++++++++++ 5 files changed, 125 insertions(+), 8 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index d9f450f07..6ccf37b9d 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -23,7 +23,8 @@ component accessors="true" singleton { property name='interceptorService' inject='interceptorService'; // Using provider since CommandService is created before modules are loaded property name='stringDistance' inject='provider:StringSimilarity@string-similarity'; - + property name='SystemSettings' inject='SystemSettings'; + property name='configured' default="false" type="boolean"; // TODO: Convert these to properties @@ -267,8 +268,9 @@ component accessors="true" singleton { // Make sure we have all required params. parameterInfo.namedParameters = ensureRequiredParams( parameterInfo.namedParameters, commandParams ); - // Evaluate parameter expressions + // Evaluate parameter expressions and system settings evaluateExpressions( parameterInfo ); + evaluateSystemSettings( parameterInfo ); // Create globbing patterns createGlobs( parameterInfo, commandParams ); @@ -420,6 +422,43 @@ component accessors="true" singleton { } } + + /** + * Evaluates any system settings and puts the output in its place. + */ + function evaluateSystemSettings( required parameterInfo ) { + + // For each parameter being passed into this command + for( var paramName in parameterInfo.namedParameters ) { + + var paramValue = parameterInfo.namedParameters[ paramName ]; + // Look for a system setting "foo" flagged as "__system__foo__system__" + var search = reFindNoCase( '__system__.*?__system__', paramValue, 1, true ); + + // As long as there are more system settings + while( search.pos[1] ) { + // Extract them + var systemSetting = mid( paramValue, search.pos[1], search.len[1] ); + // Evaluate them + var settingName = mid( systemSetting, 11, len( systemSetting )-20 ); + var defaultValue = ''; + if( settingName.listLen( ':' ) ) { + defaultValue = settingName.listRest( ':' ); + settingName = settingName.listFirst( ':' ); + } + var result = systemSettings.getSystemSetting( settingName, defaultValue ); + + // And stick their results in their place + parameterInfo.namedParameters[ paramName ] = replaceNoCase( paramValue, systemSetting, result, 'one' ); + paramValue = parameterInfo.namedParameters[ paramName ]; + // Search again + var search = reFindNoCase( '__system__.*?__system__', paramValue, 1, true ); + } + } + } + + + /** * Take an array of parameters and parse them out as named or positional * @parameters.hint The array of params to parse. diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 1e916269e..55407494d 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -22,6 +22,7 @@ component accessors="true" singleton { property name='consoleLogger' inject='logbox:logger:console'; property name='interceptorService' inject='interceptorService'; property name='JSONService' inject='JSONService'; + property name='systemSettings' inject='SystemSettings'; /** * Constructor @@ -821,12 +822,22 @@ component accessors="true" singleton { * Get the box.json as data from the passed directory location. * Any missing properties will be defaulted with our box.json template. * If you plan on writing the box.json back out to disk, use readPackageDescriptorRaw() instead. + * + * If you ask for system settings to be swapped out, do not write this box.json back to disk. + * It's has possibly been modified to expand the props like ${foo} and will overwrite the actual place holders + * * @directory The directory to search for the box.json */ - struct function readPackageDescriptor( required directory ){ + struct function readPackageDescriptor( required directory, boolean expandSystemSettings=true ){ // Merge this JSON with defaults - return newPackageDescriptor( readPackageDescriptorRaw( arguments.directory ) ); - } + var results = newPackageDescriptor( readPackageDescriptorRaw( arguments.directory ) ); + // Expand stuff like ${foo:bar} + if( expandSystemSettings ) { + systemSettings.expandDeepSystemSettings( results ); + } + return results + + } /** * Does everything readPackageDescriptor() does, but won't default deprecated box.json proprties. diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 02f52bede..b21e5f97c 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -41,7 +41,8 @@ component accessors="true" singleton { property name='wirebox' inject='wirebox'; property name='CR' inject='CR@constants'; property name='parser' inject='parser'; - + property name='systemSettings' inject='SystemSettings'; + /** * Constructor * @shell.inject shell @@ -437,6 +438,9 @@ component accessors="true" singleton { saveServerJSON( defaultServerConfigFile, serverJSON ); } + systemSettings.expandDeepSystemSettings( serverJSON ); + systemSettings.expandDeepSystemSettings( defaults ); + // Setup serverinfo according to params // Hand-entered values take precendence, then settings saved in server.json, and finally defaults. // The big servers.json is only used to keep a record of the last values the server was started with diff --git a/src/cfml/system/util/Parser.cfc b/src/cfml/system/util/Parser.cfc index f83839c59..c13281734 100644 --- a/src/cfml/system/util/Parser.cfc +++ b/src/cfml/system/util/Parser.cfc @@ -201,8 +201,9 @@ component { // Unwrap quotes from value if used value = unwrapQuotes( value ); - // Mark expressions now while escaped chars are removed + // Mark expressions and system settings now while escaped chars are removed value = markExpressions( value ); + value = markSystemSettings( value ); name = replaceEscapedChars( name ); value = replaceEscapedChars( value ); @@ -214,8 +215,9 @@ component { // Unwrap quotes from value if used param = unwrapQuotes( param ); - // Mark expressions now while escaped chars are removed + // Mark expressions and system settings now while escaped chars are removed param = markExpressions( param ); + param = markSystemSettings( param ); param = replaceEscapedChars( param ); results.positionalParameters.append( param ); @@ -234,6 +236,13 @@ component { return reReplaceNoCase( argValue, '`(.*?)`', '__expression__\1__expression__', 'all' ); } + /** + * Find any strings like ${foo} and flag them as a system setting + */ + function markSystemSettings( required argValue ) { + return reReplaceNoCase( argValue, '\$\{(.*?)}', '__system__\1__system__', 'all' ); + } + /** * Escapes a value and for inclusion in a command * The following replacements are made: @@ -244,6 +253,7 @@ component { * ; --> \; * & --> \& * | --> \| + * ${ --> \${ * [line break] --> \n * [tab] --> \t */ @@ -256,6 +266,7 @@ component { arguments.argValue = replace( arguments.argValue, ";", "\;", "all" ); arguments.argValue = replace( arguments.argValue, "&", "\&", "all" ); arguments.argValue = replace( arguments.argValue, "|", "\|", "all" ); + arguments.argValue = replace( arguments.argValue, "${", "\${", "all" ); arguments.argValue = replace( arguments.argValue, CR, "\n", "all" ); arguments.argValue = replace( arguments.argValue, chr( 9 ), "\t", "all" ); return arguments.argValue; @@ -283,6 +294,7 @@ component { theString = replaceNoCase( theString, '\=', '__equalSign__', "all" ); theString = replaceNoCase( theString, '\;', '__semiColon__', "all" ); theString = replaceNoCase( theString, '\&', '__ampersand__', "all" ); + theString = replaceNoCase( theString, '\${', '__system_setting__', "all" ); return replaceNoCase( theString, '\|', '__pipe__', "all" ); } @@ -296,6 +308,7 @@ component { theString = replaceNoCase( theString, '__equalSign__', '=', "all" ); theString = replaceNoCase( theString, '__semiColon__', ';', "all" ); theString = replaceNoCase( theString, '__ampersand__', '&', "all" ); + theString = replaceNoCase( theString, '__system_setting__', '${', "all" ); return replaceNoCase( theString, '__pipe__', '|', "all" ); } diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index 1ba13361a..6a19b74c8 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -84,7 +84,57 @@ component singleton { type = "SystemSettingNotFound", message = "Could not find a env property with key [#arguments.key#]." ); + + } + + function expandSystemSettings( required string text ) { + // Temporarily remove escaped ones like \${do.not.expand.me} + text = replaceNoCase( text, '\${', '__system_setting__', "all" ); + // Mark all system settings + text = reReplaceNoCase( text, '\$\{(.*?)}', '__system__\1__system__', 'all' ); + // put escaped stuff back + text = replaceNoCase( text, '__system_setting__', '${', "all" ); + // Look for a system setting "foo" flagged as "__system__foo__system__" + var search = reFindNoCase( '__system__.*?__system__', text, 1, true ); + + // As long as there are more system settings + while( search.pos[1] ) { + // Extract them + var systemSetting = mid( text, search.pos[1], search.len[1] ); + // Evaluate them + var settingName = mid( systemSetting, 11, len( systemSetting )-20 ); + var defaultValue = ''; + if( settingName.listLen( ':' ) ) { + defaultValue = settingName.listRest( ':' ); + settingName = settingName.listFirst( ':' ); + } + var result = getSystemSetting( settingName, defaultValue ); + + // And stick their results in their place + text = replaceNoCase( text, systemSetting, result, 'one' ); + // Search again + var search = reFindNoCase( '__system__.*?__system__', text, 1, true ); + } + return text; + } + + function expandDeepSystemSettings( required any dataStructure ) { + if( isStruct( dataStructure ) ) { + for( var key in dataStructure ) { + dataStructure[ key ] = expandDeepSystemSettings( dataStructure[ key ] ); + } + return dataStructure; + } else if( isArray( dataStructure ) ) { + var i = 0; + for( var item in dataStructure ) { + i++; + dataStructure[ i ] = expandDeepSystemSettings( item ); + } + return dataStructure; + } else if ( isSimpleValue( dataStructure ) ) { + return expandSystemSettings( dataStructure ); + } } } \ No newline at end of file From 66168dd23d0d0e8801c7ffdeea9af7c1e6ba3505 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 19 May 2017 01:17:34 -0500 Subject: [PATCH 075/123] Pass through other complex datatypes --- src/cfml/system/util/SystemSettings.cfc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index 6a19b74c8..cceb62d23 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -135,6 +135,7 @@ component singleton { } else if ( isSimpleValue( dataStructure ) ) { return expandSystemSettings( dataStructure ); } + return dataStructure; } } \ No newline at end of file From 0f312507a71aa1db4eb0e97fae464c53151f4e45 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 19 May 2017 14:52:07 -0500 Subject: [PATCH 076/123] Added comments --- src/cfml/system/util/SystemSettings.cfc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index cceb62d23..3d640c74d 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -87,6 +87,13 @@ component singleton { } + + /** + * Expands placeholders like ${foo} in a string with the matching java prop or env var. + * Will replace as many place holders that exist, but will skip escaped ones like \${do.not.expand.me} + * + * @text The string to do the replacement on + */ function expandSystemSettings( required string text ) { // Temporarily remove escaped ones like \${do.not.expand.me} text = replaceNoCase( text, '\${', '__system_setting__', "all" ); @@ -119,22 +126,36 @@ component singleton { return text; } + /** + * Expands placeholders like ${foo} in all deep struct keys and array elements with the matching java prop or env var. + * Will replace as many place holders that exist, but will skip escaped ones like \${do.not.expand.me} + * This will recursivley follow all nested structs and arrays. + * + * @dataStructure A string, struct, or array to perform deep replacement on. + */ function expandDeepSystemSettings( required any dataStructure ) { + // If it's a struct... if( isStruct( dataStructure ) ) { + // Loop over and process each key for( var key in dataStructure ) { dataStructure[ key ] = expandDeepSystemSettings( dataStructure[ key ] ); } return dataStructure; + // If it's an array... } else if( isArray( dataStructure ) ) { var i = 0; + // Loop over and process each index for( var item in dataStructure ) { i++; dataStructure[ i ] = expandDeepSystemSettings( item ); } return dataStructure; + // If it's a string... } else if ( isSimpleValue( dataStructure ) ) { + // Just do the replacement return expandSystemSettings( dataStructure ); } + // Other complex variables like XML or CFC instance would just get skipped for now. return dataStructure; } From 6fa9f7aa171e850cf359899bc4e630b4b7101856 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Sun, 21 May 2017 03:27:53 +0100 Subject: [PATCH 077/123] COMMANDBOX-626 add ability for commandbox modules to register endpoints (#121) --- src/cfml/system/services/EndpointService.cfc | 110 +++++++++---------- src/cfml/system/services/ModuleService.cfc | 51 +++++---- 2 files changed, 87 insertions(+), 74 deletions(-) diff --git a/src/cfml/system/services/EndpointService.cfc b/src/cfml/system/services/EndpointService.cfc index 818962f4d..ee11c3d2a 100644 --- a/src/cfml/system/services/EndpointService.cfc +++ b/src/cfml/system/services/EndpointService.cfc @@ -11,11 +11,11 @@ component accessors="true" singleton { // DI property name="logger" inject="logbox:logger:{this}"; - property name="wirebox" inject="wirebox"; + property name="wirebox" inject="wirebox"; property name="fileSystemUtil" inject="FileSystem"; property name="consoleLogger" inject="logbox:logger:console"; property name="configService" inject="configService"; - + // Properties property name="endpointRegistry" type="struct"; property name="endpointRootPath" type="string" default="/commandbox/system/endpoints"; @@ -28,26 +28,26 @@ component accessors="true" singleton { setEndpointRegistry( {} ); return this; } - + function onDIComplete() { - buildEndpointRegistry(); + buildEndpointRegistry(); } - + /** * Inspect the endpoints folder and register them. - */ - function buildEndpointRegistry() { + */ + function buildEndpointRegistry( string rootDirectory=getEndpointRootPath() ) { // Get the registry var endpointRegistry = getEndpointRegistry(); // Inspect file system for endpoints - var files = directoryList( getEndpointRootPath() ); - + var files = directoryList( arguments.rootDirectory ); + for( var file in files ) { var endpointName = listFirst( listLast( file, '/\' ), '.' ); // Ignore the interfaces if( !listFindNoCase( 'IEndPoint,IEndPointInteractive', endpointName ) ) { - - var endpointPath = listChangeDelims( getEndpointRootPath(), '/\', '.' ) & '.' & endpointName; + + var endpointPath = listChangeDelims( arguments.rootDirectory, '/\', '.' ) & '.' & endpointName; var oEndPoint = wirebox.getInstance( endpointPath ); var namePrefixs = listToArray( oEndPoint.getNamePrefixes() ); for( var prefix in namePrefixs ) { @@ -55,21 +55,21 @@ component accessors="true" singleton { } } } - + } - + /** * Inspects ID and returns name of endpoint. If none is specified, tests for local file * or folder. Defaults to forgebox. * @ID The id of the endpoint * @currentWorkingDirectory Where we are working from - */ + */ struct function resolveEndpointData( required string ID, required string currentWorkingDirectory ) { - + var path = fileSystemUtil.resolvePath( arguments.ID, arguments.currentWorkingDirectory ); // Is it a real zip file? if( listLast( path, '.' ) == 'zip' && fileExists( path ) ) { - var endpointName = 'file'; + var endpointName = 'file'; return { endpointName : endpointName, package : path, @@ -77,7 +77,7 @@ component accessors="true" singleton { }; // Is it a real folder? } else if( directoryExists( path ) ) { - var endpointName = 'folder'; + var endpointName = 'folder'; return { endpointName : endpointName, package : path, @@ -108,30 +108,30 @@ component accessors="true" singleton { } // I give up, let's check ForgeBox (default endpoint) } else { - var endpointName = 'forgebox'; + var endpointName = 'forgebox'; return { endpointName : endpointName, package : arguments.ID, ID : endpointName & ':' & arguments.ID }; - + } // End detecting endpoint } - + /** * Returns the endpoint object. * @endpointName The name of the endpoint to retrieve - */ + */ IEndpoint function getEndpoint( required string endpointName ) { var endpointRegistry = getEndpointRegistry(); if( structKeyExists( endpointRegistry, arguments.endpointName ) ) { return endpointRegistry[ arguments.endpointName ]; } - + // Didn't find it throw( 'Endpoint [#endpointName#] not registered.', 'EndpointNotFound' ); } - + /** * Inspects ID and returns endpoint object, endpointName, and ID (with endpoint stripped). * @ID The id of the endpoint @@ -142,7 +142,7 @@ component accessors="true" singleton { endpointData[ 'endpoint' ] = getEndpoint( endpointData.endpointName ); return endpointData; } - + /** * A facade to create a user with an interactive endpoint. Keeping this logic here so I can standardize the storage * of the APIToken and make it reusable outside of the command. @@ -159,31 +159,31 @@ component accessors="true" singleton { required string password, required string email, required string firstName, - required string lastName + required string lastName ) { // Get all endpoints that are registered var endpointRegistry = getEndpointRegistry(); - // Confirm endpoint name exists + // Confirm endpoint name exists if( !endpointRegistry.keyExists( arguments.endpointName ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] doesn't exist. Valid names are [#endpointRegistry.keyList()#]", 'endpointException' ); } - + // Get endpoint object var endpoint = getEndpoint( arguments.endpointName ); - + // Confirm is interactive endpoint if( !isInstanceOf( endpoint, 'IEndpointInteractive' ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] does not support registering users.", 'endpointException' ); } - + // Create the user var APIToken = endpoint.createUser( argumentCollection=arguments ); - + // Store the APIToken configService.setSetting( 'endpoints.#endpointName#.APIToken', APIToken ); configService.setSetting( 'endpoints.#endpointName#.tokens.#arguments.username#', APIToken ); - + } - + /** * A facade to login a user with an interactive endpoint. Keeping this logic here so I can standardize the storage * of the APIToken and make it reusable outside of the command. @@ -194,63 +194,63 @@ component accessors="true" singleton { function loginEndpointUser( required string endpointName, required string username, - required string password + required string password ) { // Get all endpoints that are registered var endpointRegistry = getEndpointRegistry(); - // Confirm endpoint name exists + // Confirm endpoint name exists if( !endpointRegistry.keyExists( arguments.endpointName ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] doesn't exist. Valid names are [#endpointRegistry.keyList()#]", 'endpointException' ); } - + // Get endpoint object var endpoint = getEndpoint( arguments.endpointName ); - + // Confirm is interactive endpoint if( !isInstanceOf( endpoint, 'IEndpointInteractive' ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] does not support logging in users.", 'endpointException' ); } - + // Login the user var APIToken = endpoint.login( argumentCollection=arguments ); - + // Store the APIToken configService.setSetting( 'endpoints.#endpointName#.APIToken', APIToken ); configService.setSetting( 'endpoints.#endpointName#.tokens.#arguments.username#', APIToken ); - + } - + /** - * A facade to publish a package with an interactive endpoint. + * A facade to publish a package with an interactive endpoint. * @endpointName The name of the endpoint to publish to * @directory The directory to publish */ function publishEndpointPackage( required string endpointName, - required string directory + required string directory ) { // Get all endpoints that are registered var endpointRegistry = getEndpointRegistry(); - // Confirm endpoint name exists + // Confirm endpoint name exists if( !endpointRegistry.keyExists( arguments.endpointName ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] doesn't exist. Valid names are [#endpointRegistry.keyList()#]", 'endpointException' ); } - + // Get endpoint object var endpoint = getEndpoint( arguments.endpointName ); - + // Confirm is interactive endpoint if( !isInstanceOf( endpoint, 'IEndpointInteractive' ) ) { - throw( "Sorry, the endpoint [#arguments.endpointName#] does not support publishing packages users.", 'endpointException' ); + throw( "Sorry, the endpoint [#arguments.endpointName#] does not support publishing packages users.", 'endpointException' ); } // Set the path to publish arguments.path = arguments.directory; // Publish the package endpoint.publish( argumentCollection=arguments ); } - - + + /** - * A facade to unpublish a package with an interactive endpoint. + * A facade to unpublish a package with an interactive endpoint. * @endpointName The name of the endpoint to publish to * @directory The directory to publish * @version The version to unpublish @@ -258,26 +258,26 @@ component accessors="true" singleton { function unpublishEndpointPackage( required string endpointName, required string directory, - string version='' + string version='' ) { // Get all endpoints that are registered var endpointRegistry = getEndpointRegistry(); - // Confirm endpoint name exists + // Confirm endpoint name exists if( !endpointRegistry.keyExists( arguments.endpointName ) ) { throw( "Sorry, the endpoint [#arguments.endpointName#] doesn't exist. Valid names are [#endpointRegistry.keyList()#]", 'endpointException' ); } - + // Get endpoint object var endpoint = getEndpoint( arguments.endpointName ); - + // Confirm is interactive endpoint if( !isInstanceOf( endpoint, 'IEndpointInteractive' ) ) { - throw( "Sorry, the endpoint [#arguments.endpointName#] does not support unpublishing packages users.", 'endpointException' ); + throw( "Sorry, the endpoint [#arguments.endpointName#] does not support unpublishing packages users.", 'endpointException' ); } // Set the path to publish arguments.path = arguments.directory; // Publish the package endpoint.unpublish( argumentCollection=arguments ); } - + } \ No newline at end of file diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index aa83183d3..8d7e49f57 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -7,24 +7,25 @@ * This service oversees all CommandBox Modules -----------------------------------------------------------------------> - + - + + - - + + @@ -37,7 +38,7 @@ instance.mConfigCache = {}; instance.moduleRegistry = createObject( "java", "java.util.LinkedHashMap" ).init(); instance.cfmappingRegistry = {}; - + setModuleData( {} ); return this; @@ -49,7 +50,7 @@ - + @@ -150,7 +151,7 @@ // Module To Load var modName = arguments.moduleName; var modulesConfiguration = getModuleData(); - // CommandBox doesn't really have settings per se-- + // CommandBox doesn't really have settings per se-- // at least not ones I'm comfortable with modules overriding. //var appSettings = shell.getConfigSettings(); @@ -209,7 +210,7 @@ // lock registration lock name="module.registration.#arguments.modulename#" type="exclusive" throwontimeout="true" timeout="20"{ - + // Setup Vanilla Config information for module var mConfig = { // Module MetaData and Directives @@ -244,19 +245,22 @@ modelsPhysicalPath = modLocation, commandsInvocationPath = modulesInvocationPath & "." & modName, commandsPhysicalPath = modLocation, + endpointsInvocationPath = modulesInvocationPath & "." & modName, + endpointsPhysicalPath = modLocation, parentSettings = {}, settings = {}, interceptors = [], interceptorSettings = { customInterceptionPoints = "" }, conventions = { modelsLocation = "models", - commandsLocation = "commands" + commandsLocation = "commands", + endpointsLocation = "endpoints" }, childModules = [], parent = arguments.parent }; - + try { // Load Module configuration from cfc and store it in module Config Cache var oConfig = loadModuleConfiguration( mConfig, arguments.moduleName ); @@ -285,10 +289,13 @@ // Update the paths according to conventions mConfig.modelsInvocationPath &= ".#replace( mConfig.conventions.modelsLocation, "/", ".", "all" )#"; mConfig.modelsPhysicalPath &= "/#mConfig.conventions.modelsLocation#"; - + mConfig.commandsInvocationPath &= ".#replace( mConfig.conventions.commandsLocation, "/", ".", "all" )#"; mConfig.commandsPhysicalPath &= "/#mConfig.conventions.commandsLocation#"; - + + mConfig.endpointsInvocationPath &= ".#replace( mConfig.conventions.endpointsLocation, "/", ".", "all" )#"; + mConfig.endpointsPhysicalPath &= "/#mConfig.conventions.endpointsLocation#"; + // Register CFML Mapping if it exists, for loading purposes if( len( trim( mConfig.cfMapping ) ) ){ shell.getUtil().addMapping( name=mConfig.cfMapping, path=mConfig.path ); @@ -431,13 +438,19 @@ } wirebox.getBinder().processMappings(); } - + // Register commands if they exist if( directoryExists( mconfig.commandsPhysicalPath ) ){ - var commandPath = '/' & replace( mconfig.commandsInvocationPath, '.', '/', 'all' ); + var commandPath = '/' & replace( mconfig.commandsInvocationPath, '.', '/', 'all' ); CommandService.initCommands( commandPath, commandPath ); } + // Register endpoints if they exist + if( directoryExists( mconfig.endpointsPhysicalPath ) ){ + var mappedPath = '/' & replace( mconfig.endpointsInvocationPath, '.', '/', 'all' ); + EndpointService.buildEndpointRegistry( mappedPath ); + } + // Register Interceptors with Announcement service for( y=1; y lte arrayLen( mConfig.interceptors ); y++ ){ interceptorService.registerInterceptor( interceptor=mConfig.interceptors[ y ].class, @@ -569,11 +582,11 @@ /*if( shell.settingExists( "sesBaseURL" ) ){ interceptorService.getInterceptor( "SES", true ).removeModuleRoutes( arguments.moduleName ); }*/ - + // Remove the possible config names with the ConfigService for auto-completion var possibleConfigSettings = []; for( var settingName in ConfigService.getPossibleConfigSettings() ) { - if( !reFindNoCase( '^modules.#arguments.moduleName#.', settingName ) ) { + if( !reFindNoCase( '^modules.#arguments.moduleName#.', settingName ) ) { possibleConfigSettings.append( settingName ); } } @@ -701,14 +714,14 @@ mConfig.settings = oConfig.getPropertyMixin( "settings", "variables", {} ); // Override with CommandBox config settings overrideConfigSettings( mConfig.settings, moduleName ); - + // Register the possible config names with the ConfigService for auto-completion var possibleConfigSettings = ConfigService.getPossibleConfigSettings(); for( var settingName in mConfig.settings ) { possibleConfigSettings.append( 'modules.#moduleName#.#settingName#' ); } ConfigService.setPossibleConfigSettings( possibleConfigSettings ); - + //Get Interceptors mConfig.interceptors = oConfig.getPropertyMixin( "interceptors", "variables", [] ); for(var x=1; x lte arrayLen( mConfig.interceptors ); x=x+1){ From 5e5d1af78a9b07990f3b88ae4f8a26a0c3c895f5 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 24 May 2017 00:02:54 -0500 Subject: [PATCH 078/123] Clean up commands that we're never going to do --- .../commands/contentbox/create/app-wizard.cfc | 40 ---- .../commands/contentbox/create/app.cfc | 175 ----------------- .../commands/contentbox/create/bdd.cfc | 23 --- .../commands/contentbox/create/handler.cfc | 134 ------------- .../contentbox/create/handlers/Users.cfc | 118 ------------ .../commands/contentbox/create/help.cfc | 14 -- .../contentbox/create/integration-test.cfc | 119 ------------ .../contentbox/create/interceptor-test.cfc | 68 ------- .../contentbox/create/interceptor.cfc | 110 ----------- .../commands/contentbox/create/layout.cfc | 52 ----- .../commands/contentbox/create/model-test.cfc | 84 -------- .../commands/contentbox/create/model.cfc | 181 ------------------ .../commands/contentbox/create/orm-crud.cfc | 136 ------------- .../commands/contentbox/create/orm-entity.cfc | 143 -------------- .../contentbox/create/orm-event-handler.cfc | 49 ----- .../contentbox/create/orm-service.cfc | 82 -------- .../contentbox/create/orm-virtual-service.cfc | 82 -------- .../{module/create.cfc => create/theme.cfc} | 0 .../commands/contentbox/create/unit.cfc | 23 --- .../commands/contentbox/create/view.cfc | 65 ------- .../contentbox/create/views/Users/edit.cfm | 1 - .../contentbox/create/views/Users/editor.cfm | 39 ---- .../contentbox/create/views/Users/index.cfm | 49 ----- .../contentbox/create/views/Users/new.cfm | 3 - .../{module/install.cfc => create/widget.cfc} | 0 .../commands/contentbox/module/help.cfc | 12 -- .../commands/contentbox/module/list.cfc | 13 -- .../commands/contentbox/module/remove.cfc | 13 -- .../commands/contentbox/theme/create.cfc | 13 -- .../commands/contentbox/theme/help.cfc | 12 -- .../commands/contentbox/theme/install.cfc | 13 -- .../commands/contentbox/theme/list.cfc | 13 -- .../commands/contentbox/theme/remove.cfc | 13 -- .../commands/contentbox/widget/create.cfc | 13 -- .../commands/contentbox/widget/help.cfc | 12 -- .../commands/contentbox/widget/install.cfc | 13 -- .../commands/contentbox/widget/list.cfc | 13 -- .../commands/contentbox/widget/remove.cfc | 13 -- .../commands/forgebox/disable.cfc | 13 -- .../commands/forgebox/enable.cfc | 13 -- .../commands/testbox/open/bundle.cfc | 13 -- .../commands/testbox/open/directory.cfc | 13 -- .../commands/testbox/open/help.cfc | 12 -- .../commands/testbox/open/runner.cfc | 13 -- 44 files changed, 2033 deletions(-) delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app-wizard.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/bdd.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handler.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handlers/Users.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/help.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/integration-test.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor-test.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/layout.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model-test.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-crud.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-entity.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-event-handler.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-service.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-virtual-service.cfc rename src/cfml/system/modules_app/contentbox-commands/commands/contentbox/{module/create.cfc => create/theme.cfc} (100%) delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/unit.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/view.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/edit.cfm delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/editor.cfm delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/index.cfm delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/new.cfm rename src/cfml/system/modules_app/contentbox-commands/commands/contentbox/{module/install.cfc => create/widget.cfc} (100%) delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/help.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/list.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/remove.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/create.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/help.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/install.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/list.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/remove.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/create.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/help.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/install.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/list.cfc delete mode 100644 src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/remove.cfc delete mode 100644 src/cfml/system/modules_app/forgebox-commands/commands/forgebox/disable.cfc delete mode 100644 src/cfml/system/modules_app/forgebox-commands/commands/forgebox/enable.cfc delete mode 100644 src/cfml/system/modules_app/testbox-commands/commands/testbox/open/bundle.cfc delete mode 100644 src/cfml/system/modules_app/testbox-commands/commands/testbox/open/directory.cfc delete mode 100644 src/cfml/system/modules_app/testbox-commands/commands/testbox/open/help.cfc delete mode 100644 src/cfml/system/modules_app/testbox-commands/commands/testbox/open/runner.cfc diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app-wizard.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app-wizard.cfc deleted file mode 100644 index 366f18a1c..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app-wizard.cfc +++ /dev/null @@ -1,40 +0,0 @@ -/** -* Create a blank ColdBox app from one of our app skeletons by following our lovely wizard. -**/ -component extends="app" { - - /** - * @name The name of the app you want to create - * @skeleton The application skeleton you want to use - * @skeleton.optionsUDF skeletonComplete - * @init Would you like to init this as a CommandBox Package - * @installColdBox Install the latest stable version of ColdBox from ForgeBox - * @installColdBoxBE Install the bleeding edge version of ColdBox from ForgeBox - * @installTestBox Install the latest stable version of TestBox from ForgeBox - **/ - function run( - required name, - required skeleton, - required boolean init, - required boolean installColdBox, - required boolean installColdBoxBE, - required boolean installTestBox - ) { - var skeletons = skeletonComplete(); - // turn off wizard - arguments.wizard = false; - arguments.initWizard = true; - arguments.directory=getCWD(); - - // Validate skeletons - while( !arrayFindNoCase( skeletons, arguments.skeleton ) ){ - print.boldRedLine( "The skeleton you chose: '#arguments.skeleton#' is not valid." ) - .boldRedLine( " Valid Choices are (#arrayToList( skeletons, ", " )#)" ) - .toConsole(); - arguments.skeleton = ask( "Choose Skeleton: " ); - } - - super.run( argumentCollection=arguments ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app.cfc deleted file mode 100644 index a5430a6b6..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/app.cfc +++ /dev/null @@ -1,175 +0,0 @@ -/** -* Create a blank ColdBox app from one of our app skeletons. By default it will create -* in your current directory. -* . -* {code:bash} -* coldbox create app myApp -* {code} -* . -* Here are the basic skeltons that are available for you. -* - Advanced -* - AdvancedScript (default) -* - rest -* - Simple -* - SuperSimple -* . -* {code:bash} -* coldbox create app skeleton=rest -* {code} -* . -* The skeleton parameter can also be any valid Endpoint ID, which includes a Git repo or HTTP URL pointing to a package. -* . -* {code:bash} -* coldbox create app skeleton=http://site.com/myCustomAppTemplate.zip -* {code} -* . -* Use the "installColdBox" parameter to install the latest stable version of ColdBox from ForgeBox -* {code:bash} -* coldbox create app myApp --installColdBox -* {code} -* . -* Use the "installTestBox" parameter to install the latest stable version of TestBox from ForgeBox -* {code:bash} -* coldbox create app myApp --installColdBox --installTestBox -* {code} -* -**/ -component { - - // DI - property name="packageService" inject="PackageService"; - - /** - * Constructor - */ - function init(){ - - // Map these shortcut names to the actual ForgeBox slugs - variables.templateMap = { - Advanced = 'cbtemplate-advanced', - AdvancedScript = 'cbtemplate-advanced-script', - rest = 'cbtemplate-rest', - Simple = 'cbtemplate-simple', - SuperSimple = 'cbtemplate-supersimple' - }; - - return this; - } - - /** - * @name The name of the app you want to create - * @skeleton The name of the app skeleton to generate - * @skeleton.optionsUDF skeletonComplete - * @directory The directory to create the app in and creates the directory if it does not exist. Defaults to your current working directory. - * @init "init" the directory as a package if it isn't already - * @installColdBox Install the latest stable version of ColdBox from ForgeBox - * @installColdBoxBE Install the bleeding edge version of ColdBox from ForgeBox - * @installTestBox Install the latest stable version of TestBox from ForgeBox - * @wizard Run the ColdBox Creation wizard - * @initWizard Run the init creation package wizard - **/ - function run( - name="My ColdBox App", - skeleton='AdvancedScript', - directory=getCWD(), - boolean init=true, - boolean installColdBox=false, - boolean installColdBoxBE=false, - boolean installTestBox=false, - boolean wizard=false, - boolean initWizard=false - ) { - - // Check for wizard argument - if( arguments.wizard ){ - runCommand( 'coldbox create app-wizard' ); - return; - } - - // This will make the directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - - // Validate directory, if it doesn't exist, create it. - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // If the skeleton is one of our "shortcut" names - if( variables.templateMap.keyExists( arguments.skeleton ) ) { - // Replace it with the actual ForgeBox slug name. - arguments.skeleton = variables.templateMap[ arguments.skeleton ]; - } - - // Install the skeleton - packageService.installPackage( - ID = arguments.skeleton, - directory = arguments.directory, - save = false, - saveDev = false, - production = true, - currentWorkingDirectory = arguments.directory - ); - - // Check for the @appname@ in .project files - if( fileExists( "#arguments.directory#/.project" ) ){ - var sProject = fileRead( "#arguments.directory#/.project" ); - sProject = replaceNoCase( sProject, "@appName@", arguments.name, "all" ); - file action='write' file='#arguments.directory#/.project' mode ='755' output='#sProject#'; - } - - // Init, if not a package as a Box Package - if( arguments.init && !packageService.isPackage( arguments.directory ) ) { - var originalPath = getCWD(); - // init must be run from CWD - shell.cd( arguments.directory ); - command( 'init' ) - .params( - name=arguments.name, - slug=replace( arguments.name, ' ', '', 'all' ), - wizard=arguments.initWizard ) - .run(); - shell.cd( originalPath ); - } - - // Install the ColdBox platform - if( arguments.installColdBox || arguments.installColdBoxBE ) { - - // Flush out stuff from above - print.toConsole(); - - packageService.installPackage( - ID = 'coldbox#iif( arguments.installColdBoxBE, de( '-be' ), de( '' ) )#', - directory = arguments.directory, - save = true, - saveDev = false, - production = true, - currentWorkingDirectory = arguments.directory - ); - } - - // Install TestBox - if( arguments.installTestBox ) { - - // Flush out stuff from above - print.toConsole(); - - packageService.installPackage( - ID = 'testbox', - directory = arguments.directory, - save = false, - saveDev = true, - production = true, - currentWorkingDirectory = arguments.directory - ); - } - - } - - /** - * Returns an array of coldbox skeletons available - */ - function skeletonComplete( ) { - return variables.templateMap.keyList().listToArray(); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/bdd.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/bdd.cfc deleted file mode 100644 index 2c3bc5097..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/bdd.cfc +++ /dev/null @@ -1,23 +0,0 @@ -/** -* Create a new BDD spec in an existing ColdBox-enabled application. Run this command in the root -* of your app for it to find the correct folder. By default, your new BDD spec will be created in /tests/specs but you can -* override that with the directory param. -* . -* {code:bash} -* coldbox create bdd mySpec -* {code} -* -**/ -component { - - /** - * @name.hint Name of the BDD spec to create without the .cfc. For packages, specify name as 'myPackage/myBDDSpec' - * @open.hint Open the file once it is created - * @directory.hint The base directory to create your BDD spec in, defaults to 'tests/specs' - **/ - function run( required name, boolean open=false, directory="tests/specs" ){ - // proxy to testbox - runCommand( "testbox create bdd name=#arguments.name# directory=#arguments.directory# open=#arguments.open#" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handler.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handler.cfc deleted file mode 100644 index 7cc71e197..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handler.cfc +++ /dev/null @@ -1,134 +0,0 @@ -/** -* Create a new handler (controller) in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. You can optionally create the views as well as the integration tests for your -* new handler at the same time. By default, your new handler will be created in /handlers but you can override that with the directory param. -* . -* {code:bash} -* coldbox create handler myHandler index,foo,bar --open -* {code} -* -**/ -component aliases='coldbox create controller' { - - /** - * @name.hint Name of the handler to create without the .cfc. For packages, specify name as 'myPackage/myHandler' - * @actions.hint A comma-delimited list of actions to generate - * @views.hint Generate a view for each action - * @viewsDirectory.hint The directory where your views are stored. Only used if views is set to true. - * @appMapping.hint The root location of the application in the web root: ex: /MyApp or / if in the root - * @integrationTests.hint Generate the integration test component - * @testsDirectory.hint Your integration tests directory. Only used if integrationTests is true - * @directory.hint The base directory to create your handler in and creates the directory if it does not exist. Defaults to 'handlers'. - * @script.hint Generate content in script markup or tag markup - * @description.hint The handler hint description - * @open.hint Open the handler once generated - **/ - function run( - required name, - actions='', - boolean views=true, - viewsDirectory='views', - boolean integrationTests=true, - appMapping='/', - testsDirectory='tests/specs/integration', - directory='handlers', - boolean script=true, - description="I am a new handler", - boolean open=false - ){ - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.viewsDirectory = fileSystemUtil.resolvePath( arguments.viewsDirectory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // Allow dot-delimited paths - arguments.name = replace( arguments.name, '.', '/', 'all' ); - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Script? - var scriptPrefix = ''; - // TODO: Pull this from box.json - if( arguments.script ) { - scriptPrefix = 'Script'; - } - - // Read in Templates - var handlerContent = fileRead( '/coldbox-commands/templates/HandlerContent#scriptPrefix#.txt' ); - var actionContent = fileRead( '/coldbox-commands/templates/ActionContent#scriptPrefix#.txt' ); - var handlerTestContent = fileRead( '/coldbox-commands/templates/testing/HandlerBDDContent#scriptPrefix#.txt' ); - var handlerTestCaseContent = fileRead( '/coldbox-commands/templates/testing/HandlerBDDCaseContent#scriptPrefix#.txt' ); - - // Start text replacements - handlerContent = replaceNoCase( handlerContent, '|handlerName|', arguments.name, 'all' ); - handlerTestContent = replaceNoCase( handlerTestContent, '|appMapping|', arguments.appMapping, 'all' ); - handlerTestContent = replaceNoCase( handlerTestContent, '|handlerName|', arguments.name, 'all' ); - handlerContent = replaceNoCase( handlerContent, '|Description|', arguments.description, 'all'); - - // Handle Actions if passed - if( len( arguments.actions ) ) { - var allActions = ''; - var allTestsCases = ''; - var thisTestCase = ''; - - // Loop Over actions generating their functions - for( var thisAction in listToArray( arguments.actions ) ) { - thisAction = trim( thisAction ); - allActions = allActions & replaceNoCase( actionContent, '|action|', thisAction, 'all' ) & cr & cr; - - // Are we creating views? - if( arguments.views ) { - var viewPath = arguments.viewsDirectory & '/' & arguments.name & '/' & thisAction & '.cfm'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( viewPath ), true, true ); - // Create View Stub - fileWrite( viewPath, '#cr#

#arguments.name#.#thisAction#

#cr#
' ); - print.greenLine( 'Created ' & arguments.viewsDirectory & '/' & arguments.name & '/' & thisAction & '.cfm' ); - } - - // Are we creating tests cases on actions - if( arguments.integrationTests ) { - thisTestCase = replaceNoCase( handlerTestCaseContent, '|action|', thisAction, 'all' ); - thisTestCase = replaceNoCase( thisTestCase, '|event|', listChangeDelims( arguments.name, '.', '/\' ) & '.' & thisAction, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - } - - } - - // final replacements - allActions = replaceNoCase( allActions, '|name|', arguments.name, 'all'); - handlerContent = replaceNoCase( handlerContent, '|EventActions|', allActions, 'all'); - handlerTestContent = replaceNoCase( handlerTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - handlerContent = replaceNoCase( handlerContent, '|EventActions|', '', 'all' ); - handlerTestContent = replaceNoCase( handlerTestContent, '|TestCases|', '', 'all' ); - } - - var handlerPath = '#arguments.directory#/#arguments.name#.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( handlerPath ), true, true ); - // Write out the files - file action='write' file='#handlerPath#' mode ='777' output='#handlerContent#'; - print.greenLine( 'Created #handlerPath#' ); - - if( arguments.integrationTests ) { - var testPath = '#arguments.testsDirectory#/#arguments.name#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#handlerTestContent#'; - print.greenLine( 'Created #testPath#' ); - // open file - if( arguments.open ){ openPath( testPath ); } - } - - // open file - if( arguments.open ){ openPath( handlerPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handlers/Users.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handlers/Users.cfc deleted file mode 100644 index 86d91af5e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/handlers/Users.cfc +++ /dev/null @@ -1,118 +0,0 @@ -/** -* Manage Users -* It will be your responsibility to fine tune this template, add validations, try/catch blocks, logging, etc. -*/ -component{ - - // DI Virtual Entity Service - property name="ormService" inject="entityService:User"; - - // HTTP Method Security - this.allowedMethods = { - index = "GET", new = "GET", edit = "GET", delete = "POST,DELETE", save = "POST,PUT" - }; - - /** - * preHandler() - */ - function preHandler( event, rc, prc ){ - event.paramValue( "format", "html" ); - } - - /** - * Listing - */ - function index( event, rc, prc ){ - // Get all Users - prc.Users = ormService.getAll(); - // Multi-format rendering - event.renderData( data=prc.Users, formats="xml,json,html,pdf" ); - } - - /** - * New Form - */ - function new( event, rc, prc ){ - // get new User - prc.User = ormService.new(); - - event.setView( "Users/new" ); - } - - /** - * Edit Form - */ - function edit( event, rc, prc ){ - // get persisted User - prc.User = ormService.get( rc.user_id ); - - event.setView( "Users/edit" ); - } - - /** - * View User mostly used for RESTful services only. - */ - function show( event, rc, prc ){ - // Default rendering. - event.paramValue( "format", "json" ); - // Get requested entity by id - prc.User = ormService.get( rc.user_id ); - // Multi-format rendering - event.renderData( data=prc.User, formats="xml,json" ); - } - - /** - * Save and Update - */ - function save( event, rc, prc ){ - // get User to persist or update and populate it with incoming form - prc.User = populateModel( model=ormService.get( rc.user_id ), exclude="user_id", composeRelationships=true ); - - // Do your validations here - - // Save it - ormService.save( prc.User ); - - // RESTful Handler - switch(rc.format){ - // xml,json,jsont are by default. Add your own or remove - case "xml" : case "json" : case "jsont" :{ - event.renderData( data=prc.User, type=rc.format, location="/Users/show/#prc.User.getuser_id()#" ); - break; - } - // HTML - default:{ - // Show a nice notice - flash.put( "notice", { message="User Created", type="success" } ); - // Redirect to listing - setNextEvent( 'Users' ); - } - } - } - - /** - * Delete - */ - function delete( event, rc, prc ){ - // Delete record by ID - var removed = ormService.delete( ormService.get( rc.user_id ) ); - - // RESTful Handler - switch( rc.format ){ - // xml,json,jsont are by default. Add your own or remove - case "xml" : case "json" : case "jsont" :{ - var restData = { "deleted" = removed }; - event.renderData( data=restData, type=rc.format ); - break; - } - // HTML - default:{ - // Show a nice notice - flash.put( "notice", { message="User Poofed!", type="success" } ); - // Redirect to listing - setNextEvent( 'Users' ); - } - } - } - -} diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/help.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/help.cfc deleted file mode 100644 index dce9140c0..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/help.cfc +++ /dev/null @@ -1,14 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line() - .yellow( 'The ' ).boldYellow( 'coldbox create' ).yellowLine( ' namespace allows you to quickly scaffold applications ' ) - .yellowLine( 'and individual app pieces. Use these commands to stub out placeholder files' ) - .yellow( 'as you plan your application. Most commands create a single file, but "' ).boldYellow( 'coldbox create app' ).yellowLine( '"' ) - .yellowLine( 'will generate an entire, working application into an empty folder for you. Type help before' ) - .yellowLine( 'any command name to get additional information on how to call that specific command.' ) - .line() - .line(); - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/integration-test.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/integration-test.cfc deleted file mode 100644 index b496451d6..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/integration-test.cfc +++ /dev/null @@ -1,119 +0,0 @@ -/** -* Create a new integration spec in an existing ColdBox-enabled application. Run this command in the root -* of your app for it to find the correct folder. By default, your new test spec will be created in /tests/specs/integration but you can -* override that with the directory param as well. You can also choose your testing style: BDD or xUnit. -* . -* {code:bash} -* #Generate a handler integration spec using BDD -* coldbox create integration-test contacts -* {code} -* . -* {code:bash} -* #Generate a handler integration spec using BDD and open the file -* coldbox create integration-test contacts --open -* {code} -* . -* {code:bash} -* #Generate a handler integration spec using BDD with several actions -* coldbox create integration-test contacts index,save,delete -* {code} -* . -* {code:bash} -* #Generate a handler integration spec using xUnit -* coldbox create integration-test contacts --xunit -* {code} -**/ -component { - - /** - * @handler.hint Name of the handler to test - * @actions.hint A comma-delimited list of actions to generate - * @appMapping.hint The root location of the application in the web root: ex: /MyApp or / if in the root - * @bdd.hint Defaults to BDD style - * @xunit.hint You can alternatively use xUnit style - * @open.hint Open the file once it is created - * @script.hint Generate content in script markup or tag markup - * @directory.hint The base directory to create your test spec in and creates the directory if it does not exist. Defaults to 'tests/specs/integration' - **/ - function run( - required handler, - actions="", - appMapping="/", - boolean bdd=true, - boolean xunit=false, - boolean open=false, - boolean script=true, - directory="tests/specs/integration" - ){ - - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - // Exit the command if something above failed - if( hasError() ) { - return; - } - - // Allow dot-delimited paths - arguments.handler = replace( arguments.handler, '.', '/', 'all' ); - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Script? - var scriptPrefix = ''; - // TODO: Pull this from box.json - if( arguments.script ) { - scriptPrefix = 'Script'; - } - - // Style? - var stylePrefix = 'BDD'; - if( arguments.xunit OR !arguments.bdd ) { - stylePrefix = 'Test'; - } - - // Read in Templates - var handlerTestContent = fileRead( '/coldbox-commands/templates/testing/Handler#stylePrefix#Content#scriptPrefix#.txt' ); - var handlerTestCaseContent = fileRead( '/coldbox-commands/templates/testing/Handler#stylePrefix#CaseContent#scriptPrefix#.txt' ); - - // Start text replacements - handlerTestContent = replaceNoCase( handlerTestContent, '|appMapping|', arguments.appMapping, 'all' ); - handlerTestContent = replaceNoCase( handlerTestContent, '|handlerName|', arguments.handler, 'all' ); - - // Handle Actions if passed - if( len( arguments.actions ) ) { - var allActions = ''; - var allTestsCases = ''; - var thisTestCase = ''; - - // Loop Over actions generating their functions - for( var thisAction in listToArray( arguments.actions ) ) { - thisAction = trim( thisAction ); - // genereate test case - thisTestCase = replaceNoCase( handlerTestCaseContent, '|action|', thisAction, 'all' ); - thisTestCase = replaceNoCase( thisTestCase, '|event|', listChangeDelims( arguments.handler, '.', '/\' ) & '.' & thisAction, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - } - - // final replacements - handlerTestContent = replaceNoCase( handlerTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - handlerTestContent = replaceNoCase( handlerTestContent, '|TestCases|', '', 'all' ); - } - - var integrationTestPath = '#arguments.directory#/#arguments.handler#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( integrationTestPath ), true, true ); - // Write out the files - file action='write' file='#integrationTestPath#' mode ='777' output='#handlerTestContent#'; - print.greenLine( 'Created #integrationTestPath#' ); - - // open file - if( arguments.open ){ openPath( integrationTestPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor-test.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor-test.cfc deleted file mode 100644 index 57a9b496a..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor-test.cfc +++ /dev/null @@ -1,68 +0,0 @@ -/** -* Create a new interceptor BDD test in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create interceptor-test interceptors.MyInterceptor preProcess,postEvent -* {code} -* - **/ -component { - - /** - * @path The instantiation path of the interceptor to create the test for - * @points A comma-delimited list of interception points to generate tests for - * @testsDirectory Your unit tests directory. Only used if tests is true - * @open.hint Open the test once generated - **/ - function run( - required path, - points='', - testsDirectory='tests/specs/interceptors', - boolean open=false - ){ - // This will make each directory canonical and absolute - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.testsDirectory ) ) { - directoryCreate( arguments.testsDirectory ); - } - - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Read in Template - var interceptorTestContent = fileRead( '/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt' ); - var interceptorTestCase = fileRead( '/coldbox-commands/templates/testing/InterceptorBDDCaseContentScript.txt' ); - - // Start Replacings - interceptorTestContent = replaceNoCase( interceptorTestContent, "|name|", arguments.path, "all" ); - - // Interception Points - if( len( arguments.points ) ) { - var allTestsCases = ''; - var thisTestCase = ''; - - for( var thisPoint in listToArray( arguments.points ) ) { - thisTestCase = replaceNoCase( interceptorTestCase, '|point|', thisPoint, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - } - interceptorTestContent = replaceNoCase( interceptorTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - interceptorTestContent = replaceNoCase( interceptorTestContent, '|TestCases|', '', 'all'); - } - - // Write it out. - var testPath = '#arguments.testsDirectory#/#listLast( arguments.path, "." )#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#interceptorTestContent#'; - print.greenLine( 'Created #testPath#' ); - - // open file - if( arguments.open ){ openPath( testPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor.cfc deleted file mode 100644 index c45a6cfe0..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/interceptor.cfc +++ /dev/null @@ -1,110 +0,0 @@ -/** -* Create a new interceptor in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. You can optionally create unit tests for your new interceptor at the same time. -* By default, your new interceptor will be created in /interceptors but you can override that with the directory param. -* Note, even though this command creates the interceptor CFC, you will still need to register it in the interceptors array -* in your ColdBox.cfc config file. -* . -* {code:bash} -* coldbox create interceptor myInterceptor preProcess,postEvent -* {code} -* - **/ -component { - - /** - * @name Name of the interceptor to create without the .cfc - * @points A comma-delimited list of interception points to generate - * @description A description for the interceptor hint - * @tests Generate the unit test component - * @testsDirectory Your unit tests directory. Only used if tests is true - * @directory The base directory to create your interceptor in and creates the directory if it does not exist. - * @script Generate content in script markup or tag markup - * @open.hint Open the interceptor once generated - **/ - function run( - required name, - points='', - description="I am a new interceptor", - boolean tests=true, - testsDirectory='tests/specs/interceptors', - directory='interceptors', - boolean script=true, - boolean open=false - ){ - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Script? - var scriptPrefix = ''; - // TODO: Pull this from box.json - if( arguments.script ) { - scriptPrefix = 'Script'; - } - - // Read in Template - var interceptorContent = fileRead( '/coldbox-commands/templates/InterceptorContent#scriptPrefix#.txt' ); - var interceptorMethod = fileRead( '/coldbox-commands/templates/InterceptorMethod#scriptPrefix#.txt' ); - var interceptorTestContent = fileRead( '/coldbox-commands/templates/testing/InterceptorBDDContentScript.txt' ); - var interceptorTestCase = fileRead( '/coldbox-commands/templates/testing/InterceptorBDDCaseContentScript.txt' ); - - // Start Replacings - interceptorContent = replaceNoCase( interceptorContent, '|Name|', arguments.name, 'all' ); - interceptorTestContent = replaceNoCase( interceptorTestContent, "|name|", arguments.name, "all" ); - - // Placeholder in case we add this in - interceptorContent = replaceNoCase( interceptorContent, '|Description|', arguments.description, 'all' ); - - // Interception Points - if( len( arguments.points ) ) { - var methodContent = ''; - var allTestsCases = ''; - var thisTestCase = ''; - - for( var thisPoint in listToArray( arguments.points ) ) { - methodContent = methodContent & replaceNoCase( interceptorMethod, '|interceptionPoint|', thisPoint, 'all' ) & CR & CR; - - // Are we creating tests cases - if( arguments.tests ) { - thisTestCase = replaceNoCase( interceptorTestCase, '|point|', thisPoint, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - } - - } - interceptorContent = replaceNoCase( interceptorContent, '|interceptionPoints|', methodContent, 'all' ); - interceptorTestContent = replaceNoCase( interceptorTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - interceptorContent = replaceNoCase( interceptorContent, '|interceptionPoints|', '', 'all' ); - interceptorTestContent = replaceNoCase( interceptorTestContent, '|TestCases|', '', 'all'); - } - - // Write it out. - var interceptorPath = '#arguments.directory#/#arguments.name#.cfc'; - file action='write' file='#interceptorPath#' mode ='777' output='#interceptorContent#'; - print.greenLine( '#interceptorPath#' ); - - if( tests ) { - var testPath = '#TestsDirectory#/#arguments.name#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#interceptorTestContent#'; - print.greenLine( 'Created #testPath#' ); - // open file - if( arguments.open ){ openPath( testPath ); } - } - - // open file - if( arguments.open ){ openPath( interceptorPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/layout.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/layout.cfc deleted file mode 100644 index b7fdcaefc..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/layout.cfc +++ /dev/null @@ -1,52 +0,0 @@ -/** -* Create a new layout in an existing ColdBox application. Run this command in the root -* of your app for it to find the correct folder. By default, your new layout will be created in /layouts but you can -* override that with the directory param. -* . -* {code:bash} -* coldbox create layout myLayout -* {code} -* -**/ -component { - - /** - * @arguments.name.hint Name of the layout to create without the .cfm. - * @helper.hint Generate a helper file for this layout - * @directory.hint The base directory to create your layout in and creates the directory if it does not exist. - **/ - function run( - required name, - boolean helper=false, - directory='layouts' - ){ - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // This help readability so the success messages aren't up against the previous command line - print.line(); - - var layoutContent = '

#arguments.name# Layout

#CR###renderView()##'; - var layoutHelperContent = ''; - - // Write out layout - var layoutPath = '#arguments.directory#/#arguments.name#.cfm'; - file action='write' file='#layoutPath#' mode ='777' output='#layoutContent#'; - print.greenLine( 'Created #layoutPath#' ); - - if( arguments.helper ) { - // Write out layout helper - var layoutHelperPath = '#arguments.directory#/#arguments.name#Helper.cfm'; - file action='write' file='#layoutHelperPath#' mode ='777' output='#layoutHelperContent#'; - print.greenLine( 'Created #layoutHelperPath#' ); - - } - - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model-test.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model-test.cfc deleted file mode 100644 index 817197dfe..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model-test.cfc +++ /dev/null @@ -1,84 +0,0 @@ -/** -* Create a new model bdd test in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create model-test myModel --open -* {code} -* - **/ -component { - - /** - * Constructor - */ - function init(){ - // valid persistences - variables.validPersistences = 'Transient,Singleton'; - - return this; - } - - /** - * @path.hint The instantiation path of the model to create the test for without any .cfc - * @methods.hint A comma-delimited list of method to generate tests for - * @testsDirectory.hint Your unit tests directory. Only used if tests is true - * @open.hint Open the file once generated - **/ - function run( - required path, - methods="", - testsDirectory='tests/specs/unit', - boolean open=false - ) { - // This will make each directory canonical and absolute - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.testsDirectory ) ) { - directoryCreate( arguments.testsDirectory ); - } - - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Read in Template - var modelTestContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDContentScript.txt' ); - var modelTestMethodContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDMethodContentScript.txt' ); - - // Basic replacements - modelTestContent = replaceNoCase( modelTestContent, '|modelName|', arguments.path, 'all' ); - - // Handle Methods - if( len( arguments.methods ) ){ - var allTestsCases = ""; - - // Loop Over methods to generate them - for( var thisMethod in listToArray( arguments.methods ) ) { - thisMethod = trim( thisMethod ); - - var thisTestCase = replaceNoCase( modelTestMethodContent, '|method|', thisMethod, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - - print.yellowLine( "Generated method: #thisMethod#"); - } - - // final replacement - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', '', 'all' ); - } - - var testPath = '#arguments.TestsDirectory#/#listLast( arguments.path, "." )#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; - // open file - if( arguments.open ){ openPath( testPath ); } - print.greenLine( 'Created #testPath#' ); - // Open file? - if( arguments.open ){ openPath( testPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model.cfc deleted file mode 100644 index fdf4aa389..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/model.cfc +++ /dev/null @@ -1,181 +0,0 @@ -/** -* Create a new model CFC in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. You can optionally create unit tests for your new model at the same time. -* By default, your new model will be created in /model but you can override that with the directory param. -* Once you create a model you can add a mapping for it in your WireBox binder, or use ColdBox's default scan location and -* just reference it with getModel( 'modelName' ). -* . -* {code:bash} -* coldbox create model myModel --open -* {code} -* . -* {code:bash} -* coldbox create model name=User properties=fname,lname,email --accessors --open -* {code} -* - **/ -component { - - /** - * Constructor - */ - function init(){ - // valid persistences - variables.validPersistences = 'Transient,Singleton'; - - return this; - } - - /** - * @name Name of the model to create without the .cfc. For packages, specify name as 'myPackage/myModel' - * @methods A comma-delimited list of method stubs to generate for you - * @persistence Specify singleton to have only one instance of this model created - * @persistence.options Transient,Singleton - * @tests Generate the unit test BDD component - * @testsDirectory Your unit tests directory. Only used if tests is true - * @directory The base directory to create your model in and creates the directory if it does not exist. - * @script Generate content in script markup or tag markup - * @description The model hint description - * @open Open the file once generated - * @accessors Setup accessors to be true or not in the component - * @properties Enter a list of properties to generate. You can add the type via semicolon separator. Ex: firstName,age:numeric,wheels:array - **/ - function run( - required name, - methods="", - persistence='transient', - boolean tests=true, - testsDirectory='tests/specs/unit', - directory='models', - boolean script=true, - description="I am a new Model Object", - boolean open=false, - boolean accessors=true, - properties="" - ) { - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - // Validate persistence - if( !listFindNoCase( variables.validPersistences, arguments.persistence ) ) { - error( "The persistence value [#arguments.persistence#] is invalid. Valid values are [#listChangeDelims( variables.validPersistences, ', ', ',' )#]" ); - } - // Exit the command if something above failed - if( hasError() ) { - return; - } - - // Allow dot-delimited paths - arguments.name = replace( arguments.name, '.', '/', 'all' ); - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Script? - var scriptPrefix = ''; - // TODO: Pull this from box.json - if( arguments.script ) { - scriptPrefix = 'Script'; - } - - // Read in Template - var modelContent = fileRead( '/coldbox-commands/templates/ModelContent#scriptPrefix#.txt' ); - var modelMethodContent = fileRead( '/coldbox-commands/templates/ModelMethodContent#scriptPrefix#.txt' ); - var modelTestContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDContent#scriptPrefix#.txt' ); - var modelTestMethodContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDMethodContent#scriptPrefix#.txt' ); - - - // Basic replacements - modelContent = replaceNoCase( modelContent, '|modelName|', listLast( arguments.name, '/\' ), 'all' ); - modelContent = replaceNoCase( modelContent, '|modelDescription|', arguments.description, 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|modelName|', listChangeDelims( arguments.name, '.', '/\' ), 'all' ); - - // Persistence - switch ( Persistence ) { - case 'Transient' : - modelContent = replaceNoCase( modelContent, '|modelPersistence|', '', 'all' ); - break; - case 'Singleton' : - modelContent = replaceNoCase( modelContent, '|modelPersistence|', 'singleton ', 'all'); - } - - // Accessors - if( arguments.accessors ){ - modelContent = replaceNoCase( modelContent, '|accessors|', 'accessors="true"', 'all'); - } else { - modelContent = replaceNoCase( modelContent, '|accessors|', '', 'all'); - } - - // Properties - var properties = listToArray( arguments.properties ); - var buffer = createObject( "java", "java.lang.StringBuffer" ).init(); - for( var thisProperty in properties ){ - var propName = getToken( trim( thisProperty ), 1, ":"); - var propType = getToken( trim( thisProperty ), 2, ":"); - if( NOT len( propType ) ){ propType = "string"; } - - if( arguments.script ){ - buffer.append( 'property name="#propName#" type="#propType#";#chr(13) & chr(9)#' ); - } else { - buffer.append( chr( 60 ) & 'cfproperty name="#propName#" type="#propType#">#chr(13) & chr(9)#' ); - } - } - modelContent = replaceNoCase( modelContent, "|properties|", buffer.toString() ); - - // Handle Methods - if( len( arguments.methods ) ){ - var allMethods = ""; - var allTestsCases = ""; - var methodContent = ""; - - // Loop Over methods to generate them - for( var thisMethod in listToArray( arguments.methods ) ) { - if( thisMethod == 'init' ) { continue; } - - thisMethod = trim( thisMethod ); - allMethods = allMethods & replaceNoCase( modelMethodContent, '|method|', thisMethod, 'all' ) & cr & cr; - - print.yellowLine( "Generated method: #thisMethod#"); - - // Are we creating tests cases on methods - if( arguments.tests ) { - var thisTestCase = replaceNoCase( modelTestMethodContent, '|method|', thisMethod, 'all' ); - allTestsCases &= thisTestCase & CR & CR; - } - } - - // final replacement - modelContent = replaceNoCase( modelContent, '|methods|', allMethods, 'all'); - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', allTestsCases, 'all'); - } else { - modelContent = replaceNoCase( modelContent, '|methods|', '', 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', '', 'all' ); - } - - // Write out the model - var modelPath = '#directory#/#arguments.name#.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( modelPath ), true, true ); - file action='write' file='#modelPath#' mode ='777' output='#trim( modelContent )#'; - print.greenLine( 'Created #modelPath#' ); - - if( arguments.tests ) { - var testPath = '#arguments.TestsDirectory#/#arguments.name#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; - // open file - if( arguments.open ){ openPath( testPath ); } - print.greenLine( 'Created #testPath#' ); - } - - // Open file? - if( arguments.open ){ openPath( modelPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-crud.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-crud.cfc deleted file mode 100644 index 913fe32f2..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-crud.cfc +++ /dev/null @@ -1,136 +0,0 @@ -/** -* Generate some CRUD goodness out of an ORM entity. -* . -* Make sure you are running this command in the root of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create crud models.Contact -* {code} -* - **/ -component { - - /** - * @entity The name and dot location path of the entity to create the CRUD for, starting from the root of your application. For example: models.Contact, models.security.User - * @pluralName The plural name of the entity. Used for display purposes. Defaults to 'entityName' + s - * @handlersDirectory The location of the handlers. Defaults to 'handlers' - * @viewsDirectory The location of the views. Defaults to 'views' - * @tests Generate the BDD tests for this CRUD operation - * @testsDirectory Your integration tests directory. Only used if tests is true - **/ - function run( - required entity, - pluralName="", - handlersDirectory="handlers", - viewsDirectory="views", - boolean tests=true, - testsDirectory='tests/specs/integration' - ) { - // This will make each directory canonical and absolute - arguments.handlersDirectory = fileSystemUtil.resolvePath( arguments.handlersDirectory ); - arguments.viewsDirectory = fileSystemUtil.resolvePath( arguments.viewsDirectory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // entity defaults - var entityName = listLast( arguments.entity, "." ); - var entityCFC = fileSystemUtil.resolvePath( replace( arguments.entity, ".", "/", "all" ) ); - var entityPath = entityCFC & ".cfc"; - // verify it - if( !fileExists( entityPath ) ){ - return error( "The entity #entityPath# does not exist, cannot continue, ciao!" ); - } - // Get content - var entityContent = fileRead( entityPath ); - // property Map - var metadata = { properties = [], pk="" }; - var md = getComponentMetadata( entityCFC ); - - // argument defaults - if( !len( arguments.pluralname ) ){ arguments.pluralName = entityName & "s"; } - - // build property maps - if( arrayLen( md.properties ) ){ - // iterate and build metadata map - for( var thisProperty in md.properties ){ - // convert string to property representation - entityDefaults( thisProperty ); - // store the pk for convenience - if( compareNoCase( thisProperty.fieldType, "id" ) EQ 0 ){ metadata.pk = thisProperty.name; } - - // Store only persistable columns - if( thisProperty.isPersistable ){ - arrayAppend( metadata.properties, thisProperty ); - } - } - - //********************** generate handler ************************************// - - // Read Handler Content - var hContent = fileRead( '/coldbox-commands/templates/crud/HandlerContent.txt' ); - // Token replacement - hContent = replacenocase( hContent, "|entity|", entityName, "all" ); - hContent = replacenocase( hContent, "|entityPlural|", arguments.pluralName, "all" ); - hContent = replacenocase( hContent, "|pk|", metadata.pk, "all" ); - - // Write Out Handler - var hpath = '#arguments.handlersDirectory#/#arguments.pluralName#.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( hpath ), true, true ); - file action='write' file='#hpath#' mode ='777' output='#hContent#'; - print.greenLine( 'Generated Handler: #hPath#' ); - - //********************** generate views ************************************// - - // Create Views Path - directorycreate( arguments.viewsDirectory & "/#arguments.pluralName#", true, true ); - var views = [ "edit", "editor", "new" ]; - for( var thisView in views ){ - var vContent = fileRead( '/coldbox-commands/templates/crud/#thisView#.txt' ); - vContent = replacenocase( vContent, "|entity|", entityName, "all" ); - vContent = replacenocase( vContent, "|entityPlural|", arguments.pluralName, "all" ); - fileWrite( arguments.viewsDirectory & "/#arguments.pluralName#/#thisView#.cfm", vContent); - print.greenLine( 'Generated View: ' & arguments.viewsDirectory & "/#arguments.pluralName#/#thisView#.cfm" ); - } - - //********************** generate table output ************************************// - - // Build table output for index - savecontent variable="local.tableData"{ - include '/coldbox-commands/templates/crud/table.cfm'; - } - tableData = replaceNoCase( tableData, "%cf", "#chr(60)#cf", "all" ); - tableData = replaceNoCase( tableData, "%/cf", "#chr(60)#/cf", "all" ); - // index data - var vContent = fileRead( '/coldbox-commands/templates/crud/index.txt' ); - vContent = replacenocase( vContent, "|entity|", entityName, "all" ); - vContent = replacenocase( vContent, "|entityPlural|", arguments.pluralName, "all" ); - vContent = replacenocase( vContent, "|tableListing|", tableData, "all" ); - fileWrite( arguments.viewsDirectory & "/#arguments.pluralName#/index.cfm", vContent); - print.greenLine( 'Generated View: ' & arguments.viewsDirectory & "/#arguments.pluralName#/index.cfm" ); - } else { - return error( "The entity: #entityName# has no properties, so I have no clue what to CRUD on dude!" ); - } - - } - - /** - * Get entity property metadata - * @target The target metadata struc - */ - private function entityDefaults( required target ){ - // add defaults to it - if( NOT structKeyExists( arguments.target, "fieldType" ) ){ arguments.target.fieldType = "column"; } - if( NOT structKeyExists( arguments.target, "persistent" ) ){ arguments.target.persistent = true; } - if( NOT structKeyExists( arguments.target, "formula" ) ){ arguments.target.formula = ""; } - if( NOT structKeyExists( arguments.target, "readonly" ) ){ arguments.target.readonly = false; } - - // Add column isValid depending if it is persistable - arguments.target.isPersistable = true; - if( NOT arguments.target.persistent OR len( arguments.target.formula ) OR arguments.target.readonly ){ - arguments.target.isPersistable = false; - } - - return arguments.target; - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-entity.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-entity.cfc deleted file mode 100644 index 5cfa1f09c..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-entity.cfc +++ /dev/null @@ -1,143 +0,0 @@ -/** -* Create a new CFML ORM entity. You can pass in extra attributes like making it an enhanced ColdBox ORM Active Entity, or generating -* primary keys and properties. -* . -* You can pass a primary key value or use the default of 'id'. You can then pass also an optional primary key table name and generator. -* The default generator used is 'native' -* . -* To generate properties you will pass a list of property names to the 'properties' argument. You can also add -* ORM types to the properties by separating them with a semicolon. For example: -* {code:bash} -* properties=name,createDate:timestamp,age:numeric -* {code} -* . -* Make sure you are running this command in the root of your app for it to find the correct folder. -* . -* {code:bash} -* // Basic -* coldbox create orm-entity User --open -* -* // Active Entity -* coldbox create orm-entity User --open --activeEntity -* -* // With Some Specifics -* coldbox create orm-entity entityName=User table=users primaryKey=userID generator=uuid -* -* // With some properties -* coldbox create orm-entity entityName=User properties=firstname,lastname,email,createDate:timestamp,updatedate:timestamp,age:numeric -* {code} -* - **/ -component { - - /** - * @entityName The name of the entity without .cfc - * @table The name of the mapped table or empty to use the same name as the entity - * @directory The base directory to create your model in and creates the directory if it does not exist. - * @activeEntity Will this be a ColdBox ORM Active entity or a Normal CFML entity. Defaults to false. - * @primaryKey Enter the name of the primary key, defaults to 'id' - * @primaryKeyColumn Enter the name of the primary key column. Leave empty if same as the primaryKey value - * @generator Enter the ORM key generator to use, defaults to 'native' - * @generator.options increment,identity,sequence,native,assigned,foreign,seqhilo,uuid,guid,select,sequence-identiy - * @properties Enter a list of properties to generate. You can add the ORM type via semicolon separator, default type is string. Ex: firstName,age:numeric,createdate:timestamp - * @tests Generate the unit test BDD component - * @testsDirectory Your unit tests directory. Only used if tests is true - * @script Generate as script or not, defaults to true - * @open Open the file(s) once generated - **/ - function run( - required entityName, - table="", - directory="models", - boolean activeEntity=false, - primaryKey="id", - primaryKeyColumn="", - generator="native", - properties="", - boolean tests=true, - testsDirectory='tests/specs/unit', - boolean script=true, - boolean open=false - ) { - // non-canonical path - var nonCanonicalDirectory = arguments.directory; - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // script - var scriptPrefix = ""; - if( arguments.script ){ scriptPrefix = "Script"; } - - // Argument defaults - if( !len( arguments.table ) ){ arguments.table = arguments.entityName; } - if( !len( arguments.primaryKeyColumn ) ){ arguments.primaryKeyColumn = arguments.primaryKey; } - - // Read in Template - var modelContent = fileRead( '/coldbox-commands/templates/orm/Entity#scriptPrefix#.txt' ); - var modelTestContent = fileRead( '/coldbox-commands/templates/testing/ORMEntityBDDContent#scriptPrefix#.txt' ); - - // Basic replacements - modelContent = replaceNoCase( modelContent, '|entityName|', arguments.entityName, 'all' ); - modelContent = replaceNoCase( modelContent, '|table|', arguments.table, 'all' ); - modelContent = replaceNoCase( modelContent, "|primaryKey|", arguments.primaryKey,"all" ); - modelContent = replaceNoCase( modelContent, "|primaryKeyColumn|", arguments.primaryKeyColumn,"all" ); - modelContent = replaceNoCase( modelContent, "|generator|", arguments.generator,"all" ); - - // Active Entity? - if( arguments.activeEntity ){ - modelContent = replaceNoCase( modelContent, "|activeEntity|",' extends="cborm.models.ActiveEntity"',"all" ); - modelContent = replaceNoCase( modelContent, "|activeEntityInit|",'super.init( useQueryCaching="false" );', "all" ); - } else { - modelContent = replaceNoCase( modelContent, "|activeEntity|", "", "all" ); - modelContent = replaceNoCase( modelContent, "|activeEntityInit|", "", "all" ); - } - - // Test Content Replacement - modelTestContent = replaceNoCase( modelTestContent, '|modelName|', "#nonCanonicalDirectory#.#arguments.entityName#", 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', "", 'all'); - - // Properties - var properties = listToArray( arguments.properties ); - var buffer = createObject( "java", "java.lang.StringBuffer" ).init(); - for( var thisProperty in properties ){ - var propName = getToken( trim( thisProperty ), 1, ":"); - var propType = getToken( trim( thisProperty ), 2, ":"); - if( NOT len( propType ) ){ propType = "string"; } - - if( arguments.script ){ - buffer.append( 'property name="#propName#" ormtype="#propType#";#chr(13) & chr(9)#' ); - } else { - buffer.append( chr( 60 ) & 'cfproperty name="#propName#" ormtype="#propType#">#chr(13) & chr(9)#' ); - } - } - modelContent = replaceNoCase( modelContent, "|properties|", buffer.toString() ); - - // Write out the model - var modelPath = '#arguments.directory#/#arguments.entityName#.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( modelPath ), true, true ); - file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; - print.greenLine( 'Created #modelPath#' ); - - if( arguments.tests ) { - var testPath = '#arguments.TestsDirectory#/#arguments.entityName#Test.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; - // open file - if( arguments.open ){ openPath( testPath ); } - print.greenLine( 'Created #testPath#' ); - } - - // Open file? - if( arguments.open ){ openPath( modelPath ); } - } - -} diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-event-handler.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-event-handler.cfc deleted file mode 100644 index b0e7ca327..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-event-handler.cfc +++ /dev/null @@ -1,49 +0,0 @@ -/** -* Create a new ORM Event Handler in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create orm-event-handler MyEventHandler --open -* {code} -* - **/ -component { - - /** - * @name.hint Name of the event handler to create without the .cfc. For packages, specify name as 'myPackage/myModel' - * @directory.hint The base directory to create your event handler in and creates the directory if it does not exist. - * @open.hint Open the file once generated - **/ - function run( - required name, - directory='models', - boolean open=false - ) { - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // Allow dot-delimited paths - arguments.name = replace( arguments.name, '.', '/', 'all' ); - // This help readability so the success messages aren't up against the previous command line - print.line(); - - // Read in Template - var modelContent = fileRead( '/coldbox-commands/templates/orm/ORMEventHandler.txt' ); - - // Write out the model - var modelPath = '#directory#/#arguments.name#.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( modelPath ), true, true ); - file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; - print.greenLine( 'Created #modelPath#' ); - - // Open file? - if( arguments.open ){ openPath( modelPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-service.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-service.cfc deleted file mode 100644 index 6ecbbd994..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-service.cfc +++ /dev/null @@ -1,82 +0,0 @@ -/** -* Create a new base ORM entity service model in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create orm-service SecurityService --open -* {code} -* - **/ -component { - - /** - * @serviceName The name of this Base ORM service to create - * @directory The base directory to create your model in and creates the directory if it does not exist. - * @queryCaching Will you be activating query caching or not - * @eventHandling Will the virtual entity service emit events - * @cacheRegion The cache region the virtual entity service methods will use - * @tests Generate the unit test BDD component - * @testsDirectory Your unit tests directory. Only used if tests is true - * @open Open the file once generated - **/ - function run( - required serviceName, - directory="models", - boolean queryCaching=false, - boolean eventHandling=true, - cacheRegion="", - boolean tests=true, - testsDirectory='tests/specs/unit', - boolean open=false - ) { - // non-canonical path - var nonCanonicalDirectory = arguments.directory; - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // Read in Template - var modelContent = fileRead( '/coldbox-commands/templates/orm/TemplatedEntityService.txt' ); - var modelTestContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDContentScript.txt' ); - - // Query cache Region - if( !len( arguments.cacheRegion ) ){ - arguments.cacheRegion = "ormservice.#arguments.serviceName#"; - } - - // Basic replacements - modelContent = replaceNoCase( modelContent, '|serviceName|', arguments.serviceName, 'all' ); - modelContent = replaceNoCase( modelContent, '|QueryCaching|', arguments.QueryCaching, 'all' ); - modelContent = replaceNoCase( modelContent, '|cacheRegion|', arguments.cacheRegion, 'all' ); - modelContent = replaceNoCase( modelContent, '|eventHandling|', arguments.eventHandling, 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|modelName|', "#nonCanonicalDirectory#.#arguments.serviceName#", 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', "", 'all'); - - // Write out the model - var modelPath = '#arguments.directory#/#arguments.serviceName#Service.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( modelPath ), true, true ); - file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; - print.greenLine( 'Created #modelPath#' ); - - if( arguments.tests ) { - var testPath = '#arguments.TestsDirectory#/#arguments.serviceName#ServiceTest.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; - // open file - if( arguments.open ){ openPath( testPath ); } - print.greenLine( 'Created #testPath#' ); - } - - // Open file? - if( arguments.open ){ openPath( modelPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-virtual-service.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-virtual-service.cfc deleted file mode 100644 index b399f6616..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/orm-virtual-service.cfc +++ /dev/null @@ -1,82 +0,0 @@ -/** -* Create a new virtual entity service model in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. -* . -* {code:bash} -* coldbox create orm-virtual-service Contact --open -* {code} -* - **/ -component { - - /** - * @entityName The name of the entity this virtual service will be bound to - * @directory The base directory to create your model in and creates the directory if it does not exist. - * @queryCaching Will you be activating query caching or not - * @eventHandling Will the virtual entity service emit events - * @cacheRegion The cache region the virtual entity service methods will use - * @tests Generate the unit test BDD component - * @testsDirectory Your unit tests directory. Only used if tests is true - * @open Open the file once generated - **/ - function run( - required entityName, - directory="models", - boolean queryCaching=false, - boolean eventHandling=true, - cacheRegion="", - boolean tests=true, - testsDirectory='tests/specs/unit', - boolean open=false - ) { - // non-canonical path - var nonCanonicalDirectory = arguments.directory; - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - arguments.testsDirectory = fileSystemUtil.resolvePath( arguments.testsDirectory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // Read in Template - var modelContent = fileRead( '/coldbox-commands/templates/orm/VirtualEntityService.txt' ); - var modelTestContent = fileRead( '/coldbox-commands/templates/testing/ModelBDDContentScript.txt' ); - - // Query cache Region - if( !len( arguments.cacheRegion ) ){ - arguments.cacheRegion = "ormservice.#arguments.entityName#"; - } - - // Basic replacements - modelContent = replaceNoCase( modelContent, '|entityName|', arguments.entityname, 'all' ); - modelContent = replaceNoCase( modelContent, '|QueryCaching|', arguments.QueryCaching, 'all' ); - modelContent = replaceNoCase( modelContent, '|cacheRegion|', arguments.cacheRegion, 'all' ); - modelContent = replaceNoCase( modelContent, '|eventHandling|', arguments.eventHandling, 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|modelName|', "#nonCanonicalDirectory#.#arguments.entityName#", 'all' ); - modelTestContent = replaceNoCase( modelTestContent, '|TestCases|', "", 'all'); - - // Write out the model - var modelPath = '#arguments.directory#/#arguments.entityName#Service.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( modelPath ), true, true ); - file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; - print.greenLine( 'Created #modelPath#' ); - - if( arguments.tests ) { - var testPath = '#arguments.TestsDirectory#/#arguments.entityName#ServiceTest.cfc'; - // Create dir if it doesn't exist - directorycreate( getDirectoryFromPath( testPath ), true, true ); - // Create the tests - file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; - // open file - if( arguments.open ){ openPath( testPath ); } - print.greenLine( 'Created #testPath#' ); - } - - // Open file? - if( arguments.open ){ openPath( modelPath ); } - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/create.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc similarity index 100% rename from src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/create.cfc rename to src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/unit.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/unit.cfc deleted file mode 100644 index d0df1253e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/unit.cfc +++ /dev/null @@ -1,23 +0,0 @@ -/** -* Create a new xUnit Bundle in an existing ColdBox-enabled application. Run this command in the root -* of your app for it to find the correct folder. By default, your new xUnit Bundle will be created in /tests/specs but you can -* override that with the directory param. -* . -* {code:bash} -* coldbox create unit myUnit -* {code} -* -**/ -component { - - /** - * @name.hint Name of the xUnit Bundle to create without the .cfc. For packages, specify name as 'myPackage/MyServiceTest' - * @open.hint Open the file once it is created - * @directory.hint The base directory to create your BDD spec in, defaults to 'tests/specs' - **/ - function run( required name, boolean open=false, directory="tests/specs" ){ - // proxy to testbox - runCommand( "testbox create unit name=#arguments.name# directory=#arguments.directory# open=#arguments.open#" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/view.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/view.cfc deleted file mode 100644 index 2e78898c9..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/view.cfc +++ /dev/null @@ -1,65 +0,0 @@ -/** -* Create a new view in an existing ColdBox application. Run this command in the root -* of your app for it to find the correct folder. By default, your new view will be created in /views but you can -* override that with the directory param. -* . -* {code:bash} -* coldbox create view myView -* {code} -* -**/ -component { - - /** - * @name.hint Name of the view to create without the .cfm. - * @helper.hint Generate a helper file for this view - * @directory.hint The base directory to create your view in and creates the directory if it does not exist. - **/ - function run( - required name, - boolean helper=false, - directory='views' - ){ - // Allow dot-delimited paths - arguments.name = replace( arguments.name, '.', '/', 'all' ); - - // Check if the name is actually a path - var nameArray = arguments.name.listToArray( '/' ); - var nameArrayLength = nameArray.len(); - if (nameArrayLength > 1) { - // If it is a path, split the path from the name - arguments.name = nameArray[nameArrayLength]; - var extendedPath = nameArray.slice(1, nameArrayLength - 1).toList('/'); - arguments.directory &= '/#extendedPath#'; - } - - // This will make each directory canonical and absolute - arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - - // Validate directory - if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); - } - - // This help readability so the success messages aren't up against the previous command line - print.line(); - - var viewContent = '

#arguments.name# view

'; - var viewHelperContent = ''; - - // Write out view - var viewPath = '#arguments.directory#/#arguments.name#.cfm'; - file action='write' file='#viewPath#' mode ='777' output='#viewContent#'; - print.greenLine( 'Created #viewPath#' ); - - if( arguments.helper ) { - // Write out view helper - var viewHelperPath = '#arguments.directory#/#arguments.name#Helper.cfm'; - file action='write' file='#viewHelperPath#' mode ='777' output='#viewHelperContent#'; - print.greenLine( 'Created #viewHelperPath#' ); - - } - - } - -} diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/edit.cfm b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/edit.cfm deleted file mode 100644 index c3b2ef025..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/edit.cfm +++ /dev/null @@ -1 +0,0 @@ - #renderView(view="Users/editor", args={title="Update User"})# \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/editor.cfm b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/editor.cfm deleted file mode 100644 index c7a418461..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/editor.cfm +++ /dev/null @@ -1,39 +0,0 @@ - - - -

#args.title#

- - -#html.startForm( action='Users.save' )# - - - #html.entityFields( entity=prc.User, - groupWrapper="div class='form-group'", - class="form-control", - fieldWrapper="", - labelWrapper="", - textAreas="", - booleanSelect=true, - manyToOne={}, - manyToMany={}, - showRelations=true)# - - -
- #html.href( href="Users", text="Cancel", class="btn btn-default" )# - #html.submitButton(value="Save", class="btn btn-primary")# -
- -#html.endForm()# -
\ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/index.cfm b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/index.cfm deleted file mode 100644 index 5ebffb1bb..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/index.cfm +++ /dev/null @@ -1,49 +0,0 @@ - -

Users

- - - -
- #flash.get( "notice" ).message# -
-
- - -#html.href( href="Users.new", text="Create User", class="btn btn-primary")# -#html.br(2)# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#thisProp.name#Actions
##thisRecord.get#thisProp.name#()## - ##html.startForm(action="#inputStruct.pluralname#.delete")## - ##html.hiddenField(name="#metadata.pk#", bind=thisRecord)## - ##html.submitButton(value="Delete", onclick="return confirm('Really Delete Record?')", class="btn btn-danger")## - ##html.href(href="#inputStruct.pluralName#.edit", queryString="#metadata.pk#=##thisRecord.get#metadata.pk#()##", text="Edit", class="btn btn-info")## - ##html.endForm()## -
-
-
\ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/new.cfm b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/new.cfm deleted file mode 100644 index 5d6de5784..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/views/Users/new.cfm +++ /dev/null @@ -1,3 +0,0 @@ - -#renderView(view="Users/editor", args={title="Create User"})# - \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/install.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc similarity index 100% rename from src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/install.cfc rename to src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/help.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/help.cfc deleted file mode 100644 index 2246ce67e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/help.cfc +++ /dev/null @@ -1,12 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line(); - print.yellowLine( 'General help and description of how to use contentbox module' ); - print.line(); - print.line(); - - - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/list.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/list.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/list.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/remove.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/remove.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/module/remove.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/create.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/create.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/create.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/help.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/help.cfc deleted file mode 100644 index 486d14d9f..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/help.cfc +++ /dev/null @@ -1,12 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line(); - print.yellowLine( 'General help and description of how to use contentbox theme' ); - print.line(); - print.line(); - - - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/install.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/install.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/install.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/list.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/list.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/list.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/remove.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/remove.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/theme/remove.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/create.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/create.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/create.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/help.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/help.cfc deleted file mode 100644 index 7e779d6f6..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/help.cfc +++ /dev/null @@ -1,12 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line(); - print.yellowLine( 'General help and description of how to use contentbox widget' ); - print.line(); - print.line(); - - - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/install.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/install.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/install.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/list.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/list.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/list.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/remove.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/remove.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/widget/remove.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/disable.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/disable.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/disable.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/enable.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/enable.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/enable.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/bundle.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/bundle.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/bundle.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/directory.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/directory.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/directory.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/help.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/help.cfc deleted file mode 100644 index 1e3a994dc..000000000 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/help.cfc +++ /dev/null @@ -1,12 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line(); - print.yellowLine( 'General help and description of how to use testbox open' ); - print.line(); - print.line(); - - - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/runner.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/runner.cfc deleted file mode 100644 index dce2a8c4e..000000000 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/open/runner.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Description of command - **/ -component { - - /** - * - **/ - function run( ) { - print.line( "Command not implemented!" ); - } - -} \ No newline at end of file From a420a8a625c0ddcf78678e5a031983a031b2c3f2 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 24 May 2017 00:03:26 -0500 Subject: [PATCH 079/123] COMMANDBOX-50 --- src/cfml/system/BaseTask.cfc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/cfml/system/BaseTask.cfc diff --git a/src/cfml/system/BaseTask.cfc b/src/cfml/system/BaseTask.cfc new file mode 100644 index 000000000..9502f9384 --- /dev/null +++ b/src/cfml/system/BaseTask.cfc @@ -0,0 +1,15 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I am the base task implementation. An abstract class if you will. +* +*/ +component accessors="true" extends='commandbox.system.BaseCommand' { + + // For now, tasks just do everything commands do + +} \ No newline at end of file From d612a9dea00c23bb449452912ea3ac4bf7cdb507 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 24 May 2017 00:13:40 -0500 Subject: [PATCH 080/123] More clean up of old commands --- .../task-commands/commands/task/create.cfc | 14 -------------- .../task-commands/commands/task/help.cfc | 12 ------------ .../task-commands/commands/task/kill-all.cfc | 10 ---------- .../task-commands/commands/task/remove.cfc | 13 ------------- .../commands/task/{list.cfc => run.cfc} | 2 +- .../wirebox/create/{aspects.cfc => aspect.cfc} | 0 6 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 src/cfml/system/modules_app/task-commands/commands/task/create.cfc delete mode 100644 src/cfml/system/modules_app/task-commands/commands/task/help.cfc delete mode 100644 src/cfml/system/modules_app/task-commands/commands/task/kill-all.cfc delete mode 100644 src/cfml/system/modules_app/task-commands/commands/task/remove.cfc rename src/cfml/system/modules_app/task-commands/commands/task/{list.cfc => run.cfc} (59%) rename src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/{aspects.cfc => aspect.cfc} (100%) diff --git a/src/cfml/system/modules_app/task-commands/commands/task/create.cfc b/src/cfml/system/modules_app/task-commands/commands/task/create.cfc deleted file mode 100644 index 04871df45..000000000 --- a/src/cfml/system/modules_app/task-commands/commands/task/create.cfc +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Adds a task to be executed on the given interval - **/ -component { - - /** - * @name.hint The Task name - * @interval.hint The task interval in seconds - **/ - function run( required String name, required numeric interval ) { - print.line( "faux-task-add! Task:#name# Interval:#interval#" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/commands/task/help.cfc b/src/cfml/system/modules_app/task-commands/commands/task/help.cfc deleted file mode 100644 index ea26583e0..000000000 --- a/src/cfml/system/modules_app/task-commands/commands/task/help.cfc +++ /dev/null @@ -1,12 +0,0 @@ -component excludeFromHelp=true { - - function run() { - - print.line(); - print.yellowLine( 'General help and description of how to use tasks' ); - print.line(); - print.line(); - - - } -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/commands/task/kill-all.cfc b/src/cfml/system/modules_app/task-commands/commands/task/kill-all.cfc deleted file mode 100644 index 9faeef65d..000000000 --- a/src/cfml/system/modules_app/task-commands/commands/task/kill-all.cfc +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Kills all running tasks - **/ -component aliases="kill" { - - function run( ) { - print.line( "faux-kill!" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/commands/task/remove.cfc b/src/cfml/system/modules_app/task-commands/commands/task/remove.cfc deleted file mode 100644 index ab86f74cf..000000000 --- a/src/cfml/system/modules_app/task-commands/commands/task/remove.cfc +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Remvoe a task - **/ -component { - - /** - * @name.hint The Task name - **/ - function run( required String name ) { - print.line( "faux-remove! Task:#name#" ); - } - -} \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/commands/task/list.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc similarity index 59% rename from src/cfml/system/modules_app/task-commands/commands/task/list.cfc rename to src/cfml/system/modules_app/task-commands/commands/task/run.cfc index d473629a6..2ab9bec8e 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/list.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -4,7 +4,7 @@ component { function run( ) { - print.line( "faux-list!" ); + print.line( "Command not implemented!" ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspects.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc similarity index 100% rename from src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspects.cfc rename to src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc From 262c7d834065852d8744a5fa024ef5b3a2c07fa6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 24 May 2017 18:05:05 -0500 Subject: [PATCH 081/123] COMMANDBOX-638 --- src/cfml/system/endpoints/Jar.cfc | 99 +++++++++++++++++++ .../task-commands/commands/task/run.cfc | 2 +- src/cfml/system/services/PackageService.cfc | 3 + 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/cfml/system/endpoints/Jar.cfc diff --git a/src/cfml/system/endpoints/Jar.cfc b/src/cfml/system/endpoints/Jar.cfc new file mode 100644 index 000000000..df02ddf42 --- /dev/null +++ b/src/cfml/system/endpoints/Jar.cfc @@ -0,0 +1,99 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I am the Jar endpoint. I get bare jar files from an HTTP URL. +* I will spoof a package around the jar so CommandBox doesn't try to unzip the jar itself. +*/ +component accessors=true implements="IEndpoint" singleton { + + // DI + property name="consoleLogger" inject="logbox:logger:console"; + property name="tempDir" inject="tempDir@constants"; + property name="progressableDownloader" inject="ProgressableDownloader"; + property name="progressBar" inject="ProgressBar"; + property name="CR" inject="CR@constants"; + property name='formatterUtil' inject='formatter'; + + // Properties + property name="namePrefixes" type="string"; + + function init() { + setNamePrefixes( 'jar' ); + return this; + } + + public string function resolvePackage( required string package, boolean verbose=false ) { + + var folderName = tempDir & '/' & 'temp#randRange( 1, 1000 )#'; + directoryCreate( folderName ); + var fullJarPath = folderName & '/' & getDefaultName( package ) & '.jar'; + var fullBoxJSONPath = folderName & '/box.json'; + + consoleLogger.info( "Downloading [#package#]" ); + + try { + // Download File + var result = progressableDownloader.download( + package, // URL to package + fullJarPath, // Place to store it locally + function( status ) { + progressBar.update( argumentCollection = status ); + }, + function( newURL ) { + consoleLogger.info( "Redirecting to: '#arguments.newURL#'..." ); + } + ); + } catch( Any var e ) { + throw( '#e.message##CR##e.detail#', 'endpointException' ); + }; + + // Spoof a box.json so this looks like a package + var boxJSON = { + 'name' : '#getDefaultName( package )#.jar', + 'slug' : getDefaultName( package ), + 'version' : '0.0.0', + 'location' : 'jar:#package#', + 'type' : 'jars' + }; + fileWrite( fullBoxJSONPath, formatterUtil.formatJSON( boxJSON ) ); + + // Here is where our alleged so-called "package" lives. + return folderName; + + } + + public function getDefaultName( required string package ) { + + var baseURL = arguments.package; + + // strip query string, unless it possibly contains .jar like so: + // https://search.maven.org/remotecontent?filepath=jline/jline/3.0.0.M1/jline-3.0.0.M1.jar + if( !right( arguments.package, 4 ) == '.jar' ) { + baseURL = listFirst( arguments.package, '?' ); + } + + // Find last segment of URL (may or may not be a file) + var fileName = listLast( baseURL, '/' ); + + // Check for file extension in URL + var fileNameListLen = listLen( fileName, '.' ); + if( fileNameListLen > 1 && listLast( fileName, '.' ) == 'jar' ) { + return listDeleteAt( fileName, fileNameListLen, '.' ); + } + return reReplaceNoCase( baseURL, '[^a-zA-Z0-9]', '', 'all' ); + } + + public function getUpdate( required string package, required string version, boolean verbose=false ) { + var result = { + isOutdated = true, + version = 'unknown' + }; + + return result; + } + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc index 2ab9bec8e..943f3624e 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -1,5 +1,5 @@ /** - * List all tasks + * Run a task **/ component { diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 55407494d..fb5a8da9a 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -332,6 +332,9 @@ component accessors="true" singleton { artifactDescriptor.createPackageDirectory = false; // Don't trash the plugins folder with this ignorePatterns.append( '/box.json' ); + // This is a jar. + } else if( packageType == 'jars' ) { + installDirectory = arguments.packagePathRequestingInstallation & '/lib'; } } From 5beae02dd2481154a86a3f5e9e7d6fb41abca87d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 25 May 2017 02:17:30 -0500 Subject: [PATCH 082/123] Additional comments --- src/cfml/system/endpoints/Jar.cfc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfml/system/endpoints/Jar.cfc b/src/cfml/system/endpoints/Jar.cfc index df02ddf42..dfd02e86b 100644 --- a/src/cfml/system/endpoints/Jar.cfc +++ b/src/cfml/system/endpoints/Jar.cfc @@ -84,6 +84,7 @@ component accessors=true implements="IEndpoint" singleton { if( fileNameListLen > 1 && listLast( fileName, '.' ) == 'jar' ) { return listDeleteAt( fileName, fileNameListLen, '.' ); } + // We give up, so just make the entire URL a slug return reReplaceNoCase( baseURL, '[^a-zA-Z0-9]', '', 'all' ); } From 519251408ca5edef12c3cdf870d0526b2b333792 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 31 May 2017 11:48:22 -0500 Subject: [PATCH 083/123] COMMANDBOX-548 --- .../server-commands/commands/server/start.cfc | 7 ++++-- src/cfml/system/services/ServerService.cfc | 25 ++++++++++++++----- src/cfml/system/util/FileSystem.cfc | 8 ++---- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index f12963f21..3f8980a11 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -82,7 +82,9 @@ component aliases="start" { * @console Start this server in the forground console process and wait until Ctrl-C is pressed to stop it. * @welcomeFiles A comma-delimited list of default files to load when visiting a directory (index.cfm,index.htm,etc) * @serverHomeDirectory The folder where the CF engine WAR should be extracted - * @restMappings A comma-delimited list of REST mappings in the form of /api/*,/rest/*. Empty string to disable. + * @restMappings A comma-delimited list of REST mappings in the form of /api/*,/rest/*. Empty string to disable. + * @trace Enable trace level logging + * @javaHomeDirectory Path to the JRE home directory containing ./bin/java **/ function run( String name, @@ -120,7 +122,8 @@ component aliases="start" { String welcomeFiles, String serverHomeDirectory, String restMappings, - Boolean trace + Boolean trace, + String javaHomeDirectory ){ // This is a common mis spelling diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index b21e5f97c..99959c547 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -124,7 +124,8 @@ component accessors="true" singleton { 'jvm' : { 'heapSize' : d.jvm.heapSize ?: 512, 'minHeapSize' : d.jvm.minHeapSize ?: 0, - 'args' : d.jvm.args ?: '' + 'args' : d.jvm.args ?: '', + 'javaHome' : ( isDefined( 'd.jvm.javaHome' ) ? fileSystemUtil.getJREExecutable( d.jvm.javaHome ) : variables.javaCommand ) }, 'web' : { 'host' : d.web.host ?: '127.0.0.1', @@ -425,6 +426,9 @@ component accessors="true" singleton { break; case "JVMArgs": serverJSON[ 'JVM' ][ 'args' ] = serverProps[ prop ]; + break; + case "javaHomeDirectory": + serverJSON[ 'JVM' ][ 'javaHome' ] = serverProps[ prop ]; break; case "runwarArgs": serverJSON[ 'runwar' ][ 'args' ] = serverProps[ prop ]; @@ -535,7 +539,15 @@ component accessors="true" singleton { serverInfo.heapSize = serverProps.heapSize ?: serverJSON.JVM.heapSize ?: defaults.JVM.heapSize; serverInfo.minHeapSize = serverProps.minHeapSize ?: serverJSON.JVM.minHeapSize ?: defaults.JVM.minHeapSize; - + + if( isDefined( 'serverProps.javaHomeDirectory' ) ) { + serverInfo.javaHome = fileSystemUtil.getJREExecutable( serverProps.javaHomeDirectory ); + } else if( isDefined( 'serverJSON.JVM.javaHome' ) ) { + serverInfo.javaHome = fileSystemUtil.getJREExecutable( serverJSON.JVM.javaHome ); + } else { + serverInfo.javaHome = defaults.JVM.javaHome; + } + serverInfo.directoryBrowsing = serverProps.directoryBrowsing ?: serverJSON.web.directoryBrowsing ?: defaults.web.directoryBrowsing; // Global aliases are always added on top of server.json (but don't overwrite) @@ -933,7 +945,7 @@ component accessors="true" singleton { if( serverInfo.debug ) { var cleanedArgs = cr & ' ' & trim( reReplaceNoCase( args.toList( ' ' ), ' (-|"-)', cr & ' \1', 'all' ) ); - consoleLogger.debug("Server start command: #javaCommand# #cleanedargs#"); + consoleLogger.debug("Server start command: #serverInfo.javaHome# #cleanedargs#"); } // needs to be unique in each run to avoid errors @@ -941,7 +953,7 @@ component accessors="true" singleton { // Construct a new process object var processBuilder = createObject( "java", "java.lang.ProcessBuilder" ); // Pass array of tokens comprised of command plus arguments - args.prepend( variables.javaCommand ); + args.prepend( serverInfo.javaHome ); processBuilder.init( args ); // Conjoin standard error and output for convenience. processBuilder.redirectErrorStream( true ); @@ -959,7 +971,7 @@ component accessors="true" singleton { try{ // save server info and persist - serverInfo.statusInfo = { command:variables.javaCommand, arguments:attributes.args.toList( ' ' ), result:'' }; + serverInfo.statusInfo = { command:serverInfo.javaHome, arguments:attributes.args.toList( ' ' ), result:'' }; serverInfo.status="starting"; setServerInfo( serverInfo ); @@ -1593,7 +1605,8 @@ component accessors="true" singleton { 'basicAuthEnable' : true, 'basicAuthUsers' : {}, 'heapSize' : 512, - 'minHeapSize' : 0, + 'minHeapSize' : 0, + 'javaHome' : '', 'directoryBrowsing' : true, 'JVMargs' : "", 'runwarArgs' : "", diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 6abf51d3b..49c229415 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -89,9 +89,9 @@ component accessors="true" singleton { /** * Get the JRE Executable from the File System */ - function getJREExecutable(){ + function getJREExecutable( javaHome ){ // get java home - var jreDirectory = createObject( "java", "java.lang.System" ).getProperty( "java.home" ); + var jreDirectory = arguments.javaHome ?: createObject( "java", "java.lang.System" ).getProperty( "java.home" ); if( isNull( jreDirectory ) OR !len( jreDirectory ) ){ throw(message="Java.home not found", type="IllegalStateException" ); } @@ -101,10 +101,6 @@ component accessors="true" singleton { var javaPath = jreDirectory & "/" & "bin" & "/java#fileExtension#"; // build command var javaCommand = createObject( "java", "java.io.File").init( javaPath ).getCanonicalPath(); - // take care of spaces in command -/* if( javaCommand contains " " ){ - javaCommand = """#javaCommand#"""; - }*/ return javaCommand; } From 036027c5fabc97e23579f2be85e51cd3c04e1fe8 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 1 Jun 2017 20:24:12 -0500 Subject: [PATCH 084/123] Additional comments --- src/cfml/system/services/ServerService.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 99959c547..78686e837 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -656,7 +656,7 @@ component accessors="true" singleton { // This will install the engine war to start, possibly downloading it first var installDetails = serverEngineService.install( cfengine=serverInfo.cfengine, basedirectory=serverinfo.customServerFolder, serverInfo=serverInfo, serverHomeDirectory=serverInfo.serverHomeDirectory ); serverInfo.serverHomeDirectory = installDetails.installDir; - // TODO: As of 3.5 this is for backwards compat. Remove in later version + // TODO: As of 3.5 "serverHome" is for backwards compat. Remove in later version in favor of serverHomeDirectory above serverInfo.serverHome = installDetails.installDir; serverInfo.logdir = serverInfo.serverHomeDirectory & "/logs"; serverInfo.consolelogPath = serverInfo.logdir & '/server.out.txt'; From 5b7ea4f788d24dc0133e86069b9dc7699d13b56a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 2 Jun 2017 23:53:32 -0500 Subject: [PATCH 085/123] COMMANDBOX-525 --- src/cfml/system/services/ServerService.cfc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 78686e837..6156aba3f 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -686,7 +686,13 @@ component accessors="true" singleton { if( serverInfo.cfengine contains "railo" ) { javaagent = '-javaagent:#serverInfo.serverHomeDirectory#/WEB-INF/lib/railo-inst.jar'; } - + + // Add in "/cf_scripts" alias for 2016+ servers if the /cf_scripts folder exists in the war we're starting and there isn't already an alias + // for this. I'm specifically not checking the engine name and version so this will work on regular Adobe wars and be future proof. + if( directoryExists( serverInfo.serverHomeDirectory & '/cf_scripts' ) && !serverInfo.aliases.keyExists( '/cf_scripts' ) ) { + serverInfo.aliases[ '/cf_scripts' ] = serverInfo.serverHomeDirectory & '/cf_scripts'; + } + // The process native name var processName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ) & ' [' & listFirst( serverinfo.cfengine, '@' ) & ' ' & installDetails.version & ']'; From fb54bcd4b9e859495335b54bcdb6e711b5c0f9e9 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 14 Jun 2017 23:02:17 -0500 Subject: [PATCH 086/123] COMMANDBOX-646 --- src/cfml/system/util/Parser.cfc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/util/Parser.cfc b/src/cfml/system/util/Parser.cfc index c13281734..1958ce13d 100644 --- a/src/cfml/system/util/Parser.cfc +++ b/src/cfml/system/util/Parser.cfc @@ -53,7 +53,8 @@ component { // Current character char = mid( line, i, 1 ); // All the remaining characters - remainingChars = mid( line, i, len( line ) ); + remainingChars = mid( line, i+1, len( line ) ); + // Reset this every time isEscaped = false; @@ -73,8 +74,11 @@ component { // We just reached the end of our quoted string if( char == quoteChar && !isEscaped ) { inQuotes = false; - tokens.append( token); - token = ''; + // Don't break if an = is next ... + if( left( trim( remainingChars ), 1 ) != '=' ) { + tokens.append( token); + token = ''; + } } prevEscaped = isEscaped; prevChar = char; @@ -199,6 +203,7 @@ component { var value = listRest( param, '=' ); // Unwrap quotes from value if used + name = unwrapQuotes( name ); value = unwrapQuotes( value ); // Mark expressions and system settings now while escaped chars are removed From f428a50bc9a31255a7e9c0891a7009b2a1ba2555 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 15 Jun 2017 00:00:02 -0500 Subject: [PATCH 087/123] COMMANDBOX-645 --- src/cfml/system/services/CommandService.cfc | 26 ++++++++++++++++++++- src/cfml/system/services/ConfigService.cfc | 5 +++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 6ccf37b9d..8fa737fcc 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -24,6 +24,7 @@ component accessors="true" singleton { // Using provider since CommandService is created before modules are loaded property name='stringDistance' inject='provider:StringSimilarity@string-similarity'; property name='SystemSettings' inject='SystemSettings'; + property name='ConfigService' inject='ConfigService'; property name='configured' default="false" type="boolean"; @@ -265,6 +266,9 @@ component accessors="true" singleton { // Merge flags into named params mergeFlagParameters( parameterInfo ); + // Add in defaults + addDefaultParameters( commandInfo.commandString, parameterInfo ); + // Make sure we have all required params. parameterInfo.namedParameters = ensureRequiredParams( parameterInfo.namedParameters, commandParams ); @@ -947,12 +951,32 @@ component accessors="true" singleton { return results; } + /** * Merge flags into named parameters **/ - private function mergeFlagParameters( required struct parameterInfo ){ + private function mergeFlagParameters( required struct parameterInfo ) { // Add flags into named params arguments.parameterInfo.namedParameters.append( arguments.parameterInfo.flags ); } + + /** + * Merge in parameter defaults + **/ + private function addDefaultParameters( commandString, parameterInfo ) { + // Get defaults for this command, an empty struct if nothing. + var defaults = configService.getSetting( 'command.defaults["#commandString#"]', {} ); + var params = parameterInfo.namedParameters; + + // For each default + defaults.each( function( k,v ) { + // If it's not already set + if( !params.keyExists( k ) ) { + // Stick it in there! + params[ k ] = v; + } + } ); + + } } \ No newline at end of file diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index 812c0b1d0..d4680bb18 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -52,7 +52,10 @@ component accessors="true" singleton { 'server', 'server.defaults', // used in Artifactsservice - 'artifactsDirectory' + 'artifactsDirectory', + // commands + 'command', + 'command.defaults' ]); setConfigFilePath( '/commandbox-home/CommandBox.json' ); From b9e6419bdf9e443e7bea4fdb6f6f7b83a1a957d9 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 15 Jun 2017 01:09:15 -0500 Subject: [PATCH 088/123] COMMANDBOX-644 --- src/cfml/system/services/ConfigService.cfc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index d4680bb18..45dd0af31 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -55,7 +55,8 @@ component accessors="true" singleton { 'artifactsDirectory', // commands 'command', - 'command.defaults' + 'command.defaults', + 'command.aliases' ]); setConfigFilePath( '/commandbox-home/CommandBox.json' ); From cbed9e7591af8cb69657480ad831e5ecc0f58446 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 15 Jun 2017 01:09:22 -0500 Subject: [PATCH 089/123] COMMANDBOX-644 --- src/cfml/system/services/CommandService.cfc | 119 ++++++++++++++------ 1 file changed, 82 insertions(+), 37 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 8fa737fcc..7d6c047ba 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -491,44 +491,9 @@ component accessors="true" singleton { // This will hold the command chain. Usually just a single command, // but a pipe ("|") will chain together commands and pass the output of one along as the input to the next - var commandsToResolve = [[]]; + var commandsToResolve = breakTokensIntoChain( tokens ); var commandChain = []; - // If this command has a pipe, we need to chain multiple commands - var i = 0; - for( var token in tokens ){ - i++; - // We've reached a pipe and there is at least one command resolved already and there are more tokens left - if( token == '|' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ '|' ] ); - commandsToResolve.append( [] ); - } else if( token == ';' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ ';' ] ); - commandsToResolve.append( [] ); - } else if( token == '&&' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ '&&' ] ); - commandsToResolve.append( [] ); - } else if( token == '||' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ '||' ] ); - commandsToResolve.append( [] ); - } else if( token == '>' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ '|' ] ); - commandsToResolve.append( [ 'fileWrite' ] ); - } else if( token == '>>' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command - commandsToResolve.append( [ '|' ] ); - commandsToResolve.append( [ 'fileAppend' ] ); - } else if( !listFindNoCase( '|,;,>,>>,&&', token ) ) { - //Append this token to the last command - commandsToResolve[ commandsToResolve.len() ].append( token ); - } - } - // command hierarchy var cmds = getCommandHierarchy(); var helpTokens = 'help,?,/?'; @@ -536,6 +501,7 @@ component accessors="true" singleton { for( var commandTokens in commandsToResolve ){ tokens = commandTokens; + var originalLine = tokens.toList( ' ' ); // If command ends with "help", switch it around to call the root help command // Ex. "coldbox help" becomes "help coldbox" @@ -594,7 +560,7 @@ component accessors="true" singleton { } var results = { - originalLine = tokens.toList( ' ' ), + originalLine = originalLine, commandString = '', commandReference = cmds, parameters = [], @@ -649,6 +615,85 @@ component accessors="true" singleton { return commandChain; } + + /** + * Takes a single array of tokens and breaks it into a chain of commands (array of arrays) + * i.e. foo bar | baz turns into [ [ 'foo', 'bar' ], [ '|' ], [ 'baz' ] ] + */ + private function breakTokensIntoChain( required array tokens ) { + + var commandsToResolve = [[]]; + var expandedCommandsToResolve = []; + + // If this command has a pipe, we need to chain multiple commands + var i = 0; + for( var token in tokens ){ + i++; + // We've reached a pipe and there is at least one command resolved already and there are more tokens left + if( token == '|' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ '|' ] ); + commandsToResolve.append( [] ); + } else if( token == ';' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ ';' ] ); + commandsToResolve.append( [] ); + } else if( token == '&&' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ '&&' ] ); + commandsToResolve.append( [] ); + } else if( token == '||' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ '||' ] ); + commandsToResolve.append( [] ); + } else if( token == '>' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ '|' ] ); + commandsToResolve.append( [ 'fileWrite' ] ); + } else if( token == '>>' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ + // Add a new command + commandsToResolve.append( [ '|' ] ); + commandsToResolve.append( [ 'fileAppend' ] ); + } else if( !listFindNoCase( '|,;,>,>>,&&', token ) ) { + //Append this token to the last command + commandsToResolve[ commandsToResolve.len() ].append( token ); + } + } + + // Expand aliases + for( commandTokens in commandsToResolve ) { + var originalLine = commandTokens.toList( ' ' ); + var aliases = configService.getSetting( 'command.aliases', {} ); + var matchingAlias = ''; + + for( alias in aliases ) { + if( lcase( originalLine ).startsWith( lcase( alias ) ) ) { + matchingAlias = alias; + break; + } + } + + // If the exact tokens in this command match an alias, swap it out. + if( matchingAlias.len() ) { + expandedCommandsToResolve.append( + // Recursivley dig down. This allows aliases to alias other alises + breakTokensIntoChain( + // Re-tokenize the new strin + parser.tokenizeInput( + // Expand the alias with the string it aliases + replaceNoCase( originalLine, matchingAlias, aliases[ matchingAlias ], 'once' ) + ) + ), + true ); + // Otherwise just use them as is. + } else { + expandedCommandsToResolve.append( commandTokens ); + } + + } + + return expandedCommandsToResolve; + } /** * Takes a struct of command data and lazy loads the actual CFC isntance if neccessary From 34e890caa003271ee8e5ccc3e9d3672efaf973ad Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 15 Jun 2017 17:41:37 -0500 Subject: [PATCH 090/123] Fix for dir command globbing --- src/cfml/system/modules_app/system-commands/commands/dir.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/system-commands/commands/dir.cfc b/src/cfml/system/modules_app/system-commands/commands/dir.cfc index 60622b30f..f3607217d 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -18,7 +18,7 @@ component aliases="ls,ll,directory" { * @directory.hint The directory to list the contents of or a file Globbing path to filter on * @recurse.hint Include nested files and folders **/ - function run( Globber directory=globber( getCWD() ), Boolean recurse=false ) { + function run( Globber directory=globber( ( getCWD().endsWith( '/' ) || getCWD().endsWith( '\' ) ? getCWD() : getCWD() & '/' ) ), Boolean recurse=false ) { // If the user gives us an existing directory foo, change it to the // glob pattern foo/* or foo/** if doing a recursive listing. From 519f41f5605da2c5a1fd4f8813c63086216d3339 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 17 Jun 2017 01:13:07 -0500 Subject: [PATCH 091/123] COMMANDBOX-642 --- build/build.properties | 2 +- src/cfml/system/services/ServerService.cfc | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 49655d22b..d120a4ec7 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.4.9 +cfml.loader.version=1.5.0 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 6156aba3f..c416ae75e 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -121,6 +121,7 @@ component accessors="true" singleton { 'trayicon' : d.trayicon ?: '', // Duplicate so onServerStart interceptors don't actually change config settings via refernce. 'trayOptions' : duplicate( d.trayOptions ?: [] ), + 'trayEnable' : d.trayEnable ?: true, 'jvm' : { 'heapSize' : d.jvm.heapSize ?: 512, 'minHeapSize' : d.jvm.minHeapSize ?: 0, @@ -527,6 +528,10 @@ component accessors="true" singleton { serverInfo.basicAuthEnable = serverJSON.web.basicAuth.enable ?: defaults.web.basicAuth.enable; serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; + + serverInfo.trayEnable = serverJSON.trayEnable ?: defaults.trayEnable; + + // Clean up spaces in welcome file list serverInfo.welcomeFiles = serverInfo.welcomeFiles.listMap( function( i ){ return trim( i ); } ); @@ -839,6 +844,7 @@ component accessors="true" singleton { .append( '--server-name' ).append( serverInfo.name ) .append( '--tray-icon' ).append( serverInfo.trayIcon ) .append( '--tray-config' ).append( trayOptionsPath ) + .append( '--tray-enable' ).append( serverInfo.trayEnable ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); @@ -1625,6 +1631,7 @@ component accessors="true" singleton { 'aliases' : {}, 'errorPages' : {}, 'trayOptions' : {}, + 'trayEnable' : true, 'dateLastStarted' : '', 'openBrowser' : true, 'openBrowserURL' : '' From 474407e0e5974f08558be70993352ec0be7d2c39 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 17 Jun 2017 01:38:36 -0500 Subject: [PATCH 092/123] COMMANDBOX-648 --- src/cfml/system/services/ServerService.cfc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index c416ae75e..71d537795 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -847,6 +847,7 @@ component accessors="true" singleton { .append( '--tray-enable' ).append( serverInfo.trayEnable ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) + .append( '--proxy-peeraddress' ).append( 'true' ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. From 3b573103efd2aed0dd530b06bf4e90336bc78e1e Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 17 Jun 2017 02:13:43 -0500 Subject: [PATCH 093/123] COMMANDBOX-649 --- src/cfml/system/config/urlrewrite.xml | 1 + src/cfml/system/services/ServerService.cfc | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/config/urlrewrite.xml b/src/cfml/system/config/urlrewrite.xml index 42380274c..6a4692d47 100644 --- a/src/cfml/system/config/urlrewrite.xml +++ b/src/cfml/system/config/urlrewrite.xml @@ -5,6 +5,7 @@ Generic Front-Controller URLs /(flex2gateway|flashservices/gateway|messagebroker|lucee|rest|cfide|CFIDE|cfformgateway|jrunscripts)/.* + /tuckey-status /.*\.cf(m|ml)/.* diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 71d537795..306313125 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -150,7 +150,9 @@ component accessors="true" singleton { }, 'rewrites' : { 'enable' : d.web.rewrites.enable ?: false, - 'config' : d.web.rewrites.config ?: variables.rewritesDefaultConfig + 'config' : d.web.rewrites.config ?: variables.rewritesDefaultConfig, + 'statusPath' : d.web.rewrites.statusPath ?: '', + 'configReloadSeconds' : d.web.rewrites.configReloadSeconds ?: '' }, 'basicAuth' : { 'enable' : d.web.basicAuth.enable ?: true, @@ -525,6 +527,8 @@ component accessors="true" singleton { serverInfo.SSLKeyFile = serverProps.SSLKeyFile ?: serverJSON.web.SSL.keyFile ?: defaults.web.SSL.keyFile; serverInfo.SSLKeyPass = serverProps.SSLKeyPass ?: serverJSON.web.SSL.keyPass ?: defaults.web.SSL.keyPass; serverInfo.rewritesEnable = serverProps.rewritesEnable ?: serverJSON.web.rewrites.enable ?: defaults.web.rewrites.enable; + serverInfo.rewritesStatusPath = serverJSON.web.rewrites.statusPath ?: defaults.web.rewrites.statusPath; + serverInfo.rewritesConfigReloadSeconds = serverJSON.web.rewrites.configReloadSeconds ?: defaults.web.rewrites.configReloadSeconds; serverInfo.basicAuthEnable = serverJSON.web.basicAuth.enable ?: defaults.web.basicAuth.enable; serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; @@ -847,7 +851,7 @@ component accessors="true" singleton { .append( '--tray-enable' ).append( serverInfo.trayEnable ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) - .append( '--proxy-peeraddress' ).append( 'true' ) + .append( '--proxy-peeraddress' ).append( 'true' ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. @@ -929,6 +933,13 @@ component accessors="true" singleton { // Incorporate rewrites to command args.append( '--urlrewrite-enable' ).append( serverInfo.rewritesEnable ); + if( len( serverInfo.rewritesStatusPath ) ) { + args.append( '--urlrewrite-statuspath' ).append( serverInfo.rewritesStatusPath ); + } + // A setting of 0 reloads on every request + if( len( serverInfo.rewritesConfigReloadSeconds ) ) { + args.append( '--urlrewrite-check' ).append( serverInfo.rewritesConfigReloadSeconds ); + } // Basic auth if( serverInfo.basicAuthEnable && serverInfo.basicAuthUsers.count() ) { From c02126f9ca8cf160185840a07b22b77852b996da Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 17 Jun 2017 19:23:33 -0500 Subject: [PATCH 094/123] Bump for new Runwar version --- build/build.properties | 2 +- src/cfml/system/services/ServerService.cfc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/build.properties b/build/build.properties index d120a4ec7..593c53284 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.5.0 +cfml.loader.version=1.5.1 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 306313125..a3a029463 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -863,7 +863,7 @@ component accessors="true" singleton { } if( serverInfo.trace ) { - args.append( '--log-level' ).append( 'trace' ); + args.append( '--log-level' ).append( 'TRACE' ); } if( len( errorPages ) ) { @@ -1008,9 +1008,9 @@ component accessors="true" singleton { var line = bufferedReader.readLine(); while( !isNull( line ) ){ // Clean log4j cruft from line - line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger processoutput: ', '' ); + line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger - processoutput: ', '' ); line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger lib: ', 'Runwar: ' ); - line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger ', 'Runwar: ' ); + line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger - ', 'Runwar: ' ); // Build up our output startOutput.append( line & chr( 13 ) & chr( 10 ) ); From bd6a780d9ab86574a93bb42711ed542d8094aa71 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 20 Jun 2017 12:50:45 -0500 Subject: [PATCH 095/123] Some preliminary menu enhancements. Not ready yet --- src/cfml/system/services/ServerService.cfc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index a3a029463..3ce038c5a 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -704,6 +704,8 @@ component accessors="true" singleton { // The process native name var processName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ) & ' [' & listFirst( serverinfo.cfengine, '@' ) & ' ' & installDetails.version & ']'; + var displayServerName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ); + var displayEngineName = listFirst( serverinfo.cfengine, '@' ) & ' ' & installDetails.version; // This is a WAR } else { @@ -760,6 +762,16 @@ component accessors="true" singleton { // Set default options for all servers // TODO: Don't overwrite existing options with the same label. + /* serverInfo.trayOptions.prepend( + { + "label":"Advanced", + "items": [ + { "label" : "Browse File System", "hotkey" : "B", "action" : "openfilesystem", "path" : "", "image" : expandPath('/commandbox/system/config/server-icons/info.png' ) }, + { "label" : displayEngineName, "disabled" : true, 'checkbox': true, "image" : expandPath('/commandbox/system/config/server-icons/info.png' ) }, + { "label" : "PID: ${runwar.PID}", "disabled" : true, 'checkbox': true, "image" : expandPath('/commandbox/system/config/server-icons/info.png' ) } + ] + } );*/ + if( CFEngineName contains "lucee" ) { serverInfo.trayOptions.prepend( { 'label':'Open Web Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/lucee/admin/web.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/web_settings.png' ) } ); serverInfo.trayOptions.prepend( { 'label':'Open Server Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/lucee/admin/server.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/server_settings.png' ) } ); @@ -771,8 +783,10 @@ component accessors="true" singleton { } serverInfo.trayOptions.prepend( { 'label':'Open Browser', 'action':'openbrowser', 'url': serverInfo.openbrowserURL, 'image' : expandPath('/commandbox/system/config/server-icons/home.png' ) } ); + /* serverInfo.trayOptions.prepend( { 'label' : 'Restart Server', 'hotkey':'R', 'action' : 'restartserver', 'image': expandPath('/commandbox/system/config/server-icons/home.png' ) } ); + */ serverInfo.trayOptions.prepend( { 'label':'Stop Server', 'action':'stopserver', 'image' : expandPath('/commandbox/system/config/server-icons/stop.png' ) } ); - serverInfo.trayOptions.prepend( { 'label': processName, 'disabled':true, 'image' : expandPath('/commandbox/system/config/server-icons/info.png' ) } ); + //serverInfo.trayOptions.prepend( { 'label': displayServerName, 'disabled':true, 'image' : expandPath('/commandbox/system/config/server-icons/info.png' ) } ); // This is due to a bug in RunWar not creating the right directory for the logs directoryCreate( serverInfo.logDir, true, true ); @@ -805,6 +819,7 @@ component accessors="true" singleton { // Serialize tray options and write to temp file var trayOptionsPath = serverinfo.customServerFolder & '/trayOptions.json'; var trayJSON = { + //'title' : displayServerName, 'title' : processName, 'tooltip' : processName, 'items' : serverInfo.trayOptions From 051487cbc5ce4fd5db5793f05702849b0238f8d4 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 23 Jun 2017 23:00:50 -0500 Subject: [PATCH 096/123] COMMANDBOX-650 --- src/cfml/system/config/CommandBoxDSL.cfc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/config/CommandBoxDSL.cfc b/src/cfml/system/config/CommandBoxDSL.cfc index a0786c3fa..f82378e27 100644 --- a/src/cfml/system/config/CommandBoxDSL.cfc +++ b/src/cfml/system/config/CommandBoxDSL.cfc @@ -77,10 +77,12 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ } } case "ConfigSettings" : { - var configSettings = getInjector().getInstance( 'ConfigService' ).getConfigSettings();; + var configService = getInjector().getInstance( 'ConfigService' ); + var configSettings = configService.getConfigSettings(); + // Check for setting existance - if( structKeyExists(configSettings, thisLocationKey ) ){ - return configSettings[ thisLocationKey ]; + if( configService.settingExists( thisLocationKey ) ){ + return configService.getSetting( thisLocationKey ); } else if( getLog().canDebug() ){ getLog().debug("The config setting requested: #thisLocationKey# does not exist in the loaded settings. Loaded settings are #structKeyList(configSettings)#"); } From 725b234265c279a2364bbac9962ee20cd1460973 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 27 Jun 2017 16:36:42 -0400 Subject: [PATCH 097/123] fix defaults for TestBox config --- src/cfml/system/config/box.json.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/config/box.json.txt b/src/cfml/system/config/box.json.txt index eb86324e5..66c765ea7 100644 --- a/src/cfml/system/config/box.json.txt +++ b/src/cfml/system/config/box.json.txt @@ -39,9 +39,9 @@ ], "labels" : "", "reporter" : "", - "bundles" : "test.specs", + "bundles" : "", "recurse" : true, - "directory" : "", + "directory" : "tests.specs", "testBundles" : "", "testSuites" : "", "testSpecs" : "", From 34023f17a2a00d68d3c0afdf6657f87172cc11f6 Mon Sep 17 00:00:00 2001 From: Mark Skelton Date: Tue, 27 Jun 2017 20:14:45 -0500 Subject: [PATCH 098/123] Added Utils module and remove trailing spaces command (#122) --- .../utils-commands/ModuleConfig.cfc | 11 ++ .../commands/utils/remove-trailing-spaces.cfc | 142 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc create mode 100644 src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc diff --git a/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc new file mode 100644 index 000000000..9ca442169 --- /dev/null +++ b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc @@ -0,0 +1,11 @@ +/** +********************************************************************************* +* Copyright Since 2017 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Mark Skelton +* @description Module Configuration for config module +*/ +component { + function configure(){} +} diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc new file mode 100644 index 000000000..d22dfee39 --- /dev/null +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -0,0 +1,142 @@ +/** + * Removes the trailing spaces from a file + * . + * {code:bash} + * utils remove-trailing-spaces /home/contentbox/index.cfm + * {code} + * . + * Removes the trailing spaces from a directory + * . + * {code:bash} + * utils remove-trailing-spaces /home/contentbox + * {code} +**/ +component aliases="rts" { + /** + * @path The file or directory path of a file to remove trailing spaces from + **/ + function run( path="" ){ + variables.excludeExtensions = getExcludeExtensions(); + + if ( arguments.path == "" ) { + print.line( "Please provide a file or folder path" ); + return; + } + + // try adding the file to the current working directory if the file doesn't exist + if ( fileExists( arguments.path ) ){ + // file exists + } else if ( fileExists( getCWD() & "/" & arguments.path ) ){ + arguments.path = getCWD() & "/" & arguments.path; + } else if ( fileExists( expandPath( arguments.path ) ) ){ + // try expanding the path + arguments.path = expandPath( arguments.path ); + } else { + if ( directoryExists( arguments.path ) ){ + // directory exists + } else if ( directoryExists( getCWD() & "/" & arguments.path ) ){ + // try adding the directory to the current working directory if the directory doesn't exist + arguments.path = getCWD() & "/" & arguments.path; + } else if ( directoryExists( expandPath( arguments.path ) ) ){ + // try expanding the path + arguments.path = expandPath( arguments.path ); + } else { + print.line( arguments.path & " is not a valid file or directory" ); + return; + } + + print.line( "Removing trailing spaces from " & arguments.path & "..." ); + + variables.excludeFolders = getExcludeFolders(); + var fileList = directoryList( arguments.path, true, "path" ); + + for ( var i in fileList ){ + var fileInfo = getFileInfo( i ); + // only process files + if ( fileInfo.type == "file" && + !isExcludedDirectory( i ) && + !variables.excludeExtensions.contains( listLast( i, "." ) ) ){ + removeTrailingSpaces( i ); + } + } + + return; + } + + print.line( "Removing trailing spaces from " & arguments.path & "..." ); + removeTrailingSpaces( arguments.path ); + } + + private function removeTrailingSpaces( filePath ){ + // trim trailing spaces and get line endings + var trimLinesResult = fileTrimLines( arguments.filePath ); + + // write new file + fileWrite( arguments.filePath, arrayToList( trimLinesResult.lines, trimLinesResult.lineEndings ) ); + } + + private function fileTrimLines( filePath ){ + var lines = []; + var lineEndings = ""; + + cfloop( file=filePath, index="line" ){ + // get the file line endings + if ( lineEndings == "" ){ + lineEndings = getLineEndings( line ); + } + // trim the trailing spaces + lines.append( rTrim( line ) ); + } + + return { lines: lines, lineEndings: lineEndings }; + } + + private function getLineEndings( data ){ + if ( arguments.data.len() > 0 ){ + if ( arguments.data[1].find( chr( 13 ) & chr( 10 ) ) != 0 ){ + return chr( 13 ) & chr( 10 ); + } else if ( arguments.data[1].find( chr( 13 ) ) != 0 ){ + return chr( 13 ); + } + } + + return chr( 10 ); + } + + private function isExcludedDirectory( file ){ + // convert all backslashes to forward-slashes + var f = arguments.file.replace( "\", "/" ); + + for ( var i in variables.excludeFolders ){ + // check if file exists in the exclude directory + if ( f.find( "/" & i & "/" ) || f.startsWith( i )){ + return true; + } + } + // file isn't in any of the exclude directories + return false; + } + + private function getExcludeFolders(){ + return [ '.git' ]; + } + + private function getExcludeExtensions(){ + return [ + '.eot', + '.gif', + '.ico', + '.jar', + '.jpeg', + '.jpg', + '.otf', + '.pdf', + '.png', + '.svg', + '.ttf', + '.woff', + '.woff2', + '.zip', + ]; + } +} From 4b0b81ae559e428b56ee9840427873644f970120 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 02:34:25 -0500 Subject: [PATCH 099/123] COMMANDBOX-651 --- src/cfml/system/services/InterceptorService.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/services/InterceptorService.cfc b/src/cfml/system/services/InterceptorService.cfc index b9a446f9e..a1a51cdd3 100644 --- a/src/cfml/system/services/InterceptorService.cfc +++ b/src/cfml/system/services/InterceptorService.cfc @@ -177,7 +177,7 @@ component accessors=true singleton { * Unregister an interceptor from an interception state or all states. If the state does not exists, it returns false */ function unregister( required string name, state='' ) { - return getEventPoolManager().unregister( arguemnts.name, arguments.state ); + return getEventPoolManager().unregister( arguments.name, arguments.state ); } } \ No newline at end of file From 0a71538ec144f9353ae88065e8f9aa157fbb4906 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 03:03:58 -0500 Subject: [PATCH 100/123] COMMANDBOX-647 --- src/cfml/system/services/CommandService.cfc | 29 +++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 7d6c047ba..8f9663866 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -275,6 +275,7 @@ component accessors="true" singleton { // Evaluate parameter expressions and system settings evaluateExpressions( parameterInfo ); evaluateSystemSettings( parameterInfo ); + combineColonParams( parameterInfo ); // Create globbing patterns createGlobs( parameterInfo, commandParams ); @@ -460,8 +461,32 @@ component accessors="true" singleton { } } } - - + + /** + * Look through named parameters and combine any ones with a colon based on matching prefixes. + */ + function combineColonParams( required struct parameters ) { + // Check each param + for( var key in parameters.namedParameters.keyArray() ) { + // If the name contains a colon, then break it out into a struct + if( key contains ':' ) { + // Default struct name for :foo=bar + if( key.listLen( ':' ) > 1 ) { + var prefix = key.listFirst( ':' ); + var nestedKey = key.listRest( ':' ); + } else { + var prefix = 'args'; + var nestedKey = mid( key, 2, len( key ) ); + } + // Default to empty struct if this is the first param with this prefix + parameters.namedParameters[ prefix ] = parameters.namedParameters[ prefix ] ?: {}; + // Set the part after the colon as the key in the new struct. + parameters.namedParameters[ prefix ][ nestedKey ] = parameters.namedParameters[ key ]; + // Remove original param + parameters.namedParameters.delete( key ); + } + } + } /** * Take an array of parameters and parse them out as named or positional From 0808d605e0d715323f26cff2078113a751ae7c7a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 04:33:46 -0500 Subject: [PATCH 101/123] COMMANDBOX-51 --- .../task-commands/commands/task/run.cfc | 21 +++- .../task-commands/models/TaskService.cfc | 100 ++++++++++++++++++ src/cfml/system/util/FileSystem.cfc | 33 +++++- 3 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/cfml/system/modules_app/task-commands/models/TaskService.cfc diff --git a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc index 943f3624e..c132ca220 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -2,9 +2,26 @@ * Run a task **/ component { + property name='taskService' inject='taskService@task-commands'; - function run( ) { - print.line( "Command not implemented!" ); + /** + * @taskFile Path to the Task CFC that you want to run + * @target Method in Task CFC to run + */ + function run( + string taskFile='task.cfc', + string target='run' + ) { + arguments.taskFile = fileSystemUtil.resolvePath( arguments.taskFile ); + var taskArgs = {}; + if( arguments.keyExists( 'args' ) && isStruct( arguments.args ) ) { + taskArgs = arguments.args; + } else if( arguments.count() > 1 ) { + taskArgs = duplicate( arguments ); + taskArgs.delete( 'taskFile' ); + taskArgs.delete( 'target' ); + } + taskService.runTask( taskFile, target, taskArgs ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc new file mode 100644 index 000000000..ac1ad201d --- /dev/null +++ b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc @@ -0,0 +1,100 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood, Luis Majano, Denny Valliant +* +* I handle running tasks +*/ +component singleton accessors=true { + + // DI Properties + property name='FileSystemUtil' inject='FileSystem'; + property name='logger' inject='logbox:logger:{this}'; + property name='cr' inject='cr@constants'; + property name='wirebox' inject='wirebox'; + property name='shell' inject='Shell'; + property name='consoleLogger' inject='logbox:logger:console'; + + function onDIComplete() { + // Check if base task class mapped? + if( NOT wirebox.getBinder().mappingExists( 'commandbox.system.BaseTask' ) ){ + // feed the base class + wirebox.registerNewInstance( name='commandbox.system.BaseTask', instancePath='commandbox.system.BaseTask' ) + .setAutowire( false ); + } + } + + /** + * Runs a task + * + * @taskFile Path to the Task CFC that you want to run + * @target Method in Task CFC to run + * @taskArgs Struct of arguments to pass on to the task + */ + function runTask( required string taskFile, required string target='run', taskArgs={} ) { + + // This is neccessary so changes to tasks get picked up right away. + pagePoolClear(); + + if( right( taskFile, 4 ) != '.cfc' ) { + taskFile &= '.cfc'; + } + if( !fileExists( taskFile ) ) { + throw( message="Task CFC doesn't exist.", detail=arguments.taskFile, type="commandException"); + } + + var taskCFC = createTaskCFC( taskFile ); + // If target doesn't exist or isn't a UDF + if( !structKeyExists( taskCFC, target ) || !IsCustomFunction( taskCFC[ target ] ) ) { + throw( message="Target [#target#] doesn't exist in Task CFC.", detail=arguments.taskFile, type="commandException"); + } + // Run the task + taskCFC.reset(); + taskCFC[ target ]( argumentCollection = taskArgs ); + var result = taskCFC.getResult(); + + if( len( result ) ) { + shell.printString( result ); + // If the command output text that didn't end with a line break one, add one + var lastChar = mid( result, len( result ), 1 ); + if( ! ( lastChar == chr( 10 ) || lastChar == chr( 13 ) ) ) { + shell.getReader().println(); + } + shell.getReader().flush(); + } + } + + + function createTaskCFC( required string taskFile ) { + // Convert to use a mapping + var relTaskFile = FileSystemUtil.makePathRelative( taskFile ); + + // Strip .cfc back off + relTaskFile = mid( relTaskFile, 1, len( relTaskFile ) - 4 ); + relTaskFile = relTaskFile.listChangeDelims( '.', '/' ); + relTaskFile = relTaskFile.listChangeDelims( '.', '\' ); + + // Create this Task CFC + try { + + // Check if task mapped? + if( NOT wirebox.getBinder().mappingExists( "task-" & relTaskFile ) ){ + // feed this task to wirebox with virtual inheritance + wirebox.registerNewInstance( name="task-" & relTaskFile, instancePath=relTaskFile ) + .setVirtualInheritance( "commandbox.system.BaseTask" ); + } + // retrieve, build and wire from wirebox + return wireBox.getInstance( "task-" & relTaskFile ); + + // This will catch nasty parse errors so the shell can keep loading + } catch( any e ){ + // Log the full exception with stack trace + logger.error( 'Error creating Task [#relTaskFile#]. #e.message# #e.detail ?: ''#', e.stackTrace ); + throw( message='Error creating Task [#relTaskFile#]', detail="#e.message# #CR# #e.detail ?: ''# #CR# #e.stacktrace#", type="commandException"); + } + + } +} + diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 49c229415..17843c44b 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -208,10 +208,29 @@ component accessors="true" singleton { if( !isWindows() ) { return arguments.absolutePath; } - var driveLetter = listFirst( arguments.absolutePath, ':' ); - var path = listRest( arguments.absolutePath, ':' ); - var mapping = locateMapping( driveLetter ); - return mapping & path; + // If one of the folders has a period, we've got to do something special. + // C:/users/brad.development/foo.cfc turns into /C__users_brad_development/foo.cfc + if( getDirectoryFromPath( arguments.absolutePath ) contains '.' ) { + var mappingPath = getDirectoryFromPath( arguments.absolutePath ); + mappingPath = mappingPath.replace( '\', '/', 'all' ); + mappingPath = mappingPath.listChangeDelims( '/', '/' ); + + var mappingName = mappingPath.replace( ':', '_', 'all' ); + mappingName = mappingName.replace( '.', '_', 'all' ); + mappingName = mappingName.replace( '/', '_', 'all' ); + mappingName = '/' & mappingName; + + createMapping( mappingName, mappingPath ); + return mappingName & '/' & getFileFromPath( arguments.absolutePath ); + + // Otherwise, do the "normal" way that re-uses top level drive mappings + // C:/users/brad/foo.cfc turns into /C_Drive/users/brad/foo.cfc + } else { + var driveLetter = listFirst( arguments.absolutePath, ':' ); + var path = listRest( arguments.absolutePath, ':' ); + var mapping = locateMapping( driveLetter ); + return mapping & path; + } } /** @@ -221,12 +240,16 @@ component accessors="true" singleton { string function locateMapping( required string driveLetter ) { var mappingName = '/' & arguments.driveLetter & '_drive'; var mappingPath = arguments.driveLetter & ':/'; + createMapping( mappingName, mappingPath ); + return mappingName; + } + + function createMapping( mappingName, mappingPath ) { var mappings = getApplicationSettings().mappings; if( !structKeyExists( mappings, mappingName ) ) { mappings[ mappingName ] = mappingPath; application action='update' mappings='#mappings#'; } - return mappingName; } } \ No newline at end of file From 4a21c7d2d0ff3f3f46c5fe98b90cdf8550a20ff3 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 04:39:41 -0500 Subject: [PATCH 102/123] COMMANDBOX-51 Docs --- .../task-commands/commands/task/run.cfc | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc index c132ca220..f814b7a07 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -1,5 +1,24 @@ /** - * Run a task + * Run a task. By default this will look for a file called "task.cfc" in the current directory and invoke it's run() method. + * + * {code} + * task run + * {code} + * + * Override the file name and/or method name with the taskFile and target parameters. The .cfc is optional. + * + * {code} + * task run build.cfc createZips + * {code} + * + * To pass parameters to your task, include additional positional parameters or named parameters starting with a colon (:). + * Theses parameters will appear directly in the arguments scope of the task. + * + * {code} + * task run build.cfc createZips value1 value2 + * task run :param1=value1 :param2=value2 + * {code} + * **/ component { property name='taskService' inject='taskService@task-commands'; From 13a6a98d135f75bcd12fa9f8711ea9345114c475 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 17:55:20 -0500 Subject: [PATCH 103/123] CommandBox-51 --- .../task-commands/commands/task/run.cfc | 16 +++++++++++++++- .../task-commands/models/TaskService.cfc | 17 ++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc index f814b7a07..21ba49957 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -31,16 +31,30 @@ component { string taskFile='task.cfc', string target='run' ) { + arguments.taskFile = fileSystemUtil.resolvePath( arguments.taskFile ); var taskArgs = {}; + + // Named task args will come through in a struct called args + // task run :param=value :param2=value2 if( arguments.keyExists( 'args' ) && isStruct( arguments.args ) ) { taskArgs = arguments.args; + + // Positional task args will come through direclty in the arguments scope + // task run task.cfc run value value2 } else if( arguments.count() > 1 ) { + // Make a copy of the arguments scope taskArgs = duplicate( arguments ); + // And pull out the two args that were meant for this command taskArgs.delete( 'taskFile' ); taskArgs.delete( 'target' ); } - taskService.runTask( taskFile, target, taskArgs ); + + // Run the task! + // We're printing the output here so we can capture it and pipe or redirect the output from "task run" + print.text( + taskService.runTask( taskFile, target, taskArgs ) + ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc index ac1ad201d..aa67e4ea7 100644 --- a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc +++ b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc @@ -32,8 +32,10 @@ component singleton accessors=true { * @taskFile Path to the Task CFC that you want to run * @target Method in Task CFC to run * @taskArgs Struct of arguments to pass on to the task + * + * @returns The output of the task. It's up to the caller to output it. */ - function runTask( required string taskFile, required string target='run', taskArgs={} ) { + string function runTask( required string taskFile, required string target='run', taskArgs={} ) { // This is neccessary so changes to tasks get picked up right away. pagePoolClear(); @@ -53,17 +55,10 @@ component singleton accessors=true { // Run the task taskCFC.reset(); taskCFC[ target ]( argumentCollection = taskArgs ); - var result = taskCFC.getResult(); - if( len( result ) ) { - shell.printString( result ); - // If the command output text that didn't end with a line break one, add one - var lastChar = mid( result, len( result ), 1 ); - if( ! ( lastChar == chr( 10 ) || lastChar == chr( 13 ) ) ) { - shell.getReader().println(); - } - shell.getReader().flush(); - } + // Return any output. It's up to the caller to output it. + return taskCFC.getResult(); + } From 13b2697254dbe7793e759c1d643594ebbe89299d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 28 Jun 2017 18:01:42 -0500 Subject: [PATCH 104/123] Commandbox-51 --- .../modules_app/task-commands/models/TaskService.cfc | 12 +++++++++--- src/cfml/system/util/FileSystem.cfc | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc index aa67e4ea7..5c222870b 100644 --- a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc +++ b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc @@ -39,24 +39,30 @@ component singleton accessors=true { // This is neccessary so changes to tasks get picked up right away. pagePoolClear(); - + + // We need the .cfc extension for the file exists check to work. if( right( taskFile, 4 ) != '.cfc' ) { taskFile &= '.cfc'; } + if( !fileExists( taskFile ) ) { throw( message="Task CFC doesn't exist.", detail=arguments.taskFile, type="commandException"); } + // Create an instance of the taskCFC. To prevent caching of the actual code in the task, we're treating them as + // transients. Since is since the code is likely to change while devs are building and testing them. var taskCFC = createTaskCFC( taskFile ); + // If target doesn't exist or isn't a UDF if( !structKeyExists( taskCFC, target ) || !IsCustomFunction( taskCFC[ target ] ) ) { throw( message="Target [#target#] doesn't exist in Task CFC.", detail=arguments.taskFile, type="commandException"); } + // Run the task - taskCFC.reset(); taskCFC[ target ]( argumentCollection = taskArgs ); // Return any output. It's up to the caller to output it. + // This is so task output can be correctly captured and piped or redirected to a file. return taskCFC.getResult(); } @@ -83,7 +89,7 @@ component singleton accessors=true { // retrieve, build and wire from wirebox return wireBox.getInstance( "task-" & relTaskFile ); - // This will catch nasty parse errors so the shell can keep loading + // This will catch nasty parse errors and tell us where they happened } catch( any e ){ // Log the full exception with stack trace logger.error( 'Error creating Task [#relTaskFile#]. #e.message# #e.detail ?: ''#', e.stackTrace ); diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 17843c44b..43b6bd561 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -205,7 +205,8 @@ component accessors="true" singleton { * Does NOT apply any canonicalization */ string function makePathRelative( required string absolutePath ) { - if( !isWindows() ) { + if( !isWindows() ) { + // TODO: Unix paths with a period in a folder name are likely still a problem. return arguments.absolutePath; } // If one of the folders has a period, we've got to do something special. From 81ae7f5ca2b2f3d8b43204a2fba1be4c002d8383 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 30 Jun 2017 16:23:15 -0500 Subject: [PATCH 105/123] Bump for newest runwar snapshot --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 593c53284..7b335f498 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.5.1 +cfml.loader.version=1.5.2 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 From 4105c02118368caa68513721f2d558becc4608d2 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 30 Jun 2017 18:44:20 -0500 Subject: [PATCH 106/123] Fix for Runwar debugging always being on. --- src/cfml/system/services/ServerService.cfc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 3ce038c5a..bc12df314 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -854,7 +854,6 @@ component accessors="true" singleton { .append( '--background=#background#' ) .append( '--port' ).append( serverInfo.port ) .append( '--host' ).append( serverInfo.host ) - .append( '--debug' ).append( serverInfo.debug ) .append( '--stop-port' ).append( serverInfo.stopsocket ) .append( '--processname' ).append( processName ) .append( '--log-dir' ).append( serverInfo.logDir ) @@ -869,6 +868,11 @@ component accessors="true" singleton { .append( '--proxy-peeraddress' ).append( 'true' ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); + if( serverInfo.debug ) { + // Debug is getting turned on any time I include the --debug flag regardless of whether it's true or false. + args.append( '--debug' ).append( serverInfo.debug ); + } + // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. if( len( serverInfo.restMappings ) ) { args.append( '--servlet-rest-mappings' ).append( serverInfo.restMappings ); From 2c7766d53818b229cf997f7412786193c27d5de4 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 1 Jul 2017 00:48:47 -0500 Subject: [PATCH 107/123] Bump again for new Runwar snapshot --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 7b335f498..0202b7baf 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.5.2 +cfml.loader.version=1.5.3 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 From d3adf9080e188051827048da02bb84cb8edf233b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 1 Jul 2017 12:04:06 -0500 Subject: [PATCH 108/123] Work around for Lucee instantiating class --- src/cfml/system/services/ServerService.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index bc12df314..207eca359 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -87,7 +87,7 @@ component accessors="true" singleton { // The JRE executable command variables.javaCommand = arguments.fileSystem.getJREExecutable(); // The runwar jar path - variables.jarPath = java.File.init( java.launchUtil.class.getProtectionDomain().getCodeSource() + variables.jarPath = java.File.init( java.launchUtil.getClass().getProtectionDomain().getCodeSource() .getLocation().toURI().getSchemeSpecificPart() ).getAbsolutePath(); // Init server config if not found From 1f5324ab7169364702164370f97041ad46307362 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 1 Jul 2017 12:22:27 -0500 Subject: [PATCH 109/123] Bump for release candidate build --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 8d4236b60..c04ac0851 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From 58792b8accf3cd7f9aee64f5f395e71eada2e31f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 1 Jul 2017 20:14:43 -0500 Subject: [PATCH 110/123] Wrong semver injection --- src/cfml/system/endpoints/File.cfc | 2 +- src/cfml/system/endpoints/Folder.cfc | 2 +- src/cfml/system/endpoints/ForgeBox.cfc | 2 +- .../modules/semver/models/SemanticVersion.cfc | 7 +- .../commands/forgebox/search.cfc | 2 +- .../commands/forgebox/show.cfc | 2 +- .../commands/package/outdated.cfc | 2 +- .../commands/package/update.cfc | 2 +- src/cfml/system/services/ArtifactService.cfc | 2 +- .../system/services/ServerEngineService.cfc | 2 +- src/cfml/system/util/SemanticVersion.cfc | 609 ------------------ 11 files changed, 15 insertions(+), 619 deletions(-) delete mode 100644 src/cfml/system/util/SemanticVersion.cfc diff --git a/src/cfml/system/endpoints/File.cfc b/src/cfml/system/endpoints/File.cfc index 3e5b1edf9..40b24926a 100644 --- a/src/cfml/system/endpoints/File.cfc +++ b/src/cfml/system/endpoints/File.cfc @@ -15,7 +15,7 @@ component accessors="true" implements="IEndpoint" singleton { property name="packageService" inject="packageService"; property name="fileSystemUtil" inject="FileSystem"; property name="folderEndpoint" inject="commandbox.system.endpoints.Folder"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; // Properties property name="namePrefixes" type="string"; diff --git a/src/cfml/system/endpoints/Folder.cfc b/src/cfml/system/endpoints/Folder.cfc index 78eb5a89f..bb49cafa7 100644 --- a/src/cfml/system/endpoints/Folder.cfc +++ b/src/cfml/system/endpoints/Folder.cfc @@ -11,7 +11,7 @@ component accessors="true" implements="IEndpoint" singleton { // DI property name="packageService" inject="packageService"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; // Properties property name="namePrefixes" type="string"; diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 91dc0c1ea..b91a19bbe 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -14,7 +14,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { property name="consoleLogger" inject="logbox:logger:console"; property name="forgeBox" inject="ForgeBox"; property name="tempDir" inject="tempDir@constants"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; property name="artifactService" inject="ArtifactService"; property name="packageService" inject="packageService"; property name="configService" inject="configService"; diff --git a/src/cfml/system/modules/semver/models/SemanticVersion.cfc b/src/cfml/system/modules/semver/models/SemanticVersion.cfc index aaf6778d0..37d12e099 100644 --- a/src/cfml/system/modules/semver/models/SemanticVersion.cfc +++ b/src/cfml/system/modules/semver/models/SemanticVersion.cfc @@ -59,6 +59,8 @@ component singleton{ Semantic version: major.minor.revision-alpha.1+build **/ +systemOutput( current & ' <==> ' & target , true); + var current = parseVersion( arguments.current ); var target = parseVersion( arguments.target ); @@ -84,12 +86,15 @@ component singleton{ if( !len( target.preReleaseID ) ) { target.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } if( !len( current.preReleaseID ) ) { current.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } +systemOutput( target.preReleaseID, true); +systemOutput( current.preReleaseID, true); +systemOutput( lcase( target.preReleaseID ) gt lcase( current.preReleaseID ), true); // pre-release Check if( target.major eq current.major AND target.minor eq current.minor AND target.revision eq current.revision AND // preReleaseID is either alphabetically higher, or target has no prereleaes id and current does. - target.preReleaseID gt current.preReleaseID ) { + lcase( target.preReleaseID ) gt lcase( current.preReleaseID ) ) { return true; } diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc index c518272f7..df23cfa4e 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc @@ -11,7 +11,7 @@ component { // DI property name="forgeBox" inject="ForgeBox"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; /** * @searchText.hint Text to search on diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc index 9c453fcee..75e3858c2 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc @@ -35,7 +35,7 @@ component aliases="show" { // DI property name="forgeBox" inject="ForgeBox"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; function onDIComplete() { variables.forgeboxOrders = forgebox.ORDER; diff --git a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc index 8128e43f0..b41a50049 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc @@ -24,7 +24,7 @@ component aliases="outdated" { // DI property name="packageService" inject="PackageService"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; /** * @verbose.hint Outputs additional information about each package diff --git a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc index fb7f35cbb..72ca4ebe3 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc @@ -32,7 +32,7 @@ component aliases="update" { // DI property name="packageService" inject="PackageService"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; property name='parser' inject='Parser'; /** diff --git a/src/cfml/system/services/ArtifactService.cfc b/src/cfml/system/services/ArtifactService.cfc index fbf940d5b..3e8e1008c 100644 --- a/src/cfml/system/services/ArtifactService.cfc +++ b/src/cfml/system/services/ArtifactService.cfc @@ -20,7 +20,7 @@ component accessors="true" singleton { property name='tempDir' inject='tempDir@constants'; property name='packageService' inject='PackageService'; property name='logger' inject='logbox:logger:{this}'; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; // COMMANDBOX-479 property name="configService" inject="ConfigService"; diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index 81ca30df6..c962cd076 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -17,7 +17,7 @@ component accessors="true" singleton="true" { property name='consoleLogger' inject='logbox:logger:console'; property name='cr' inject='cr@constants'; property name='shell' inject='shell'; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; property name="artifactService" inject="artifactService"; diff --git a/src/cfml/system/util/SemanticVersion.cfc b/src/cfml/system/util/SemanticVersion.cfc deleted file mode 100644 index 27f275c4a..000000000 --- a/src/cfml/system/util/SemanticVersion.cfc +++ /dev/null @@ -1,609 +0,0 @@ -/** -******************************************************************************** -Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp -www.coldbox.org | www.luismajano.com | www.ortussolutions.com -******************************************************************************** -* @author Luis Majano & Brad Wood -* Utility to parse and validate semantic versions -* Semantic version: major.minor.revision-preReleaseID+build -* http://semver.org/ -* https://github.com/npm/node-semver -*/ -component singleton{ - - /** - * Constructor - */ - function init(){ - return this; - } - - function getDefaultsVersion() { - return { major = 1, minor = 0, revision = 0, preReleaseID = "", buildID = 0 }; - } - - function compare( - required string current, - required string target, - boolean checkBuildID=true ) { - - // versions are identical - if( isEQ( arguments.current, arguments.target, checkBuildID ) ) { - return 0; - } - - // first is 'smaller' than the second - if( isNew( arguments.current, arguments.target, checkBuildID ) ) { - return -1; - // first is 'larger' than the second - } else { - return 1; - } - - } - - /** - * Checks if target version is a newer semantic version than the passed current version - * Note: To confirm to semvar, I think this needs to defer to gt(). - * @current The current version of the system - * @target The newer version received - * @checkBuildID If true it will check build equality, else it will ignore it - * - */ - boolean function isNew( - required string current, - required string target, - boolean checkBuildID=true - ){ - /** - Semantic version: major.minor.revision-alpha.1+build - **/ - - var current = parseVersion( arguments.current ); - var target = parseVersion( arguments.target ); - - // Major check - if( target.major gt current.major ){ - return true; - } - - // Minor Check - if( target.major eq current.major AND target.minor gt current.minor ){ - return true; - } - - // Revision Check - if( target.major eq current.major AND - target.minor eq current.minor AND - target.revision gt current.revision ){ - return true; - } - - // A little hacky, but less code than what I had. - // Basically, an empty pre release ID needs to sort AFTER a non-empty one. - if( !len( target.preReleaseID ) ) { target.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } - if( !len( current.preReleaseID ) ) { current.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } - - // pre-release Check - if( target.major eq current.major AND - target.minor eq current.minor AND - target.revision eq current.revision AND - // preReleaseID is either alphabetically higher, or target has no prereleaes id and current does. - target.preReleaseID gt current.preReleaseID ) { - return true; - } - - // BuildID verification is turned on? - if( !arguments.checkBuildID ){ return false; } - - // Build Check - if( target.major eq current.major AND - target.minor eq current.minor AND - target.revision eq current.revision AND - target.preReleaseID eq current.preReleaseID AND - target.buildID gt current.buildID ){ - return true; - } - - return false; - } - - /** - * Clean a version string from leading = or v - */ - string function clean( required version ){ - version = trim( version ); - return reReplaceNoCase( arguments.version, "^[=v]*", "" ); - } - - /** - * Decides whether a version satisfies a range - * - */ - boolean function satisfies( required string version, required string range ){ - - arguments.version = clean( arguments.version ); - - if( range == 'be' ) { - return true; - } - - if( range == 'stable' && !isPreRelease( version ) ) { - return true; - } else if( range == 'stable' ) { - return false; - } - - // An array of comparator sets. At least one of the comparator sets needs to - // satisfy. Each comparator of a given comparator set must match for the set to pass. - var semverRange = buildRange( range ); - - // Only one of our comparatorSets in the range need to match - for( var comparatorSet in semverRange ) { - // If the version we're inspecting is a pre-release, don't consider it unless at least one comparator in this - // set specifically mentions a pre release matching this major.minor.revision. - if( isPreRelease( arguments.version ) && !interestedInPreReleasesOfThisVersion( comparatorSet, arguments.version ) ) { - continue; - } - var setResult = false; - // Each comparator in the set much match - for( var comparator in comparatorSet ) { - setResult = evaluateComparator( comparator, arguments.version ); - // Short circuit if at least one comparator in this set has failed - if( !setResult ) { break; } - } - // If this comparatorSet passed, we've seen all we need to see - if( setResult ) { return true; } - } - - // If we made it here, none of the comparatorSets in our range matched - return false; - - - return isEQ( arguments.version, arguments.range, false ); - } - - private function evaluateComparator( required struct comparator, version ) { - switch( comparator.operator ) { - case "<": - return isNew( arguments.version, comparator.version, false ); - break; - case "<=": - return isNew( arguments.version, comparator.version, false ) || isEq( comparator.version, arguments.version, false ); - break; - case ">": - return isNew( comparator.version, arguments.version, false ); - break; - case ">=": - return isNew( comparator.version, arguments.version, false ) || isEq( comparator.version, arguments.version, false ); - break; - case "=": - return isEq( comparator.version, arguments.version, false ); - break; - default: - return false; - } - } - - private function interestedInPreReleasesOfThisVersion( required array comparatorSet, required string version ) { - var sVersion = parseVersion( arguments.version ); - // Look at each comparator - for( var comparator in arguments.comparatorSet ) { - // And see if there is a pre release version that matches major.minor.revision - if( isPreRelease( comparator.version ) - && comparator.sVersion.major == sVersion.major - && comparator.sVersion.minor == sVersion.minor - && comparator.sVersion.revision == sVersion.revision) { - return true; - } - } - return false; - } - - private function buildRange( required string range ) { - // A character that I hope will never be part of an actual range so split easier. - // Comprator sets inside a range are delimited by " || " - arguments.range = replaceNoCase( arguments.range, ' || ', '•', 'all' ); - var semverRange = listToArray( arguments.range, '•' ); - - // An empty range becomes * - if( !arrayLen( semverRange ) ) { - semverRange = [ '*' ]; - } - - // Loop over each comparator set and parse - semverRange = semverRange.map( function( i ) { - return buildComparatorSet( i ); - } ); - - return semverRange; - } - - private function buildComparatorSet( required string set ) { - var comparatorSet = []; - - // Check for a hyphen range - if( set contains ' - ' ) { - set = replaceNoCase( set, ' - ', '•', 'all' ); - var lowerBound = listFirst( set, '•' ); - var upperBound = listLast( set, '•' ); - - lowerBound = replaceNoCase( lowerBound, '*', 'x', 'all' ); - upperBound = replaceNoCase( upperBound, '*', 'x', 'all' ); - - sVersion = parseVersion( lowerBound, 'x' ); - - comparatorSet.append( - expandXRanges( { - operator : '>=', - sVersion : sVersion, - version : getVersionAsString( sVersion ) - } ), - true - ); - - sVersion = parseVersion( upperBound, 'x' ); - - comparatorSet.append( - expandXRanges( { - operator : '<=', - sVersion : sVersion, - version : getVersionAsString( sVersion ) - } ), - true - ); - - return comparatorSet; - } - - // Comparators are delimited by whitespace - for( var comparator in listToArray( set, ' ' ) ) { - - // standardize * to x - comparator = replaceNoCase( comparator, '*', 'x', 'all' ); - // >=1.2.3 - if( comparator.startsWith( '>=' ) ) { - var version = right( comparator, len( comparator )-2 ); - var operator = '>='; - // <=1.2.3 - } else if( comparator.startsWith( '<=' ) ) { - var version = right( comparator, len( comparator )-2 ); - var operator = '<='; - // >1.2.3 - } else if( comparator.startsWith( '>' ) ) { - var version = right( comparator, len( comparator )-1 ); - var operator = '>'; - // <1.2.3 - } else if( comparator.startsWith( '<' ) ) { - var version = right( comparator, len( comparator )-1 ); - var operator = '<'; - // =1.2.3 - } else if( comparator.startsWith( '=' ) ) { - var operator = '='; - var version = right( comparator, len( comparator )-1 ); - // ~1.2.3 - } else if( comparator.startsWith( '~' ) ) { - var operator = '~'; - var version = right( comparator, len( comparator )-1 ); - // ^1.2.3 - } else if( comparator.startsWith( '^' ) ) { - var operator = '^'; - var version = right( comparator, len( comparator )-1 ); - // 1.2.3 - } else { - var version = comparator; - var operator = '='; - } - - // Missing bits become x. So 1.3 becomes 1.3.x - sVersion = parseVersion( version, 'x' ); - comparatorSet.append( - // Convert 1.x into multiple comparators - expandXRanges( { - operator : operator, - sVersion : sVersion, - version : getVersionAsString( sVersion ) - } ), - true - ); - - } - - return comparatorSet; - } - - private function expandXRanges( required struct sComparator ) { - var comparatorSet = []; - - switch( sComparator.operator ) { - case "<": - // <1.1.x becomes <1.1.0 - // <1.x becomes <1.0.0 - - if( sComparator.sVersion.major == 'x' ) { sComparator.sVersion.major = '0'; } - if( sComparator.sVersion.minor == 'x' ) { sComparator.sVersion.minor = '0'; } - if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - break; - case "<=": - // <=1.x becomes <2.0.0 - if( sComparator.sVersion.minor == 'x' ) { - - sComparator.sVersion.minor = '0'; - sComparator.sVersion.revision = '0'; - sComparator.sVersion.major=val( sComparator.sVersion.major )+1; - sComparator.operator = '<'; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - // <=1.0.x becomes <1.1.0 - } else if( sComparator.sVersion.revision == 'x' ) { - - sComparator.sVersion.revision = '0'; - sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; - sComparator.operator = '<'; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - } - else { - comparatorSet.append( sComparator ); - } - break; - case ">": - // >1.x becomes >=2.0.0 - if( sComparator.sVersion.minor == 'x' ) { - - sComparator.sVersion.minor = '0'; - sComparator.sVersion.revision = '0'; - sComparator.sVersion.major=val( sComparator.sVersion.major )+1; - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - // >1.0.x becomes >=1.1.0 - } else if( sComparator.sVersion.revision == 'x' ) { - - sComparator.sVersion.revision = '0'; - sComparator.sVersion.minor=val(sComparator.sVersion.minor)+1; - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - } - else { - comparatorSet.append( sComparator ); - } - break; - case ">=": - // >=1.1.x becomes >=1.1.0 - // >=1.x becomes >=1.0.0 - - if( sComparator.sVersion.major == 'x' ) { sComparator.sVersion.major = '0'; } - if( sComparator.sVersion.minor == 'x' ) { sComparator.sVersion.minor = '0'; } - if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - break; - case "=": - // * becomes >=0.0.0 - if( sComparator.sVersion.major == 'x' ) { - - sComparator.sVersion.major = 0; - sComparator.sVersion.minor = 0; - sComparator.sVersion.revision = 0; - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - // 1.x becomes >=1.0.0 < 2.0.0 - } else if ( sComparator.sVersion.minor == 'x' ) { - - sComparator.sVersion.minor = 0; - sComparator.sVersion.revision = 0; - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( duplicate( sComparator ) ); - - sComparator.sVersion.major=val( sComparator.sVersion.major )+1; - sComparator.operator = '<'; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - - // 1.0.x becomes >=1.0.0 < 1.1.0 - } else if( sComparator.sVersion.revision == 'x' ) { - - sComparator.sVersion.revision = 0; - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( duplicate( sComparator ) ); - - sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; - sComparator.operator = '<'; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - } else { - comparatorSet.append( sComparator ); - } - break; - case "~": - // ~1.2 Same as 1.2.x - // ~1 Same as 1.x - // ~0.2 Same as 0.2.x - // ~0 Same as 0.x - if( sComparator.sVersion.minor== 'x' || sComparator.sVersion.revision== 'x' ) { - sComparator.operator = '='; - // Recursivley handle as an X range - comparatorSet.append( expandXRanges( sComparator ), true ); - } else { - - // ~0.2.3 becomes >=0.2.3 <0.3.0 - // ~1.2.3 becomes >=1.2.3 <1.3.0 - sComparator.operator = '>='; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( duplicate( sComparator ) ); - - sComparator.operator = '<'; - sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; - sComparator.sVersion.revision = 0; - sComparator.sVersion.preReleaseID = ''; - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - } - break; - case "^": - // ^1.2.3 becomes >=1.2.3 <2.0.0 - // ^0.2.3 becomes >=0.2.3 <0.3.0 - // ^0.0.3 becomes >=0.0.3 <0.0.4 - // ^1.2.3-beta.2 becomes >=1.2.3-beta.2 <2.0.0 - // ^1.2.x becomes >=1.2.0 <2.0.0 - // ^0.0.x becomes >=0.0.0 <0.1.0 - // ^0.0 becomes >=0.0.0 <0.1.0 - // ^1.x becomes >=1.0.0 <2.0.0 - // ^0.x becomes >=0.0.0 <1.0.0 - var sComparator2 = duplicate( sComparator ); - sComparator2.operator = '>='; - if( sComparator2.sVersion.major == 'x' ) { sComparator2.sVersion.major = '0'; } - if( sComparator2.sVersion.minor == 'x' ) { sComparator2.sVersion.minor = '0'; } - if( sComparator2.sVersion.revision == 'x' ) { sComparator2.sVersion.revision = '0'; } - sComparator2.version = getVersionAsString( sComparator2.sVersion ); - comparatorSet.append( sComparator2 ); - - sComparator.operator = '<'; - sComparator.sVersion.preReleaseID = ''; - if( sComparator.sVersion.major != 0 || sComparator.sVersion.minor == 'x' ) { - sComparator.sVersion.major=val( sComparator.sVersion.major )+1; - sComparator.sVersion.minor = 0; - sComparator.sVersion.revision = 0; - } else if( sComparator.sVersion.minor != 0 || sComparator.sVersion.revision == 'x' ) { - sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; - sComparator.sVersion.revision = 0; - } else { - sComparator.sVersion.revision=val( sComparator.sVersion.revision )+1; - } - - sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - break; - } - - return comparatorSet; - } - - /** - * Parse the semantic version. If no minor found, then 0. If not revision found, then 0. - * If not Bleeding Edge bit, then empty. If not buildID, then 0 - * @return struct:{major,minor,revision,preReleaseID,buildid} - */ - struct function parseVersion( required string version, missingValuePlaceholder ){ - arguments.version = clean( arguments.version ); - var results = getDefaultsVersion(); - - // Get build ID first - results.buildID = find( "+", arguments.version ) ? listLast( arguments.version, "+" ) : '0'; - // Remove build ID - arguments.version = reReplace( arguments.version, "\+([^\+]*).$", "" ); - // Get preReleaseID Formalized Now we have major.minor.revision-alpha.1 - results.preReleaseID = find( "-", arguments.version ) ? listLast( arguments.version, "-" ) : ''; - // Remove preReleaseID - arguments.version = reReplace( arguments.version, "\-([^\-]*).$", "" ); - // Get Revision - results.revision = getToken( arguments.version, 3, "." ); - if( results.revision == "" ){ results.revision = missingValuePlaceholder ?: 0; } - - // Get Minor + Major - results.minor = getToken( arguments.version, 2, "." ); - if( results.minor == "" ){ results.minor = missingValuePlaceholder ?: 0; } - results.major = getToken( arguments.version, 1, "." ); - - return results; - } - - /** - * Parse the incoming version string and conform it to semantic version. - * If preReleaseID is not found it is omitted. - * @return string:{major.minor.revision[-preReleaseID]+buildid} - */ - string function parseVersionAsString( required string version, boolean includeBuildID=true ){ - var sVersion = parseVersion( arguments.version ); - return getVersionAsString( sVersion, includeBuildID ); - } - - - /** - * Parse the incoming version struct and output it as a string - * @return string:{major.minor.revision[-preReleaseID]+buildid} - */ - string function getVersionAsString( required struct sVersion, boolean includeBuildID=true ){ - var defaultsVersion = getDefaultsVersion(); - arguments.sVersion = defaultsVersion.append( arguments.sVersion ); - if( includeBuildID && sVersion.buildID != 0 ) { - return ( "#sVersion.major#.#sVersion.minor#.#sVersion.revision#" & ( len( sVersion.preReleaseID ) ? "-" & sVersion.preReleaseID : '' ) & "+#sVersion.buildID#" ); - } else { - return ( "#sVersion.major#.#sVersion.minor#.#sVersion.revision#" & ( len( sVersion.preReleaseID ) ? "-" & sVersion.preReleaseID : '' ) ); - } - } - - /** - * Verifies if the passed version string is in a pre-release state - * Pre-release is defined by the existance of a preRelease ID - */ - boolean function isPreRelease( required string version ){ - var pVersion = parseVersion( arguments.version ); - - return ( len( pVersion.preReleaseID ) ) ? true : false; - } - - /** - * Checks if the versions are equal - * current.hint The current version of the system - * target.hint The target version to check - */ - boolean function isEQ( required string current, required string target, boolean checkBuildID=true ){ - /** - Semantic version: major.minor.revision-alpha.1+build - **/ - - var current = parseVersionAsString( arguments.current, checkBuildID ); - var target = parseVersionAsString( arguments.target, checkBuildID ); - - return ( current == target ); - } - - /** - * True if a specific version, false if a range that could match multiple versions - * version.hint A string that contains a version or a range - */ - boolean function isExactVersion( required string version, boolean includeBuildID=false ) { - - // First test for some sort of range - if( version contains '*' ) return false; - if( version contains 'x.' ) return false; - if( version contains '.x' ) return false; - if( version contains '>=' ) return false; - if( version contains '<=' ) return false; - if( version contains '<' ) return false; - if( version contains '>' ) return false; - if( version contains ' - ' ) return false; - if( version contains '~' ) return false; - if( version contains '^' ) return false; - if( version contains ' || ' ) return false; - - // Ok, looks like it might be a simple version format, so let's fire up the parser. - // Default any missing pieces to "x" so "3" becomes "3.x.x". - arguments.version = parseVersion( clean( arguments.version ), 'x' ); - - // If any of these bits are "x" it means they weren't specified. - if( version.major == 'x' ) { return false; } - if( version.minor == 'x' ) { return false; } - if( version.revision == 'x' ) { return false; } - if( includeBuildID && val( version.buildID ) == 0 ) { return false; } - - return true; - } - -} \ No newline at end of file From 8b0be2ea8535fe17623e6ad1738a73435b135c75 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sat, 1 Jul 2017 20:25:56 -0500 Subject: [PATCH 111/123] Provider fixes --- src/cfml/system/endpoints/File.cfc | 2 +- src/cfml/system/endpoints/Folder.cfc | 2 +- src/cfml/system/endpoints/ForgeBox.cfc | 2 +- src/cfml/system/modules/semver/models/SemanticVersion.cfc | 5 ----- .../system/modules_app/system-commands/commands/upgrade.cfc | 4 ++-- src/cfml/system/services/ArtifactService.cfc | 2 +- src/cfml/system/services/ServerEngineService.cfc | 2 +- 7 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/cfml/system/endpoints/File.cfc b/src/cfml/system/endpoints/File.cfc index 40b24926a..9e71bb06e 100644 --- a/src/cfml/system/endpoints/File.cfc +++ b/src/cfml/system/endpoints/File.cfc @@ -15,7 +15,7 @@ component accessors="true" implements="IEndpoint" singleton { property name="packageService" inject="packageService"; property name="fileSystemUtil" inject="FileSystem"; property name="folderEndpoint" inject="commandbox.system.endpoints.Folder"; - property name="semanticVersion" inject="semanticVersion@semver"; + property name="semanticVersion" inject="provider:semanticVersion@semver"; // Properties property name="namePrefixes" type="string"; diff --git a/src/cfml/system/endpoints/Folder.cfc b/src/cfml/system/endpoints/Folder.cfc index bb49cafa7..9284b0086 100644 --- a/src/cfml/system/endpoints/Folder.cfc +++ b/src/cfml/system/endpoints/Folder.cfc @@ -11,7 +11,7 @@ component accessors="true" implements="IEndpoint" singleton { // DI property name="packageService" inject="packageService"; - property name="semanticVersion" inject="semanticVersion@semver"; + property name="semanticVersion" inject="provider:semanticVersion@semver"; // Properties property name="namePrefixes" type="string"; diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index b91a19bbe..e1a47871b 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -14,7 +14,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { property name="consoleLogger" inject="logbox:logger:console"; property name="forgeBox" inject="ForgeBox"; property name="tempDir" inject="tempDir@constants"; - property name="semanticVersion" inject="semanticVersion@semver"; + property name="semanticVersion" inject="provider:semanticVersion@semver"; property name="artifactService" inject="ArtifactService"; property name="packageService" inject="packageService"; property name="configService" inject="configService"; diff --git a/src/cfml/system/modules/semver/models/SemanticVersion.cfc b/src/cfml/system/modules/semver/models/SemanticVersion.cfc index 37d12e099..585e7900c 100644 --- a/src/cfml/system/modules/semver/models/SemanticVersion.cfc +++ b/src/cfml/system/modules/semver/models/SemanticVersion.cfc @@ -59,8 +59,6 @@ component singleton{ Semantic version: major.minor.revision-alpha.1+build **/ -systemOutput( current & ' <==> ' & target , true); - var current = parseVersion( arguments.current ); var target = parseVersion( arguments.target ); @@ -86,9 +84,6 @@ systemOutput( current & ' <==> ' & target , true); if( !len( target.preReleaseID ) ) { target.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } if( !len( current.preReleaseID ) ) { current.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } -systemOutput( target.preReleaseID, true); -systemOutput( current.preReleaseID, true); -systemOutput( lcase( target.preReleaseID ) gt lcase( current.preReleaseID ), true); // pre-release Check if( target.major eq current.major AND target.minor eq current.minor AND diff --git a/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc b/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc index dccdfd6e7..00f6b7954 100644 --- a/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc @@ -6,7 +6,7 @@ * {code} * . * Use the "latest" parameter to download the bleeding edge version - * . + * .x * {code:bash} * upgrade --latest * {code} @@ -26,7 +26,7 @@ component { property name="ortusPRDArtifactsURL" inject="ortusPRDArtifactsURL@constants"; property name="progressableDownloader" inject="ProgressableDownloader"; property name="progressBar" inject="ProgressBar"; - property name="semanticVersion" inject="semanticVersion"; + property name="semanticVersion" inject="semanticVersion@semver"; property name="ConfigService" inject="ConfigService"; /** diff --git a/src/cfml/system/services/ArtifactService.cfc b/src/cfml/system/services/ArtifactService.cfc index 3e8e1008c..7d3457c18 100644 --- a/src/cfml/system/services/ArtifactService.cfc +++ b/src/cfml/system/services/ArtifactService.cfc @@ -20,7 +20,7 @@ component accessors="true" singleton { property name='tempDir' inject='tempDir@constants'; property name='packageService' inject='PackageService'; property name='logger' inject='logbox:logger:{this}'; - property name="semanticVersion" inject="semanticVersion@semver"; + property name="semanticVersion" inject="provider:semanticVersion@semver"; // COMMANDBOX-479 property name="configService" inject="ConfigService"; diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index c962cd076..234a651cf 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -17,7 +17,7 @@ component accessors="true" singleton="true" { property name='consoleLogger' inject='logbox:logger:console'; property name='cr' inject='cr@constants'; property name='shell' inject='shell'; - property name="semanticVersion" inject="semanticVersion@semver"; + property name="semanticVersion" inject="provider:semanticVersion@semver"; property name="artifactService" inject="artifactService"; From 9082826b9c7de815ca65e8a94245b15f445a4a10 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 4 Jul 2017 00:30:20 -0500 Subject: [PATCH 112/123] Simplify error output and Adobe CF fix --- .../modules_app/testbox-commands/models/CLIRenderer.cfc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc index 777c800a2..262820de2 100644 --- a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc +++ b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc @@ -109,8 +109,11 @@ component { print.line("#repeatString( " ", arguments.level+2 )#-> Failure: #local.thisSpec.failMessage##chr(13)#", COLOR.FAIL ); } if ( local.thisSpec.status == "error" ) { - print.line("#repeatString( " ", arguments.level+2 )#-> Error: #local.thisSpec.error.message##chr(13)#", COLOR.ERROR ) - .line( "#repeatString( " ", arguments.level+2 )#-> Exception Trace: #local.thisSpec.error.stackTrace# #chr(13)##chr(13)#", COLOR.ERROR ); + print.line("#repeatString( " ", arguments.level+2 )#-> Error: #local.thisSpec.error.message##chr(13)#", COLOR.ERROR ); + // If there's a tag context, show the file name and line number where the error occurred + if( isDefined( 'local.thisSpec.error.tagContext' ) && isArray( local.thisSpec.error.tagContext ) && local.thisSpec.error.tagContext.len() ) { + print.line( "#repeatString( " ", arguments.level+2 )#-> at #local.thisSpec.error.tagContext[1].template#:#local.thisSpec.error.tagContext[1].line# #chr(13)##chr(13)#", COLOR.ERROR ); + } } } if ( arrayLen( arguments.suiteStats.suiteStats ) ) { From 9561704ed47e9fecec5a6de9a84e06aad4c3316b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 4 Jul 2017 01:27:22 -0500 Subject: [PATCH 113/123] Fixing global exception for ACF as well --- .../testbox-commands/models/CLIRenderer.cfc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc index 262820de2..c9582b5c1 100644 --- a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc +++ b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc @@ -55,13 +55,19 @@ component { print.line("GLOBAL BUNDLE EXCEPTION", COLOR.ERROR ) .line( "-> #thisBundle.globalException.type#:#thisBundle.globalException.message#:#thisBundle.globalException.detail#", COLOR.ERROR ) - .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) - .line( "STACKTRACE", COLOR.ERROR ) - .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) - .line( "#thisBundle.globalException.stacktrace#", COLOR.ERROR ) - .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) - .line( "END STACKTRACE", COLOR.ERROR ) .line( "---------------------------------------------------------------------------------", COLOR.ERROR ); + + // ACF has an array for the stack trace + if( isSimpleValue( thisBundle.globalException.stacktrace ) ) { + print + .line( "STACKTRACE", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) + .line( "#thisBundle.globalException.stacktrace#", COLOR.ERROR ) + .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) + .line( "END STACKTRACE", COLOR.ERROR ); + } + + print.line( "---------------------------------------------------------------------------------", COLOR.ERROR ); } for ( suiteStats in thisBundle.suiteStats ) { didPrint = genSuiteReport( suiteStats, thisBundle, 0, print, verbose ); From eccf017aa3652f6fab239d573aef3a378179729c Mon Sep 17 00:00:00 2001 From: Mark Skelton Date: Tue, 4 Jul 2017 12:49:38 -0500 Subject: [PATCH 114/123] Updated remove trailing spaces to use Globber (#123) * Updated remove trailing spaces to use Globber, added user configuration options, add all binary extensions to exclude extensions * Move print to top of remove trailing spaces function * Filter files before prompting user to get correct file count, update documentation * Improved exclusions, add force and verbose arguments * Improved documentation --- .../commands/utils/remove-trailing-spaces.cfc | 157 ++++++++---------- 1 file changed, 67 insertions(+), 90 deletions(-) diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc index d22dfee39..a7faf42a9 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -1,70 +1,70 @@ /** - * Removes the trailing spaces from a file + * - Usage * . + * Remove trailing spaces from a list of files + * . + * {code:bash} + * rts globber-filter + * {code} + * . + * No-confirm + * . + * {code:bash} + * rts globber-filter --force + * {code} + * . + * Print the file path of each file affected + * . + * {code:bash} + * rts globber-filter --verbose + * {code} + * . + * Exclude a list a globber patterns + * . + * {code:bash} + * rts globber-filter *.png,node_modules/ + * {code} + * . + * - Configuration + * . + * Set default force parameter * {code:bash} - * utils remove-trailing-spaces /home/contentbox/index.cfm + * config set command.defaults.rts.force=true * {code} * . - * Removes the trailing spaces from a directory + * Set default verbose parameter + * {code:bash} + * config set command.defaults.rts.verbose=true + * {code} * . + * Set default exclude patterns * {code:bash} - * utils remove-trailing-spaces /home/contentbox + * config set command.defaults.rts.exclude=.git/,*.png * {code} **/ component aliases="rts" { - /** - * @path The file or directory path of a file to remove trailing spaces from - **/ - function run( path="" ){ - variables.excludeExtensions = getExcludeExtensions(); - - if ( arguments.path == "" ) { - print.line( "Please provide a file or folder path" ); + property name="pathPatternMatcher" inject="provider:pathPatternMatcher@globber"; + + public function run( + required Globber files, + String exclude = "", + Boolean force = false, + Boolean verbose = false + ){ + arguments.files = filterFiles( arguments.files, arguments.exclude ); + var count = arguments.files.len(); + + if ( !arguments.force && !shell.confirm( "Confirm removing trailing spaces from #count# #count != 1 ? "files" : "file"#" ) ){ return; } - // try adding the file to the current working directory if the file doesn't exist - if ( fileExists( arguments.path ) ){ - // file exists - } else if ( fileExists( getCWD() & "/" & arguments.path ) ){ - arguments.path = getCWD() & "/" & arguments.path; - } else if ( fileExists( expandPath( arguments.path ) ) ){ - // try expanding the path - arguments.path = expandPath( arguments.path ); - } else { - if ( directoryExists( arguments.path ) ){ - // directory exists - } else if ( directoryExists( getCWD() & "/" & arguments.path ) ){ - // try adding the directory to the current working directory if the directory doesn't exist - arguments.path = getCWD() & "/" & arguments.path; - } else if ( directoryExists( expandPath( arguments.path ) ) ){ - // try expanding the path - arguments.path = expandPath( arguments.path ); - } else { - print.line( arguments.path & " is not a valid file or directory" ); - return; + for ( var file in arguments.files ){ + if ( arguments.verbose ){ + print.line( "Removing trailing spaces from " & file & "..." ); } - print.line( "Removing trailing spaces from " & arguments.path & "..." ); - - variables.excludeFolders = getExcludeFolders(); - var fileList = directoryList( arguments.path, true, "path" ); - - for ( var i in fileList ){ - var fileInfo = getFileInfo( i ); - // only process files - if ( fileInfo.type == "file" && - !isExcludedDirectory( i ) && - !variables.excludeExtensions.contains( listLast( i, "." ) ) ){ - removeTrailingSpaces( i ); - } - } - - return; + removeTrailingSpaces( file ); } - - print.line( "Removing trailing spaces from " & arguments.path & "..." ); - removeTrailingSpaces( arguments.path ); } private function removeTrailingSpaces( filePath ){ @@ -91,52 +91,29 @@ component aliases="rts" { return { lines: lines, lineEndings: lineEndings }; } + private function filterFiles( files, exclude ){ + var filteredFiles = []; + + arguments.files.apply( function( file ){ + var fileInfo = getFileInfo( arguments.file ); + // only process files + if ( fileInfo.type == "file" && !pathPatternMatcher.matchPatterns( listToArray( exclude ), arguments.file ) ){ + filteredFiles.append( arguments.file ); + } + } ); + + return filteredFiles; + } + private function getLineEndings( data ){ if ( arguments.data.len() > 0 ){ - if ( arguments.data[1].find( chr( 13 ) & chr( 10 ) ) != 0 ){ + if ( arguments.data[ 1 ].find( chr( 13 ) & chr( 10 ) ) != 0 ){ return chr( 13 ) & chr( 10 ); - } else if ( arguments.data[1].find( chr( 13 ) ) != 0 ){ + } else if ( arguments.data[ 1 ].find( chr( 13 ) ) != 0 ){ return chr( 13 ); } } return chr( 10 ); } - - private function isExcludedDirectory( file ){ - // convert all backslashes to forward-slashes - var f = arguments.file.replace( "\", "/" ); - - for ( var i in variables.excludeFolders ){ - // check if file exists in the exclude directory - if ( f.find( "/" & i & "/" ) || f.startsWith( i )){ - return true; - } - } - // file isn't in any of the exclude directories - return false; - } - - private function getExcludeFolders(){ - return [ '.git' ]; - } - - private function getExcludeExtensions(){ - return [ - '.eot', - '.gif', - '.ico', - '.jar', - '.jpeg', - '.jpg', - '.otf', - '.pdf', - '.png', - '.svg', - '.ttf', - '.woff', - '.woff2', - '.zip', - ]; - } } From e853896c56b9a5c1c11fde01ecb3253792258a9b Mon Sep 17 00:00:00 2001 From: Mark Skelton Date: Tue, 4 Jul 2017 12:50:21 -0500 Subject: [PATCH 115/123] Added function add EOL at EOF to utils module (#124) * Added function add EOL at EOF to utils module * Updated add-eol-at-eof.cfc to add verbose and force parameters, improved how excludes work --- .../commands/utils/add-eol-at-eof.cfc | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc new file mode 100644 index 000000000..93fc6f072 --- /dev/null +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc @@ -0,0 +1,106 @@ +/** + * - Usage + * . + * Add trailing newline to a list of files + * . + * {code:bash} + * eol globber-filter + * {code} + * . + * No-confirm + * . + * {code:bash} + * eol globber-filter --force + * {code} + * . + * Print the file path of each file affected + * . + * {code:bash} + * eol globber-filter --verbose + * {code} + * . + * Exclude a list a globber patterns + * . + * {code:bash} + * eol globber-filter *.png,node_modules/ + * {code} + * . + * - Configuration + * . + * Set default force parameter + * {code:bash} + * config set command.defaults.eol.force=true + * {code} + * . + * Set default verbose parameter + * {code:bash} + * config set command.defaults.eol.verbose=true + * {code} + * . + * Set default exclude patterns + * {code:bash} + * config set command.defaults.eol.exclude=.git/,*.png + * {code} +**/ +component aliases="eol" { + property name="pathPatternMatcher" inject="provider:pathPatternMatcher@globber"; + + public function run( + required Globber files, + String exclude = "", + Boolean force = false, + Boolean verbose = false + ){ + arguments.files = filterFiles( arguments.files, arguments.exclude ); + var count = arguments.files.len(); + + if ( !arguments.force && !shell.confirm( "Confirm adding EOL at EOF for #count# #count != 1 ? "files" : "file"#" ) ){ + return; + } + + for ( var file in arguments.files ){ + if ( arguments.verbose ){ + print.line( "Adding EOL at EOF to " & file & "..." ); + } + + addEOL( file ); + } + } + + private function addEOL( filePath ){ + // trim and get line endings + var content = rTrim( fileRead( arguments.filePath ) ); + + // Add single newline to file content + content &= getLineEndings( content ); + + // write new file + fileWrite( arguments.filePath, content ); + } + + private function filterFiles( files, exclude ){ + var filteredFiles = []; + + arguments.files.apply( function( file ){ + var fileInfo = getFileInfo( arguments.file ); + // only process files + if ( fileInfo.type == "file" && !pathPatternMatcher.matchPatterns( listToArray( exclude ), arguments.file ) ){ + filteredFiles.append( arguments.file ); + } + } ); + + return filteredFiles; + } + + private function getLineEndings( data ){ + if ( arguments.data.len() > 0 ){ + if ( arguments.data[ 1 ].find( chr( 13 ) & chr( 10 ) ) != 0 ){ + return chr( 13 ) & chr( 10 ); + } else if ( arguments.data[ 1 ].find( chr( 13 ) ) != 0 ){ + return chr( 13 ); + } + } + + return chr( 10 ); + } +} From bf9b1e1866824e12c310c418df4fed88b2ed5e50 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 4 Jul 2017 13:24:54 -0500 Subject: [PATCH 116/123] Documentation tweaks --- .../commands/utils/add-eol-at-eof.cfc | 54 +++++++++--------- .../commands/utils/remove-trailing-spaces.cfc | 56 +++++++++---------- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc index 93fc6f072..cd1e8a65a 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc @@ -1,50 +1,48 @@ /** - * - Usage - * . - * Add trailing newline to a list of files - * . + * + * Ensure files have a trailing newline to adhere to POSIX standard. Operates on a single file + * or multiple files as defined by a file globbing pattern. + * * {code:bash} - * eol globber-filter + * eol **.cf* * {code} - * . - * No-confirm - * . + * + * To skip the confirmation, use the --force flag. + * * {code:bash} - * eol globber-filter --force + * eol models/**.cfc --force * {code} - * . - * Print the file path of each file affected - * . + * + * Print the file path of each file affected with the --verbose flag. + * * {code:bash} - * eol globber-filter --verbose + * eol includes/*.cfm --verbose * {code} - * . + * * Exclude a list a globber patterns - * . + * * {code:bash} - * eol globber-filter *.png,node_modules/ + * eol ** *.png,node_modules/ * {code} - * . - * - Configuration - * . - * Set default force parameter + * + * You can set global default parameters for this command to use like so: + * * {code:bash} * config set command.defaults.eol.force=true - * {code} - * . - * Set default verbose parameter - * {code:bash} * config set command.defaults.eol.verbose=true - * {code} - * . - * Set default exclude patterns - * {code:bash} * config set command.defaults.eol.exclude=.git/,*.png * {code} + * **/ component aliases="eol" { property name="pathPatternMatcher" inject="provider:pathPatternMatcher@globber"; + /** + * @files A file globbing pattern that matches one or more files + * @exclude A list of globbing patterns to ignore + * @force Skip user confirmation of modiying files + * @verbose Output additional information about each file affected + */ public function run( required Globber files, String exclude = "", diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc index a7faf42a9..61399e80a 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -1,50 +1,48 @@ /** - * - Usage - * . - * Remove trailing spaces from a list of files - * . + * + * Remove those pesky trailing spaces from each line that some editors add. + * Can be run on a single file or aginst a list of files defined by a file globbing pattern. + * * {code:bash} - * rts globber-filter + * rts **.cf* * {code} - * . - * No-confirm - * . + * + * Skip the user confirmation with the --force flag. + * * {code:bash} - * rts globber-filter --force + * rts models/**.cfc --force * {code} - * . - * Print the file path of each file affected - * . + * + * Print the file path of each file affected with the --verbose flag. + * * {code:bash} - * rts globber-filter --verbose + * rts includes/*.cfm --verbose * {code} - * . - * Exclude a list a globber patterns - * . + * + * Exclude a list a file globbing patterns + * * {code:bash} - * rts globber-filter *.png,node_modules/ + * rts ** *.png,node_modules/ * {code} - * . - * - Configuration - * . - * Set default force parameter + * + * You can set global default parameters for this command to use like so: + * * {code:bash} * config set command.defaults.rts.force=true - * {code} - * . - * Set default verbose parameter - * {code:bash} * config set command.defaults.rts.verbose=true - * {code} - * . - * Set default exclude patterns - * {code:bash} * config set command.defaults.rts.exclude=.git/,*.png * {code} + * **/ component aliases="rts" { property name="pathPatternMatcher" inject="provider:pathPatternMatcher@globber"; + /** + * @files A file globbing pattern that matches one or more files + * @exclude A list of globbing patterns to ignore + * @force Skip user confirmation of modiying files + * @verbose Output additional information about each file affected + */ public function run( required Globber files, String exclude = "", From 53817f980b2b1aa7676c9bbd1594065492559144 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 4 Jul 2017 13:34:36 -0500 Subject: [PATCH 117/123] Removed all trailing spaces from source code! --- src/cfml/Application.cfc | 12 +- src/cfml/system/BaseCommand.cfc | 70 +-- src/cfml/system/BaseTask.cfc | 4 +- src/cfml/system/Bootstrap.cfm | 60 +-- src/cfml/system/Shell.cfc | 58 +-- src/cfml/system/config/CommandBoxDSL.cfc | 18 +- src/cfml/system/config/LogBox.cfc | 90 ++-- src/cfml/system/config/WireBox.cfc | 6 +- src/cfml/system/endpoints/CFLib-ColdBox.cfc | 22 +- src/cfml/system/endpoints/CFLib.cfc | 22 +- src/cfml/system/endpoints/File.cfc | 38 +- src/cfml/system/endpoints/Folder.cfc | 18 +- src/cfml/system/endpoints/ForgeBox.cfc | 196 ++++---- src/cfml/system/endpoints/Git.cfc | 62 +-- src/cfml/system/endpoints/Git_HTTP.cfc | 6 +- src/cfml/system/endpoints/Git_HTTPS.cfc | 6 +- src/cfml/system/endpoints/Git_SSH.cfc | 6 +- src/cfml/system/endpoints/Github.cfc | 12 +- src/cfml/system/endpoints/HTTP.cfc | 34 +- src/cfml/system/endpoints/HTTPS.cfc | 6 +- src/cfml/system/endpoints/IEndpoint.cfc | 6 +- .../system/endpoints/IEndpointInteractive.cfc | 12 +- src/cfml/system/endpoints/Jar.cfc | 28 +- src/cfml/system/endpoints/RIAForge.cfc | 10 +- .../modules/JSONPrettyPrint/ModuleConfig.cfc | 2 +- .../models/JSONPrettyPrint.cfc | 22 +- .../system/modules/globber/ModuleConfig.cfc | 2 +- .../system/modules/globber/models/Globber.cfc | 38 +- .../globber/models/PathPatternMatcher.cfc | 32 +- .../propertyFile/models/PropertyFile.cfc | 36 +- .../system/modules/semver/ModuleConfig.cfc | 6 +- .../modules/semver/models/SemanticVersion.cfc | 182 +++---- .../string-similarity/ModuleConfig.cfc | 6 +- .../models/StringSimilarity.cfc | 20 +- .../commands/artifacts/clean.cfc | 6 +- .../commands/artifacts/help.cfc | 4 +- .../commands/artifacts/list.cfc | 14 +- .../commands/artifacts/remove.cfc | 4 +- .../commands/cachebox/create/config.cfc | 4 +- .../commands/cachebox/create/help.cfc | 4 +- .../commands/cachebox/help.cfc | 6 +- .../commands/coldbox/create/app-wizard.cfc | 4 +- .../commands/coldbox/create/app.cfc | 36 +- .../commands/coldbox/create/bdd.cfc | 6 +- .../commands/coldbox/create/handler.cfc | 4 +- .../commands/coldbox/create/help.cfc | 4 +- .../coldbox/create/interceptor-test.cfc | 8 +- .../commands/coldbox/create/interceptor.cfc | 10 +- .../commands/coldbox/create/layout.cfc | 34 +- .../commands/coldbox/create/model-test.cfc | 12 +- .../commands/coldbox/create/model.cfc | 10 +- .../commands/coldbox/create/module.cfc | 40 +- .../commands/coldbox/create/orm-crud.cfc | 18 +- .../commands/coldbox/create/orm-entity.cfc | 14 +- .../coldbox/create/orm-event-handler.cfc | 4 +- .../commands/coldbox/create/orm-service.cfc | 8 +- .../coldbox/create/orm-virtual-service.cfc | 8 +- .../commands/coldbox/create/unit.cfc | 6 +- .../commands/coldbox/create/view.cfc | 4 +- .../commands/coldbox/help.cfc | 6 +- .../commands/coldbox/reinit.cfc | 10 +- .../commands/contentbox/create/module.cfc | 40 +- .../commands/contentbox/create/theme.cfc | 4 +- .../commands/contentbox/create/widget.cfc | 4 +- .../commands/contentbox/help.cfc | 6 +- .../commands/forgebox/help.cfc | 4 +- .../commands/forgebox/login.cfc | 18 +- .../commands/forgebox/my-contributions.cfc | 4 +- .../commands/forgebox/publish.cfc | 20 +- .../commands/forgebox/register.cfc | 10 +- .../commands/forgebox/search.cfc | 28 +- .../commands/forgebox/show.cfc | 90 ++-- .../commands/forgebox/slugcheck.cfc | 12 +- .../commands/forgebox/types.cfc | 10 +- .../commands/forgebox/unpublish.cfc | 16 +- .../commands/forgebox/use.cfc | 8 +- .../commands/forgebox/whoami.cfc | 10 +- .../games-commands/commands/game/snake.cfc | 218 ++++----- .../commands/logbox/create/appender.cfc | 4 +- .../commands/logbox/create/config.cfc | 4 +- .../commands/logbox/create/help.cfc | 6 +- .../logbox-commands/commands/logbox/help.cfc | 6 +- .../commands/endpoint/login.cfc | 20 +- .../commands/endpoint/publish.cfc | 24 +- .../commands/endpoint/register.cfc | 22 +- .../commands/endpoint/unpublish.cfc | 26 +- .../commands/package/bugs.cfc | 12 +- .../commands/package/clear.cfc | 36 +- .../commands/package/documentation.cfc | 12 +- .../commands/package/help.cfc | 6 +- .../commands/package/homepage.cfc | 12 +- .../commands/package/init-wizard.cfc | 8 +- .../commands/package/init.cfc | 22 +- .../commands/package/install.cfc | 5 +- .../commands/package/list.cfc | 34 +- .../commands/package/outdated.cfc | 34 +- .../commands/package/run-script.cfc | 18 +- .../package-commands/commands/package/set.cfc | 28 +- .../commands/package/show.cfc | 22 +- .../commands/package/uninstall.cfc | 36 +- .../commands/package/update.cfc | 40 +- .../commands/package/version.cfc | 76 +-- .../interceptors/packageScripts.cfc | 22 +- .../server-commands/commands/server/cd.cfc | 6 +- .../server-commands/commands/server/clear.cfc | 30 +- .../commands/server/forget.cfc | 12 +- .../server-commands/commands/server/help.cfc | 6 +- .../server-commands/commands/server/list.cfc | 8 +- .../server-commands/commands/server/log.cfc | 18 +- .../server-commands/commands/server/open.cfc | 20 +- .../commands/server/restart.cfc | 8 +- .../server-commands/commands/server/set.cfc | 28 +- .../server-commands/commands/server/show.cfc | 22 +- .../server-commands/commands/server/start.cfc | 22 +- .../commands/server/status.cfc | 64 +-- .../server-commands/commands/server/stop.cfc | 28 +- .../system-commands/commands/browse.cfc | 4 +- .../system-commands/commands/cat.cfc | 34 +- .../system-commands/commands/cd.cfc | 8 +- .../system-commands/commands/cfml.cfc | 78 +-- .../system-commands/commands/checksum.cfc | 40 +- .../system-commands/commands/config/clear.cfc | 28 +- .../system-commands/commands/config/set.cfc | 22 +- .../system-commands/commands/config/show.cfc | 16 +- .../system-commands/commands/cp.cfc | 16 +- .../system-commands/commands/delete.cfc | 38 +- .../system-commands/commands/dir.cfc | 16 +- .../system-commands/commands/echo.cfc | 2 +- .../system-commands/commands/edit.cfc | 16 +- .../system-commands/commands/execute.cfc | 12 +- .../system-commands/commands/fileAppend.cfc | 16 +- .../system-commands/commands/fileWrite.cfc | 8 +- .../system-commands/commands/grep.cfc | 16 +- .../system-commands/commands/help.cfc | 108 ++--- .../system-commands/commands/history.cfc | 22 +- .../system-commands/commands/info.cfc | 19 +- .../system-commands/commands/mkdir.cfc | 20 +- .../system-commands/commands/more.cfc | 12 +- .../system-commands/commands/mv.cfc | 22 +- .../system-commands/commands/pause.cfc | 4 +- .../commands/propertyFile/clear.cfc | 10 +- .../commands/propertyFile/set.cfc | 10 +- .../commands/propertyFile/show.cfc | 14 +- .../system-commands/commands/pwd.cfc | 2 +- .../system-commands/commands/quit.cfc | 4 +- .../system-commands/commands/recipe.cfc | 48 +- .../system-commands/commands/reload.cfc | 4 +- .../system-commands/commands/repl.cfc | 36 +- .../system-commands/commands/run.cfc | 18 +- .../system-commands/commands/sed.cfc | 50 +- .../system-commands/commands/system-log.cfc | 16 +- .../system-commands/commands/tail.cfc | 98 ++-- .../system-commands/commands/tokenReplace.cfc | 12 +- .../system-commands/commands/touch.cfc | 22 +- .../system-commands/commands/upgrade.cfc | 28 +- .../system-commands/commands/version.cfc | 4 +- .../task-commands/commands/task/run.cfc | 20 +- .../task-commands/models/TaskService.cfc | 39 +- .../commands/testbox/create/bdd.cfc | 24 +- .../commands/testbox/create/help.cfc | 8 +- .../commands/testbox/create/unit.cfc | 26 +- .../commands/testbox/generate/harness.cfc | 4 +- .../commands/testbox/generate/help.cfc | 6 +- .../commands/testbox/help.cfc | 12 +- .../testbox-commands/commands/testbox/run.cfc | 42 +- .../commands/testbox/watch.cfc | 24 +- .../testbox-commands/models/CLIRenderer.cfc | 42 +- .../models/TestingService.cfc | 16 +- .../templates/testbox/test-harness/runner.cfm | 2 +- .../utils-commands/ModuleConfig.cfc | 2 +- .../commands/utils/add-eol-at-eof.cfc | 24 +- .../commands/utils/remove-trailing-spaces.cfc | 24 +- .../commands/wirebox/create/aspect.cfc | 4 +- .../commands/wirebox/create/binder.cfc | 4 +- .../commands/wirebox/create/dsl.cfc | 4 +- .../commands/wirebox/create/help.cfc | 6 +- .../commands/wirebox/create/scope.cfc | 4 +- .../commands/wirebox/help.cfc | 6 +- src/cfml/system/services/ArtifactService.cfc | 112 ++--- src/cfml/system/services/CommandService.cfc | 52 +- src/cfml/system/services/ConfigService.cfc | 50 +- .../system/services/InterceptorService.cfc | 24 +- src/cfml/system/services/JSONService.cfc | 64 +-- src/cfml/system/services/ModuleService.cfc | 2 +- src/cfml/system/services/PackageService.cfc | 450 ++++++++--------- .../system/services/ServerEngineService.cfc | 128 ++--- src/cfml/system/services/ServerService.cfc | 418 ++++++++-------- src/cfml/system/util/ANSIConsoleAppender.cfc | 24 +- src/cfml/system/util/CommandDSL.cfc | 84 ++-- src/cfml/system/util/Completor.cfc | 72 +-- src/cfml/system/util/Executor.cfc | 8 +- src/cfml/system/util/FileSystem.cfc | 60 +-- src/cfml/system/util/ForgeBox.cfc | 226 ++++----- src/cfml/system/util/Formatter.cfc | 28 +- src/cfml/system/util/Parser.cfc | 110 ++--- src/cfml/system/util/Print.cfc | 10 +- src/cfml/system/util/PrintBuffer.cfc | 14 +- src/cfml/system/util/ProgressBar.cfc | 40 +- .../system/util/ProgressableDownloader.cfc | 92 ++-- src/cfml/system/util/REPLParser.cfc | 2 +- src/cfml/system/util/ReaderFactory.cfc | 24 +- src/cfml/system/util/SystemSettings.cfc | 22 +- src/cfml/system/util/Watcher.cfc | 74 +-- .../system/wirebox/system/aop/Matcher.cfc | 192 ++++---- .../wirebox/system/aop/MethodInterceptor.cfc | 8 +- .../wirebox/system/aop/MethodInvocation.cfc | 118 ++--- src/cfml/system/wirebox/system/aop/Mixer.cfc | 2 +- .../system/wirebox/system/aop/MixerUtil.cfc | 2 +- .../system/aop/aspects/CFTransaction.cfc | 2 +- .../system/aop/aspects/MethodLogger.cfc | 30 +- .../system/core/collections/ScopeStorage.cfc | 32 +- .../system/core/conversion/DataMarshaller.cfc | 2 +- .../core/conversion/ObjectMarshaller.cfc | 2 +- .../system/core/conversion/XMLConverter.cfc | 54 +-- .../system/core/dynamic/BeanPopulator.cfc | 2 +- .../system/core/dynamic/HTMLHelper.cfc | 18 +- .../wirebox/system/core/dynamic/MixerUtil.cfc | 2 +- .../wirebox/system/core/events/EventPool.cfc | 12 +- .../system/core/events/EventPoolManager.cfc | 2 +- .../wirebox/system/core/util/CFMLEngine.cfc | 2 +- .../system/core/util/CFMappingHelper.cfc | 2 +- .../wirebox/system/core/util/FileUtils.cfc | 451 +++++++++++++++++- .../system/core/util/RailoMappingHelper.cfc | 2 +- .../system/core/util/RequestBuffer.cfc | 2 +- .../system/wirebox/system/core/util/Util.cfc | 2 +- .../system/wirebox/system/ioc/Builder.cfc | 4 +- .../system/wirebox/system/ioc/IInjector.cfc | 14 +- .../system/wirebox/system/ioc/IProvider.cfc | 6 +- .../system/wirebox/system/ioc/Injector.cfc | 8 +- .../system/wirebox/system/ioc/Provider.cfc | 24 +- src/cfml/system/wirebox/system/ioc/Scopes.cfc | 10 +- src/cfml/system/wirebox/system/ioc/Types.cfc | 12 +- .../wirebox/system/ioc/config/Binder.cfc | 2 +- .../system/ioc/config/DefaultBinder.cfc | 30 +- .../wirebox/system/ioc/config/LogBox.cfc | 6 +- .../wirebox/system/ioc/config/Mapping.cfc | 2 +- .../wirebox/system/ioc/config/Mixin.cfc | 18 +- .../wirebox/system/ioc/dsl/CacheBoxDSL.cfc | 18 +- .../wirebox/system/ioc/dsl/ColdBoxDSL.cfc | 2 +- .../wirebox/system/ioc/dsl/IDSLBuilder.cfc | 12 +- .../wirebox/system/ioc/dsl/LogBoxDSL.cfc | 28 +- .../wirebox/system/ioc/scopes/CFScopes.cfc | 2 +- .../wirebox/system/ioc/scopes/CacheBox.cfc | 4 +- .../wirebox/system/ioc/scopes/IScope.cfc | 8 +- .../wirebox/system/ioc/scopes/NoScope.cfc | 6 +- .../system/ioc/scopes/RequestScope.cfc | 2 +- .../wirebox/system/ioc/scopes/Singleton.cfc | 2 +- .../system/logging/AbstractAppender.cfc | 2 +- .../system/wirebox/system/logging/Layout.cfc | 16 +- .../system/wirebox/system/logging/LogBox.cfc | 2 +- .../wirebox/system/logging/LogEvent.cfc | 26 +- .../wirebox/system/logging/LogLevels.cfc | 22 +- .../system/wirebox/system/logging/Logger.cfc | 2 +- .../system/logging/appenders/CFAppender.cfc | 30 +- .../logging/appenders/ConsoleAppender.cfc | 8 +- .../system/logging/appenders/DBAppender.cfc | 110 ++--- .../logging/appenders/DummyAppender.cfc | 22 +- .../logging/appenders/EmailAppender.cfc | 2 +- .../system/logging/appenders/FileAppender.cfc | 2 +- .../logging/appenders/RollingFileAppender.cfc | 24 +- .../logging/appenders/ScopeAppender.cfc | 40 +- .../logging/appenders/SocketAppender.cfc | 46 +- .../logging/appenders/TracerAppender.cfc | 26 +- .../system/logging/config/LogBoxConfig.cfc | 110 ++--- .../logging/config/samples/Sample.LogBox.cfc | 10 +- .../system/logging/util/FileRotator.cfc | 2 +- 266 files changed, 4170 insertions(+), 3724 deletions(-) diff --git a/src/cfml/Application.cfc b/src/cfml/Application.cfc index b3305830c..df8738c20 100644 --- a/src/cfml/Application.cfc +++ b/src/cfml/Application.cfc @@ -28,18 +28,18 @@ component{ // kick in an abort to exit shell, application timeout controls wirebox. abort; } - + function onError( any exception, string eventName ) { - + createObject( 'java', 'java.lang.System' ).setProperty( 'cfml.cli.exitCode', '1' ); - + // Try to log this to LogBox try { application.wireBox.getLogBox().getRootLogger().error( '#exception.message# #exception.detail ?: ''#', exception.stackTrace ); application.wireBox.getInstance( 'interceptorService' ).announceInterception( 'onException', { exception=exception } ); // If it fails no worries, LogBox just probably isn't loaded yet. } catch ( Any e ) {} - + // Give nicer message to user var err = arguments.exception; var CR = chr( 13 ); @@ -71,8 +71,8 @@ component{ systemOutput( '', true ); systemOutput( '#err.stacktrace#', true ); - //writeDump(var=arguments.exception, output="console"); - + //writeDump(var=arguments.exception, output="console"); + // Give them a chance to read it sleep( 30000 ); } diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index 2f09b22f3..1711b80fe 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -9,7 +9,7 @@ * */ component accessors="true" singleton { - + // DI property name="CR"; property name="formatterUtil"; @@ -35,37 +35,37 @@ component accessors="true" singleton { variables.parser = wirebox.getInstance( "Parser" ); variables.configService = wirebox.getInstance( "ConfigService" ); variables.SystemSettings = wirebox.getInstance( "SystemSettings" ); - + hasErrored = false; return this; } - + // This method needs to be overridden by the concrete class. function run() { return 'This command CFC has not implemented a run() method.'; - } - + } + // Convenience method for getting stuff from WireBox function getInstance( name, dsl, initArguments={}, targetObject='' ) { return wirebox.getInstance( argumentCollection = arguments ); } - + // Called prior to each execution to reset any state stored in the CFC function reset() { print.clear(); hasErrored = false; } - + // Get the result. This will be called if the run() method doesn't return anything function getResult() { return print.getResult(); } - + // Returns the current working directory of the shell function getCWD() { return shell.pwd(); } - + /** * ask the user a question and wait for response * @message.hint message to prompt the user with @@ -77,18 +77,18 @@ component accessors="true" singleton { print.toConsole(); return shell.ask( arguments.message, arguments.mask, arguments.defaultResponse ); } - + /** * Wait until the user's next keystroke * @message.hint Message to display to the user such as "Press any key to continue." **/ function waitForKey( message='' ) { if( len( arguments.message ) ) { - print.toConsole(); + print.toConsole(); } return shell.waitForKey( arguments.message ); } - + /** * Ask the user a question looking for a yes/no response * Accepts any boolean value, or "y". @@ -98,7 +98,7 @@ component accessors="true" singleton { print.toConsole(); return shell.confirm( arguments.message ); } - + /** * Run another command by name. * This is deprecated in favor of command(), which escapes parameters for you. @@ -107,22 +107,22 @@ component accessors="true" singleton { function runCommand( required command, returnOutput=false ) { return shell.callCommand( arguments.command, arguments.returnOutput ); } - + /** - * Run another command by DSL. + * Run another command by DSL. * @name.hint The name of the command to run. **/ function command( required name ) { return getinstance( name='CommandDSL', initArguments={ name : arguments.name } ); } - + /** * Create a directory watcher. Call its DSL to configure it. **/ function watch() { return getinstance( 'watcher' ); } - + /** * Return a new globber **/ @@ -133,7 +133,7 @@ component accessors="true" singleton { } return globber; } - + /** * Return a new PropertyFile instance **/ @@ -147,11 +147,11 @@ component accessors="true" singleton { /** * Use if if your command wants to give controlled feedback to the user without raising - * an actual exception which comes with a messy stack trace. - * Use clearPrintBuffer to wipe out any output accrued in the print buffer. - * + * an actual exception which comes with a messy stack trace. + * Use clearPrintBuffer to wipe out any output accrued in the print buffer. + * * return error( "We're sorry, but happy hour ended 20 minutes ago." ); - * + * * @message.hint The error message to display * @clearPrintBuffer.hint Wipe out the print buffer or not, it does not by default **/ @@ -159,25 +159,25 @@ component accessors="true" singleton { setExitCode( 1 ); hasErrored = true; if( arguments.clearPrintBuffer ) { - // Wipe + // Wipe print.clear(); } else { // Distance ourselves from whatever other output the command may have given so far. print.line(); } throw( message=arguments.message, detail=arguments.detail, type="commandException"); - + } - + /** - * Tells you if the error() method has been called on this command. + * Tells you if the error() method has been called on this command. **/ function hasError() { return hasErrored; } - + /** - * Sets the OS exit code + * Sets the OS exit code **/ function setExitCode( required string exitCode ) { if( arguments.exitCode != 0 ) { @@ -185,9 +185,9 @@ component accessors="true" singleton { } return shell.setExitCode( arguments.exitCode ); } - + /** - * This will open a file or folder externally in the default editor for the user. + * This will open a file or folder externally in the default editor for the user. * Useful for opening a new file for editing that was just created. **/ function openPath( path ) { @@ -196,15 +196,15 @@ component accessors="true" singleton { .params( arguments.path ) .run(); } - + /** - * This will open a URL in the user's browser + * This will open a URL in the user's browser **/ function openURL( theURL ) { // Defer to "browse" command. command( "browse" ) .params( arguments.theURL ) - .run(); + .run(); } /** @@ -229,7 +229,7 @@ component accessors="true" singleton { /** * Retrieve an env value by name. - * + * * @key The name of the setting to look up. * @defaultValue The default value to use if the key does not exist in the env */ @@ -237,5 +237,5 @@ component accessors="true" singleton { return systemSettings.getEnv( argumentCollection=arguments ); } - + } \ No newline at end of file diff --git a/src/cfml/system/BaseTask.cfc b/src/cfml/system/BaseTask.cfc index 9502f9384..3b17ed846 100644 --- a/src/cfml/system/BaseTask.cfc +++ b/src/cfml/system/BaseTask.cfc @@ -9,7 +9,7 @@ * */ component accessors="true" extends='commandbox.system.BaseCommand' { - + // For now, tasks just do everything commands do - + } \ No newline at end of file diff --git a/src/cfml/system/Bootstrap.cfm b/src/cfml/system/Bootstrap.cfm index 05c081335..f2ed145f8 100644 --- a/src/cfml/system/Bootstrap.cfm +++ b/src/cfml/system/Bootstrap.cfm @@ -14,11 +14,11 @@ This file will stay running the entire time the shell is open #chr( 27 )#[32m#chr( 27 )#[40m#chr( 27 )#[1m - _____ _ ____ - / ____| | | _ \ - | | ___ _ __ ___ _ __ ___ __ _ _ __ __| | |_) | _____ __ - | | / _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` | _ < / _ \ \/ / - | |___| (_) | | | | | | | | | | | (_| | | | | (_| | |_) | (_) > < + _____ _ ____ + / ____| | | _ \ + | | ___ _ __ ___ _ __ ___ __ _ _ __ __| | |_) | _____ __ + | | / _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` | _ < / _ \ \/ / + | |___| (_) | | | | | | | | | | | (_| | | | | (_| | |_) | (_) > < \_____\___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_|____/ \___/_/\_\ #chr( 27 )#[0m v@@version@@ #chr( 27 )#[1mWelcome to CommandBox! @@ -29,31 +29,31 @@ Type "help" for help, or "help [command]" to be more specific.#chr( 27 )#[0m system = createObject( "java", "java.lang.System" ); args = system.getProperty( "cfml.cli.arguments" ); argsArray = deserializeJSON( system.getProperty( "cfml.cli.argument.array" ) ); - + // System.in is usually the keyboard input, but if the output of another command or a file - // was piped into CommandBox, System.in will represent that input. Wrap System.in + // was piped into CommandBox, System.in will represent that input. Wrap System.in // in a buffered reader so we can check it. inputStreamReader = createObject( 'java', 'java.io.InputStreamReader' ).init( system.in ); bufferedReader = createObject( 'java', 'java.io.BufferedReader' ).init( inputStreamReader ); - + // Verify if we can run CommandBox Java v. 1.7+ if( findNoCase( "1.6", server.java.version ) ){ systemOutput( "The Java Version you have (#server.java.version#) is not supported by CommandBox. Please install a Java JRE/JDK 1.7+" ); sleep( 5000 ); abort; } - + // Check if we are called with an inline command if( !isNull( args ) && trim( args ) != "" ){ - + // Create the shell shell = wireBox.getInstance( name='Shell', initArguments={ asyncLoad=false } ); shell.setShellType( 'command' ); interceptorService = shell.getInterceptorService(); - + interceptData = { shellType=shell.getShellType(), args=argsArray, banner=banner }; interceptorService.announceInterception( 'onCLIStart', interceptData ); - + piped = []; hasPiped = false; // If data is piped to CommandBox, it will be in this buffered reader @@ -62,7 +62,7 @@ Type "help" for help, or "help [command]" to be more specific.#chr( 27 )#[0m piped.append( bufferedReader.readLine() ); hasPiped = true; } - + // If data was piped via standard input if( hasPiped ) { // Concat lines back together @@ -71,7 +71,7 @@ Type "help" for help, or "help [command]" to be more specific.#chr( 27 )#[0m } else { shell.callCommand( command=argsArray, initialCommand=true ); } - + // flush console shell.getReader().flush(); // "box" was called all by itself with no commands @@ -79,10 +79,10 @@ Type "help" for help, or "help [command]" to be more specific.#chr( 27 )#[0m // If the standard input has content waiting, cut the chit chat and just run the commands so we can exit. silent = bufferedReader.ready(); inStream = system.in; - + // If we're piping in data, let's grab it and treat it as commands. // system.in should work directly, but Windows was blocking forever and not reading the InputStream - // So we'll create our own input stream with a line break at the end + // So we'll create our own input stream with a line break at the end if( silent ) { piped = []; // If data is piped to CommandBox, it will be in this buffered reader @@ -94,55 +94,55 @@ Type "help" for help, or "help [command]" to be more specific.#chr( 27 )#[0m piped = piped.toList( chr( 10 ) ) & chr( 10 ); inStream = createObject("java","java.io.ByteArrayInputStream").init(piped.getBytes()); } - + // Create the shell - shell = application.wirebox.getInstance( name='Shell', initArguments={ asyncLoad=!silent, inStream=inStream, outputStream=system.out } ); - + shell = application.wirebox.getInstance( name='Shell', initArguments={ asyncLoad=!silent, inStream=inStream, outputStream=system.out } ); + shell.setShellType( 'interactive' ); interceptorService = shell.getInterceptorService(); - + interceptData = { shellType=shell.getShellType(), args=argsArray, banner=banner }; interceptorService.announceInterception( 'onCLIStart', interceptData ); - + if( !silent ) { // Output the welcome banner shell.printString( replace( interceptData.banner, '@@version@@', shell.getVersion() ) ); } - + // Running the "reload" command will enter this while loop once while( shell.run( silent=silent ) ){ clearScreen = shell.getDoClearScreen(); - + interceptorService.announceInterception( 'onCLIExit' ); if( clearScreen ){ shell.clearScreen(); } - + // Clear all caches: template, ... SystemCacheClear( "all" ); shell = javacast( "null", "" ); - + // reload wirebox wireBox.shutdown(); new wirebox.system.ioc.Injector( 'commandbox.system.config.WireBox' ); variables.wireBox = application.wireBox; - - + + // startup a new shell shell = wireBox.getInstance( 'Shell' ); interceptorService = shell.getInterceptorService(); shell.setShellType( 'interactive' ); interceptData = { shellType=shell.getShellType(), args=[], banner=banner }; interceptorService.announceInterception( 'onCLIStart', interceptData ); - + if( clearScreen ){ // Output the welcome banner shell.printString( replace( interceptData.banner, '@@version@@', shell.getVersion() ) ); } - + } } - + interceptorService.announceInterception( 'onCLIExit' ); system.runFinalization(); diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index f4152a2ea..7fbc7a28a 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -21,7 +21,7 @@ component accessors="true" singleton { property name="InterceptorService" inject="InterceptorService"; property name="ModuleService" inject="ModuleService"; property name="Util" inject="wirebox.system.core.util.Util"; - + /** * The java jline reader class. @@ -65,7 +65,7 @@ component accessors="true" singleton { * to be fed into another OS command. */ property name="shellType" default="interactive"; - + /** * constructor @@ -81,7 +81,7 @@ component accessors="true" singleton { any outputStream, required string userDir, required string tempDir, - boolean asyncLoad=true + boolean asyncLoad=true ){ // Possible byte order marks variables.BOMS = [ @@ -132,12 +132,12 @@ component accessors="true" singleton { // Create temp dir & set setTempDir( variables.tempdir ); - + getInterceptorService().configure(); getModuleService().configure(); - + getModuleService().activateAllModules(); - + // load commands if( variables.initArgs.asyncLoad ){ thread name="commandbox.loadcommands#getTickCount()#"{ @@ -172,7 +172,7 @@ component accessors="true" singleton { * @clear.hint clears the screen after reload **/ Shell function reload( Boolean clear=true ){ - + setDoClearScreen( arguments.clear ); setReloadshell( true ); setKeepRunning( false ); @@ -210,7 +210,7 @@ component accessors="true" singleton { * @return the response from the user **/ string function ask( message, string mask='', string defaultResponse='' ) { - + try { // read reponse while masking input var input = variables.reader.readLine( @@ -226,7 +226,7 @@ component accessors="true" singleton { throw( message='CANCELLED', type="UserInterruptException"); } finally{ // Reset back to default prompt - setPrompt(); + setPrompt(); } return input; @@ -310,10 +310,10 @@ component accessors="true" singleton { * @directory.hint directory to use **/ Shell function setTempDir( required directory ){ - + // Create it if it's not there. if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } // set now that it is created. @@ -383,20 +383,20 @@ component accessors="true" singleton { if( arguments.input != "" ){ variables.keepRunning = false; } - + // Shell stops on this line while waiting for user input if( arguments.silent ) { line = variables.reader.readLine( javacast( "char", ' ' ) ); } else { line = variables.reader.readLine(); } - + // If the standard input isn't avilable, bail. This happens // when commands are piped in and we've reached the end of the piped stream if( !isDefined( 'line' ) ) { return false; } - + // Clean BOM from start of text in case something was piped from a file BOMS.each( function( i ){ if( line.startsWith( i ) ) { @@ -405,7 +405,7 @@ component accessors="true" singleton { } ); // If there's input, try to run it. - if( len( trim( line ) ) ) { + if( len( trim( line ) ) ) { callCommand( command=line, initialCommand=true ); } @@ -425,31 +425,31 @@ component accessors="true" singleton { /** * Call a command - * @command.hint Either a string containing a text command, or an array of tokens representing the command and parameters. + * @command.hint Either a string containing a text command, or an array of tokens representing the command and parameters. * @returnOutput.hint True will return the output of the command as a string, false will send the output to the console. If command outputs nothing, an empty string will come back. * @piped.hint Any text being piped into the command. This will overwrite the first parameter (pushing any positional params back) * @initialCommand.hint Since commands can recursivley call new commands via this method, this flags the first in the chain so exceptions can bubble all the way back to the beginning. - * In other words, if "foo" calls "bar", which calls "baz" and baz errors, all three commands are scrapped and do not finish execution. + * In other words, if "foo" calls "bar", which calls "baz" and baz errors, all three commands are scrapped and do not finish execution. **/ - function callCommand( + function callCommand( required any command, returnOutput=false, string piped, boolean initialCommand=false ) { - + // Commands a loaded async in interactive mode, so this is a failsafe to ensure the CommandService // is finished. Especially useful for commands run onCLIStart. Wait up to 5 seconds. var i = 0; while( !CommandService.getConfigured() && ++i<50 ) { sleep( 100 ); } - + // Flush history buffer to disk. I could do this in the quit command // but then I would lose everything if the user just closes the window variables.reader.getHistory().flush(); - + try{ - + if( isArray( command ) ) { if( structKeyExists( arguments, 'piped' ) ) { var result = variables.commandService.runCommandTokens( arguments.command, piped ); @@ -459,7 +459,7 @@ component accessors="true" singleton { } else { var result = variables.commandService.runCommandLine( arguments.command ); } - + // This type of error is recoverable-- like validation error or unresolved command, just a polite message please. } catch ( commandException var e) { // If this is a nested command, pass the exception along to unwind the entire stack. @@ -486,7 +486,7 @@ component accessors="true" singleton { printError( e ); } } - + // Return the output to the caller to deal with if( arguments.returnOutput ) { if( isNull( result ) ) { @@ -495,7 +495,7 @@ component accessors="true" singleton { return result; } } - + // We get to output the results ourselves if( !isNull( result ) && !isSimpleValue( result ) ){ if( isArray( result ) ){ @@ -522,14 +522,14 @@ component accessors="true" singleton { * @err.hint Error object to print (only message is required) **/ Shell function printError( required err ){ - + setExitCode( 1 ); - + // If CommandBox blows up while starting, the interceptor service won't be ready yet. if( getInterceptorService().getConfigured() ) { getInterceptorService().announceInterception( 'onException', { exception=err } ); } - + variables.logger.error( '#arguments.err.message# #arguments.err.detail ?: ''#', arguments.err.stackTrace ?: '' ); variables.reader.print( variables.print.whiteOnRedLine( 'ERROR (#variables.version#)' ) ); @@ -566,4 +566,4 @@ component accessors="true" singleton { return this; } -} +} \ No newline at end of file diff --git a/src/cfml/system/config/CommandBoxDSL.cfc b/src/cfml/system/config/CommandBoxDSL.cfc index f82378e27..6873de423 100644 --- a/src/cfml/system/config/CommandBoxDSL.cfc +++ b/src/cfml/system/config/CommandBoxDSL.cfc @@ -13,7 +13,7 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ property name="injector"; property name="log"; - /** + /** * Configure the DSL for operation and returns itself */ public any function init( required any injector ) output=false { @@ -22,15 +22,15 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ return this; } - - /** + + /** * Process an incoming DSL definition and produce an object with it. * @output false * @definition.hint The injection dsl definition structure to process. Keys: name, dsl * @targetObject.hint The target object we are building the DSL dependency for. If empty, means we are just requesting building */ public any function process( required definition, targetObject ) output=false { - + var thisName = arguments.definition.name; var thisType = arguments.definition.dsl; var thisTypeLen = listLen(thisType,":"); @@ -53,7 +53,7 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ break; } - //commandbox:{key}:{target} + //commandbox:{key}:{target} case 3: { thisLocationType = getToken(thisType,2,":"); thisLocationKey = getToken(thisType,3,":"); @@ -79,7 +79,7 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ case "ConfigSettings" : { var configService = getInjector().getInstance( 'ConfigService' ); var configSettings = configService.getConfigSettings(); - + // Check for setting existance if( configService.settingExists( thisLocationKey ) ){ return configService.getSetting( thisLocationKey ); @@ -105,7 +105,7 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ return moduleConfig[ thisLocationKey ].settings[ thisLocationToken ]; } else if( getLog().canDebug() ){ getLog().debug("The module requested: #thisLocationKey# does not exist in the loaded modules. Loaded modules are #structKeyList(moduleConfig)#"); - } + } } else if( getLog().canDebug() ){ getLog().debug("The module requested: #thisLocationKey# does not exist in the loaded modules. Loaded modules are #structKeyList(moduleConfig)#"); } @@ -114,11 +114,11 @@ component implements="wirebox.system.ioc.dsl.IDSLBuilder" accessors=true{ break; } } - + // debug info if( getLog().canDebug() ){ getLog().debug("getColdboxDSL() cannot find dependency using definition: #arguments.definition.toString()#"); - } + } } diff --git a/src/cfml/system/config/LogBox.cfc b/src/cfml/system/config/LogBox.cfc index af94f83e2..6034d1ace 100644 --- a/src/cfml/system/config/LogBox.cfc +++ b/src/cfml/system/config/LogBox.cfc @@ -1,46 +1,46 @@ -/** -********************************************************************************* -* Copyright Since 2005 ColdBox Platform by Ortus Solutions, Corp -* www.coldbox.org | www.ortussolutions.com -******************************************************************************** -* LogBox Configuration -*/ -component { - - function configure(){ - var system = createObject( "java", "java.lang.System" ); - var homeDir = isNull( system.getProperty('cfml.cli.home') ) ? - system.getProperty( 'user.home' ) & "/.CommandBox/" : system.getProperty( 'cfml.cli.home' ); - - logBox = {}; - - - // Define Appenders - logBox.appenders = { - fileAppender = { - class="wirebox.system.logging.appenders.RollingFileAppender", - properties = { - fileMaxArchives = 5, - filename = "commandbox", - filepath = homeDir & "/logs" - }, - async=true - }, - ANSIConsoleAppender = { - class="commandbox.system.util.ANSIConsoleAppender" - } - }; - - // Root Logger - logBox.root = { - levelmax="INFO", - levelMin="FATAL", - appenders="fileAppender" - }; - - logBox.categories = { - "console" = { appenders="ANSIConsoleAppender" } - }; - - } +/** +********************************************************************************* +* Copyright Since 2005 ColdBox Platform by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* LogBox Configuration +*/ +component { + + function configure(){ + var system = createObject( "java", "java.lang.System" ); + var homeDir = isNull( system.getProperty('cfml.cli.home') ) ? + system.getProperty( 'user.home' ) & "/.CommandBox/" : system.getProperty( 'cfml.cli.home' ); + + logBox = {}; + + + // Define Appenders + logBox.appenders = { + fileAppender = { + class="wirebox.system.logging.appenders.RollingFileAppender", + properties = { + fileMaxArchives = 5, + filename = "commandbox", + filepath = homeDir & "/logs" + }, + async=true + }, + ANSIConsoleAppender = { + class="commandbox.system.util.ANSIConsoleAppender" + } + }; + + // Root Logger + logBox.root = { + levelmax="INFO", + levelMin="FATAL", + appenders="fileAppender" + }; + + logBox.categories = { + "console" = { appenders="ANSIConsoleAppender" } + }; + + } } \ No newline at end of file diff --git a/src/cfml/system/config/WireBox.cfc b/src/cfml/system/config/WireBox.cfc index 60b231d9a..2db2fe537 100644 --- a/src/cfml/system/config/WireBox.cfc +++ b/src/cfml/system/config/WireBox.cfc @@ -25,7 +25,7 @@ component extends="wirebox.system.ioc.config.Binder" { wirebox.listeners = [ // { class="", name="", properties={} } ]; - + // LogBox wirebox.logBoxConfig = "commandbox.system.config.LogBox"; @@ -66,7 +66,7 @@ component extends="wirebox.system.ioc.config.Binder" { map( 'ortusArtifactsURL@constants' ).toValue( ortusArtifactsURL ); map( 'ortusPRDArtifactsURL@constants' ).toValue( ortusPRDArtifactsURL ); map( 'rewritesDefaultConfig@constants' ).toValue( "#homeDir#/cfml/system/config/urlrewrite.xml" ); - + // Map Java Classes map( 'commandHistoryFile@java' ).toJava( "jline.console.history.FileHistory" ) .initWith( createObject( "java", "java.io.File" ).init( commandHistoryFile ) ) @@ -79,7 +79,7 @@ component extends="wirebox.system.ioc.config.Binder" { map( 'REPLTagHistoryFile@java' ).toJava( "jline.console.history.FileHistory" ) .initWith( createObject( "java", "java.io.File" ).init( REPLTagHistoryFile ) ) .asSingleton(); - + // Map Directories mapDirectory( '/commandbox/system/services' ); mapDirectory( '/commandbox/system/util' ); diff --git a/src/cfml/system/endpoints/CFLib-ColdBox.cfc b/src/cfml/system/endpoints/CFLib-ColdBox.cfc index 4dd3f5c3f..2fafe9a61 100644 --- a/src/cfml/system/endpoints/CFLib-ColdBox.cfc +++ b/src/cfml/system/endpoints/CFLib-ColdBox.cfc @@ -9,29 +9,29 @@ * and store them as a ColdBox module, wrapping the UDF in a CFC so it can be injected. */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.CFLib" singleton { - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'CFLib-ColdBox' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { // Retrieve the UDF in a single .cfm file var tempFolder = super.resolvePackage( argumentCollection = arguments ); - var tempFile = tempFolder & '/' & package & '.cfm'; - + var tempFile = tempFolder & '/' & package & '.cfm'; + // Turn this baby into a module! createModuleConfig( tempFolder ); createModel( tempFolder, tempFile ); createBoxJSON( tempFolder, arguments.package ); - + // Return the new and improved folder return tempFolder; } - + private function createModuleConfig( required string tempFolder ) { var fileContents = 'component { this.modelNamespace="cflib"; @@ -39,17 +39,17 @@ component accessors="true" implements="IEndpoint" extends="commandbox.system.end }'; fileWrite( arguments.tempFolder & '/ModuleConfig.cfc', fileContents ); } - + private function createModel( required string tempFolder, required string tempFile ) { var modelsDir = arguments.tempFolder & '/models'; var funcContent = fileRead( arguments.tempFile ); directoryCreate( modelsDir, true, true ); - + var modelContent = '#chr(13)##chr(10)#' & funcContent & '#chr(13)##chr(10)#'; fileWrite( modelsDir & '/' & replaceNoCase( listLast( arguments.tempFile, '/' ), '.cfm', '.cfc' ), modelContent ); fileDelete( arguments.tempFile ); } - + private function createBoxJSON( required string tempFolder, required string package ) { var fileContents = '{ "name"="#arguments.package#", @@ -59,7 +59,7 @@ component accessors="true" implements="IEndpoint" extends="commandbox.system.end "homepage"="http://www.cflib.org/udf/#arguments.package#", "documentation"="http://www.cflib.org/udf/#arguments.package#" }'; - fileWrite( arguments.tempFolder & '/box.json', fileContents ); + fileWrite( arguments.tempFolder & '/box.json', fileContents ); } } \ No newline at end of file diff --git a/src/cfml/system/endpoints/CFLib.cfc b/src/cfml/system/endpoints/CFLib.cfc index 33ab393b7..ca655b535 100644 --- a/src/cfml/system/endpoints/CFLib.cfc +++ b/src/cfml/system/endpoints/CFLib.cfc @@ -9,29 +9,29 @@ * install cflib:UDFName */ component accessors="true" implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="tempDir" inject="tempDir@constants"; property name="progressableDownloader" inject="ProgressableDownloader"; property name="progressBar" inject="ProgressBar"; property name="CR" inject="CR@constants"; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'CFLib' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - + var folderName = tempDir & '/' & 'temp#randRange( 1, 1000 )#'; var fullPath = folderName & '/' & package & '.cfm'; - + directoryCreate( folderName, true, true ); - + try { // Download File var result = progressableDownloader.download( @@ -49,8 +49,8 @@ component accessors="true" implements="IEndpoint" singleton { }; fixTags( fullPath ); - - return folderName; + + return folderName; } public function getDefaultName( required string package ) { @@ -62,7 +62,7 @@ component accessors="true" implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + return result; } @@ -74,7 +74,7 @@ component accessors="true" implements="IEndpoint" singleton { if( !findNoCase( '#chr(13)##chr(10)#' & fileContents & '#chr(13)##chr(10)#'; - fileWrite( arguments.fileName, fileContents ); + fileWrite( arguments.fileName, fileContents ); } } diff --git a/src/cfml/system/endpoints/File.cfc b/src/cfml/system/endpoints/File.cfc index 9e71bb06e..bb9c352bb 100644 --- a/src/cfml/system/endpoints/File.cfc +++ b/src/cfml/system/endpoints/File.cfc @@ -8,7 +8,7 @@ * I am the file endpoint. I get packages from a local file. */ component accessors="true" implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="tempDir" inject="tempDir@constants"; @@ -16,34 +16,34 @@ component accessors="true" implements="IEndpoint" singleton { property name="fileSystemUtil" inject="FileSystem"; property name="folderEndpoint" inject="commandbox.system.endpoints.Folder"; property name="semanticVersion" inject="provider:semanticVersion@semver"; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'file' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - - + + // Has file size? if( getFileInfo( package ).size <= 0 ) { throw( 'Cannot install file as it has a file size of 0.', 'endpointException', package ); } - + // Normalize slashes var packagePath = fileSystemUtil.resolvePath( "#variables.tempDir#/#createUUID()#" ); - + // Unzip to temp directory consoleLogger.info( "Decompressing..."); - + zip action="unzip" file="#package#" destination="#packagePath#" overwrite="true"; - + // Defer to folder endpoint return folderEndpoint.resolvePackage( packagePath, arguments.verbose ); - + } /** @@ -59,28 +59,28 @@ component accessors="true" implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + if( fileExists( arguments.package ) ) { - + var boxJSONPath = 'zip://' & arguments.package & '!box.json'; - + // If the packge has a box.json in the root... if( fileExists( boxJSONPath ) ) { - + // ...Read it. var boxJSON = fileRead( boxJSONPath ); - + // Validate the file is valid JSOn if( isJSON( boxJSON ) ) { // Merge this JSON with defaults boxJSON = packageService.newPackageDescriptor( deserializeJSON( boxJSON ) ); result.isOutdated = semanticVersion.isNew( current=arguments.version, target=boxJSON.version ); result.version = boxJSON.version; - } // isJSON + } // isJSON } // box.json exists } // zip exists - + return result; } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/Folder.cfc b/src/cfml/system/endpoints/Folder.cfc index 9284b0086..925d71140 100644 --- a/src/cfml/system/endpoints/Folder.cfc +++ b/src/cfml/system/endpoints/Folder.cfc @@ -8,23 +8,23 @@ * I am the folder endpoint. I get packages from a local folder. */ component accessors="true" implements="IEndpoint" singleton { - + // DI property name="packageService" inject="packageService"; property name="semanticVersion" inject="provider:semanticVersion@semver"; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'folder' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - + package = packageService.findPackageRoot( package ); - + return package; } @@ -41,14 +41,14 @@ component accessors="true" implements="IEndpoint" singleton { isOutdated = false, version = 'unknown' }; - + if( directoryExists( arguments.package ) ) { var boxJSON = packageService.readPackageDescriptor( arguments.package ); result.isOutdated = semanticVersion.isNew( current=arguments.version, target=boxJSON.version ); result.version = boxJSON.version; } - + return result; } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index e1a47871b..be8f3588e 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -8,7 +8,7 @@ * I am the ForgeBox endpoint. I wrap CFML's coolest package repository EVER! */ component accessors="true" implements="IEndpointInteractive" singleton { - + // DI property name="CR" inject="CR@constants"; property name="consoleLogger" inject="logbox:logger:console"; @@ -21,10 +21,10 @@ component accessors="true" implements="IEndpointInteractive" singleton { property name="endpointService" inject="endpointService"; property name="fileSystemUtil" inject="FileSystem"; property name="fileEndpoint" inject="commandbox.system.endpoints.File"; - + // Properties property name="namePrefixes" type="string"; - + /** * Constructor */ @@ -32,7 +32,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { setNamePrefixes( 'forgebox' ); return this; } - + /** * Resolve a package * @package The package to resolve @@ -42,19 +42,19 @@ component accessors="true" implements="IEndpointInteractive" singleton { var slug = parseSlug( arguments.package ); var version = parseVersion( arguments.package ); var strVersion = semanticVersion.parseVersion( version ); - + // If we have a specific version and it exists in artifacts and this isn't a snapshot build, use it. Otherwise, to ForgeBox!! if( semanticVersion.isExactVersion( version ) && artifactService.artifactExists( slug, version ) && strVersion.preReleaseID != 'snapshot' ) { - consoleLogger.info( "Package found in local artifacts!"); + consoleLogger.info( "Package found in local artifacts!"); // Install the package - var thisArtifactPath = artifactService.getArtifactPath( slug, version ); + var thisArtifactPath = artifactService.getArtifactPath( slug, version ); // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); } else { - return getPackage( slug, version, arguments.verbose ); + return getPackage( slug, version, arguments.verbose ); } } - + /** * Get default name for a package * @package The package to resolve @@ -80,25 +80,25 @@ component accessors="true" implements="IEndpointInteractive" singleton { isOutdated = false, version = '' }; - - // Only bother checking if we have a version range. If an exact version is stored in + + // Only bother checking if we have a version range. If an exact version is stored in // box.json, we're never going to update it anyway. if( semanticVersion.isExactVersion( boxJSONversion ) ) { return result; } - - try { - + + try { + // Verify in ForgeBox var entryData = forgebox.getEntry( slug, APIToken ); - + } catch( forgebox var e ) { // This can include "expected" errors such as "Email already in use" throw( e.message, 'endpointException', e.detail ); } - + entryData.versions.sort( function( a, b ) { return semanticVersion.compare( b.version, a.version ) } ); - + var found = false; for( var thisVersion in entryData.versions ) { // Look for a version on ForgeBox that satisfies our range @@ -107,21 +107,21 @@ component accessors="true" implements="IEndpointInteractive" singleton { found = true; // Only flag it as outdated if the matching version is newer. if( semanticVersion.isNew( current=version, target=thisVersion.version, checkBuildID=false ) ) { - result.isOutdated = true; - } + result.isOutdated = true; + } break; } } - + if( !found ) { // If we requsted stable and all releases are pre-release, just grab the latest if( boxJSONversion == 'stable' && arrayLen( entryData.versions ) ) { result.version = entryData.versions[ 1 ].version; - result.isOutdated = true; + result.isOutdated = true; } } - - return result; + + return result; } /** @@ -139,12 +139,12 @@ component accessors="true" implements="IEndpointInteractive" singleton { required string password, required string email, required string firstName, - required string lastName + required string lastName ){ var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + try { - + var results = forgebox.register( username = arguments.username, password = arguments.password, @@ -154,13 +154,13 @@ component accessors="true" implements="IEndpointInteractive" singleton { APIToken = APIToken ); return results.APIToken; - + } catch( forgebox var e ) { // This can include "expected" errors such as "Email already in use" throw( e.message, 'endpointException', e.detail ); } } - + /** * Login a user into ForgeBox * @username The username @@ -170,32 +170,32 @@ component accessors="true" implements="IEndpointInteractive" singleton { */ public string function login( required string userName, required string password ) { try { - + var results = forgebox.login( argumentCollection=arguments ); return results.APIToken; - + } catch( forgebox var e ) { // This can include "expected" errors such as "Email already in use" throw( e.message, 'endpointException', e.detail ); } } - + /** * Publish a package in ForgeBox * @path The path to publish */ public function publish( required string path ) { - + if( !packageService.isPackage( arguments.path ) ) { - throw( - 'Sorry but [#arguments.path#] isn''t a package.', - 'endpointException', - 'Please double check you''re in the correct directory or use "package init" to turn your directory into a package.' - ); + throw( + 'Sorry but [#arguments.path#] isn''t a package.', + 'endpointException', + 'Please double check you''re in the correct directory or use "package init" to turn your directory into a package.' + ); } - + var boxJSON = packageService.readPackageDescriptor( arguments.path ); - + var props = {} props.slug = boxJSON.slug; props.version = boxJSON.version; @@ -208,7 +208,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { props.changeLog = boxJSON.changeLog; props.changeLogFormat = 'text'; props.APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + // Look for readme, instruction, and changelog files for( var item in [ { variable : 'description', file : 'readme' }, @@ -226,41 +226,41 @@ component accessors="true" implements="IEndpointInteractive" singleton { } } } - - try { + + try { consoleLogger.warn( "Sending package information to ForgeBox, please wait..." ); forgebox.publish( argumentCollection=props ); - + consoleLogger.info( "Package is alive, you can visit it here: #forgebox.getEndpointURL()#/view/#boxJSON.slug#" ); } catch( forgebox var e ) { // This can include "expected" errors such as "User not authenticated" throw( e.message, 'endpointException', e.detail ); } } - + /** * Unpublish a package in ForgeBox * @path The path to publish * @version The version to publish */ public function unpublish( required string path, string version='') { - + if( !packageService.isPackage( arguments.path ) ) { - throw( - 'Sorry but [#arguments.path#] isn''t a package.', - 'endpointException', - 'Please double check you''re in the correct directory.' - ); + throw( + 'Sorry but [#arguments.path#] isn''t a package.', + 'endpointException', + 'Please double check you''re in the correct directory.' + ); } - + var boxJSON = packageService.readPackageDescriptor( arguments.path ); - - try { + + try { consoleLogger.warn( "Unpublishing package [#boxJSON.slug##( len( arguments.version ) ? '@' : '' )##arguments.version#] from ForgeBox, please wait..." ); forgebox.unpublish( boxJSON.slug, arguments.version, configService.getSetting( 'endpoints.forgebox.APIToken', '' ) ); - + } catch( forgebox var e ) { // This can include "expected" errors such as "User not authenticated" throw( e.message, 'endpointException', e.detail ); @@ -282,27 +282,27 @@ component accessors="true" implements="IEndpointInteractive" singleton { // This can include "expected" errors such as "User not authenticated" throw( e.message, 'endpointException', e.detail ); } - + arguments.entryData.versions.sort( function( a, b ) { return semanticVersion.compare( b.version, a.version ) } ); - + var found = false; for( var thisVersion in arguments.entryData.versions ) { if( semanticVersion.satisfies( thisVersion.version, arguments.version ) ) { return thisVersion; } } - + // If we requsted stable and all releases are pre-release, just grab the latest if( arguments.version == 'stable' && arrayLen( arguments.entryData.versions ) ) { - return arguments.entryData.versions[ 1 ]; + return arguments.entryData.versions[ 1 ]; } else { - throw( 'Version [#arguments.version#] not found for package [#arguments.slug#].', 'endpointException', 'Available versions are [#arguments.entryData.versions.map( function( i ){ return ' ' & i.version; } ).toList()#]' ); + throw( 'Version [#arguments.version#] not found for package [#arguments.slug#].', 'endpointException', 'Available versions are [#arguments.entryData.versions.map( function( i ){ return ' ' & i.version; } ).toList()#]' ); } } - + /** * Parses just the slug portion out of an endpoint ID - * @package The full endpointID like foo@1.0.0 + * @package The full endpointID like foo@1.0.0 */ public function parseSlug( required string package ) { return listFirst( arguments.package, '@' ); @@ -310,7 +310,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { /** * Parses just the version portion out of an endpoint ID - * @package The full endpointID like foo@1.0.0 + * @package The full endpointID like foo@1.0.0 */ public function parseVersion( required string package ) { var version = 'stable'; @@ -323,7 +323,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { return version; } - + /****************************************** PRIVATE ******************************************/ /** @@ -332,108 +332,108 @@ component accessors="true" implements="IEndpointInteractive" singleton { * @version The package version * @verbose Verbose flag or silent, defaults to false */ - private function getPackage( slug, version, verbose=false ) { - + private function getPackage( slug, version, verbose=false ) { + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + try { // Info consoleLogger.warn( "Verifying package '#slug#' in ForgeBox, please wait..." ); - + var entryData = forgebox.getEntry( slug, APIToken ); - + // Verbose info if( arguments.verbose ){ consoleLogger.debug( "Package data retrieved: ", entryData ); } - + // entrylink,createdate,lname,isactive,installinstructions,typename,version,hits,coldboxversion,sourceurl,slug,homeurl,typeslug, // downloads,entryid,fname,changelog,updatedate,downloadurl,title,entryrating,summary,username,description,email - - if( !entryData.isActive ) { + + if( !entryData.isActive ) { throw( 'The ForgeBox entry [#entryData.title#] is inactive.', 'endpointException' ); } - + var satisfyingVersion = findSatisfyingVersion( slug, version, entryData ); arguments.version = satisfyingVersion.version; var downloadURL = satisfyingVersion.downloadURL; - + if( !len( downloadurl ) ) { throw( 'No download URL provided in ForgeBox. Manual install only.', 'endpointException' ); } - + consoleLogger.info( "Installing version [#arguments.version#]." ); - + try { forgeBox.recordInstall( arguments.slug, arguments.version, APIToken ); } catch( forgebox var e ) { consoleLogger.warn( e.message & CR & e.detail ); } - + var packageType = entryData.typeSlug; - + // Advice we found it consoleLogger.info( "Verified entry in ForgeBox: '#slug#'" ); - + var strVersion = semanticVersion.parseVersion( version ); - + // If the local artifact doesn't exist or it's a snapshot build, download and create it if( !artifactService.artifactExists( slug, version ) || strVersion.preReleaseID == 'snapshot' ) { - + // Test package location to see what endpoint we can refer to. var endpointData = endpointService.resolveEndpoint( downloadURL, 'fakePath' ); - + consoleLogger.info( "Deferring to [#endpointData.endpointName#] endpoint for ForgeBox entry [#slug#]..." ); - + var packagePath = endpointData.endpoint.resolvePackage( endpointData.package, arguments.verbose ); - + // Cheat for people who set a version, slug, or type in ForgeBox, but didn't put it in their box.json var boxJSON = packageService.readPackageDescriptorRaw( packagePath ); if( !structKeyExists( boxJSON, 'type' ) || !len( boxJSON.type ) ) { boxJSON.type = entryData.typeslug; } if( !structKeyExists( boxJSON, 'slug' ) || !len( boxJSON.slug ) ) { boxJSON.slug = entryData.slug; } if( !structKeyExists( boxJSON, 'version' ) || !len( boxJSON.version ) ) { boxJSON.version = version; } packageService.writePackageDescriptor( boxJSON, packagePath ); - + consoleLogger.info( "Storing download in artifact cache..." ); - + // Store it locally in the artfact cache artifactService.createArtifact( slug, version, packagePath ); - + consoleLogger.info( "Done." ); - + return packagePath; - + } else { consoleLogger.info( "Package found in local artifacts!"); - var thisArtifactPath = artifactService.getArtifactPath( slug, version ); + var thisArtifactPath = artifactService.getArtifactPath( slug, version ); // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); } - - + + } catch( forgebox var e ) { - + consoleLogger.error( "."); consoleLogger.error( "Aww man, ForgeBox isn't feeling well."); consoleLogger.debug( "#e.message# #e.detail#"); consoleLogger.error( "We're going to look in your local artifacts cache and see if one of those versions will work."); - + // See if there's something usable in the artifacts cache. If so, we'll use that version. var satisfyingVersion = artifactService.findSatisfyingVersion( slug, version ); - + if( len( satisfyingVersion ) ) { consoleLogger.info( "."); consoleLogger.info( "Sweet! We found a local version of [#satisfyingVersion#] that we can use in your artifacts."); consoleLogger.info( "."); - - var thisArtifactPath = artifactService.getArtifactPath( slug, satisfyingVersion ); + + var thisArtifactPath = artifactService.getArtifactPath( slug, satisfyingVersion ); // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); } else { throw( 'No satisfying version found for [#version#].', 'endpointException', 'Well, we tried as hard as we can. ForgeBox is unreachable and you don''t have a usable version in your local artifacts cache. Please try another version.' ); } - } + } } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/Git.cfc b/src/cfml/system/endpoints/Git.cfc index 9d82c1727..e06d588da 100644 --- a/src/cfml/system/endpoints/Git.cfc +++ b/src/cfml/system/endpoints/Git.cfc @@ -6,7 +6,7 @@ * @author Brad Wood, Luis Majano, Denny Valliant * * I am the Git endpoint. I get packages from a Git URL. -* +* * - git+ssh://git@github.com:user/repo.git#v1.0.27 * - git+https://login@github.com/user/repo.git * - git+http://login@github.com/user/repo.git @@ -21,7 +21,7 @@ * */ component accessors="true" implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="tempDir" inject="tempDir@constants"; @@ -30,18 +30,18 @@ component accessors="true" implements="IEndpoint" singleton { property name="progressableDownloader" inject="ProgressableDownloader"; property name="progressBar" inject="ProgressBar"; property name="system" inject="system@constants"; - - + + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'git' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - + var GitURL = replace( arguments.package, '//', '' ); GitURL = getProtocol() & GitURL; var branch = 'master'; @@ -52,55 +52,55 @@ component accessors="true" implements="IEndpoint" singleton { } consoleLogger.debug( 'Cloning Git URL [#GitURL#]' ); - + // The main Git API var Git = createObject( 'java', 'org.eclipse.jgit.api.Git' ); - + // Wrap up system out in a PrintWriter and create a progress monitor to track our clone var printWriter = createObject( 'java', 'java.io.PrintWriter' ).init( system.out, true ); var progressMonitor = createObject( 'java', 'org.eclipse.jgit.lib.TextProgressMonitor' ).init( printWriter ); - + // Temporary location to place the repo var localPath = createObject( 'java', 'java.io.File' ).init( "#tempDir#/git_#randRange( 1, 1000 )#" ); - + // This will trap the full java exceptions to work around this annoying behavior: // https://luceeserver.atlassian.net/browse/LDEV-454 var CommandCaller = createObject( 'java', 'com.ortussolutions.commandbox.jgit.CommandCaller' ).init(); - - try { + + try { // Clone the repo locally into a temp folder var cloneCommand = Git.cloneRepository() - .setURI( GitURL ) + .setURI( GitURL ) .setCloneSubmodules( true ) .setDirectory( localPath ) .setProgressMonitor( progressMonitor ); - + // Conditionally apply security var command = secureCloneCommand( cloneCommand ); // call with our special java wrapper local.result = CommandCaller.call( command ); - + // Get a list of all branches var branchListCommand = local.result.branchList(); var listModeAll = createObject( 'java', 'org.eclipse.jgit.api.ListBranchCommand$ListMode' ).ALL; var branchList = [].append( CommandCaller.call( branchListCommand.setListMode( listModeAll ) ), true ); branchList = branchList.map( function( ref ){ return ref.getName(); } ); - + if( arguments.verbose ){ consoleLogger.debug( 'Available branches are #branchList.toList()#' ); } - + // If the commit-ish looks like it's a branch, modify the ref's name. if( branchList.containsNoCase( branch ) ) { if( arguments.verbose ){ consoleLogger.debug( 'Commit-ish [#branch#] appears to be a branch.' ); } branch = 'origin/' & branch; } - + // Checkout branch, tag, or commit hash. CommandCaller.call( local.result.checkout().setName( branch ) ); - + } catch( any var e ) { // If the exception came from the Java call, this exception won't be null var theRealJavaException = CommandCaller.getException(); - + // If it's null, that just means some other CFML code must have blown chunks above. if( isNull( theRealJavaException ) ) { throw( message="Error Cloning Git repository", detail="#e.message#", type="endpointException"); @@ -111,10 +111,10 @@ component accessors="true" implements="IEndpoint" singleton { deepMessage &= '#theRealJavaException.toString()# #chr( 10 )#'; theRealJavaException = theRealJavaException.getCause() } while( !isNull( theRealJavaException ) ) - + throw( message="Error Cloning Git repository", detail="#deepMessage#", type="endpointException"); } - + } finally { // Release file system locks on the repo if( structKeyExists( local, 'result' ) ) { @@ -122,16 +122,16 @@ component accessors="true" implements="IEndpoint" singleton { result.close(); } } - + // Clean up a bit var gitFolder = localPath.getPath() & '/.git'; if( directoryExists( gitFolder ) ) { directoryDelete( gitFolder, true ); } - + // Defer to file endpoint return folderEndpoint.resolvePackage( localPath.getPath(), arguments.verbose ); - + } /** @@ -140,15 +140,15 @@ component accessors="true" implements="IEndpoint" singleton { public function getDefaultName( required string package ) { // Remove committ-ish var baseURL = listFirst( arguments.package, '##' ); - + // Find last segment of URL (may or may not be a repo name) var repoName = listLast( baseURL, '/' ); - + // Check for the "git" extension in URL if( listLast( repoName, '.' ) == 'git' ) { return listFirst( repoName, '.' ); } - return reReplaceNoCase( arguments.package, '[^a-zA-Z0-9]', '', 'all' ); + return reReplaceNoCase( arguments.package, '[^a-zA-Z0-9]', '', 'all' ); } private function getProtocol() { @@ -161,7 +161,7 @@ component accessors="true" implements="IEndpoint" singleton { return ""; } return prefix & '://'; - + } public function getUpdate( required string package, required string version, boolean verbose=false ) { @@ -169,7 +169,7 @@ component accessors="true" implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + return result; } diff --git a/src/cfml/system/endpoints/Git_HTTP.cfc b/src/cfml/system/endpoints/Git_HTTP.cfc index e3daa4c79..1b67bb967 100644 --- a/src/cfml/system/endpoints/Git_HTTP.cfc +++ b/src/cfml/system/endpoints/Git_HTTP.cfc @@ -8,13 +8,13 @@ * I am the git+http endpoint. */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.Git" singleton { - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'git+http' ); return this; } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/Git_HTTPS.cfc b/src/cfml/system/endpoints/Git_HTTPS.cfc index e7de81be6..363a0e287 100644 --- a/src/cfml/system/endpoints/Git_HTTPS.cfc +++ b/src/cfml/system/endpoints/Git_HTTPS.cfc @@ -8,13 +8,13 @@ * I am the git+https endpoint. */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.Git" singleton { - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'git+https' ); return this; } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/Git_SSH.cfc b/src/cfml/system/endpoints/Git_SSH.cfc index 22512f257..a9399c052 100644 --- a/src/cfml/system/endpoints/Git_SSH.cfc +++ b/src/cfml/system/endpoints/Git_SSH.cfc @@ -8,7 +8,7 @@ * I am the git+ssh endpoint. */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.Git" singleton { - + // Properties property name="namePrefixes" type="string"; @@ -16,11 +16,11 @@ component accessors="true" implements="IEndpoint" extends="commandbox.system.end setNamePrefixes( 'git+ssh' ); return this; } - + // Set SSH listener private function secureCloneCommand( required any cloneCommand ) { // This is our custom SSH callback - var SSHCallback = createObject( 'java', 'com.ortussolutions.commandbox.jgit.SSHCallback' ).init(); + var SSHCallback = createObject( 'java', 'com.ortussolutions.commandbox.jgit.SSHCallback' ).init(); cloneCommand.setTransportConfigCallback( SSHCallback ); return cloneCommand; } diff --git a/src/cfml/system/endpoints/Github.cfc b/src/cfml/system/endpoints/Github.cfc index 80aaf217c..fdbbdb9b6 100644 --- a/src/cfml/system/endpoints/Github.cfc +++ b/src/cfml/system/endpoints/Github.cfc @@ -5,18 +5,18 @@ ******************************************************************************** * @author Brad Wood, Luis Majano, Denny Valliant * -* I am the github endpoint. I install 'shortcut' packages listed as "user/repo[#committ-ish]" +* I am the github endpoint. I install 'shortcut' packages listed as "user/repo[#committ-ish]" */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.Git" singleton { - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'github' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { if( listLen( arguments.package, '##' ) == 2 ) { return super.resolvePackage( '//github.com/' & listFirst( arguments.package, '##' ) & '.git' & '##' & listLast( arguments.package, '##' ), arguments.verbose ); @@ -24,11 +24,11 @@ component accessors="true" implements="IEndpoint" extends="commandbox.system.end return super.resolvePackage( '//github.com/' & arguments.package & '.git', arguments.verbose ); } } - + public function getDefaultName( required string package ) { // Remove committ-ish var baseURL = listFirst( arguments.package, '##' ); - + // Find last segment of URL (may or may not be a repo name) return listLast( baseURL, '/' ); } diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index 6ecf863ee..513512108 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -8,7 +8,7 @@ * I am the HTTP endpoint. I get packages from an HTTP URL. */ component accessors=true implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="tempDir" inject="tempDir@constants"; @@ -17,22 +17,22 @@ component accessors=true implements="IEndpoint" singleton { property name="progressableDownloader" inject="ProgressableDownloader"; property name="progressBar" inject="ProgressBar"; property name="CR" inject="CR@constants"; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'HTTP' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - + var fileName = 'temp#randRange( 1, 1000 )#.zip'; - var fullPath = tempDir & '/' & fileName; - + var fullPath = tempDir & '/' & fileName; + consoleLogger.info( "Downloading [#getNamePrefixes() & ':' & package#]" ); - + try { // Download File var result = progressableDownloader.download( @@ -51,28 +51,28 @@ component accessors=true implements="IEndpoint" singleton { // Defer to file endpoint return fileEndpoint.resolvePackage( fullPath, arguments.verbose ); - + } public function getDefaultName( required string package ) { - + // strip query string var baseURL = listFirst( arguments.package, '?' ); - + // Github zip downloads tend to be called useless things like "master" // https://github.com/Ortus-Solutions/commandbox-docs/archive/master.zip - if( baseURL contains 'github.com' ) { + if( baseURL contains 'github.com' ) { // Ortus-Solutions/commandbox-docs/archive/master.zip var path = mid( baseURL, findNoCase( 'github.com', baseURL ) + 10, len( baseURL ) ); if( listLen( path, '/' ) >= 2 ) { // commandbox-docs - return listGetAt( path, 2, '/' ); + return listGetAt( path, 2, '/' ); } - } - + } + // Find last segment of URL (may or may not be a file) var fileName = listLast( baseURL, '/' ); - + // Check for file extension in URL var fileNameListLen = listLen( fileName, '.' ); if( fileNameListLen > 1 && listLast( fileName, '.' ) == 'zip' ) { @@ -86,7 +86,7 @@ component accessors=true implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + return result; } diff --git a/src/cfml/system/endpoints/HTTPS.cfc b/src/cfml/system/endpoints/HTTPS.cfc index 5195108fa..693ec1a9d 100644 --- a/src/cfml/system/endpoints/HTTPS.cfc +++ b/src/cfml/system/endpoints/HTTPS.cfc @@ -8,13 +8,13 @@ * I am the HTTPS endpoint. I get packages from an HTTPS URL. */ component accessors="true" implements="IEndpoint" extends="commandbox.system.endpoints.HTTP" singleton { - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'HTTPS' ); return this; } - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/IEndpoint.cfc b/src/cfml/system/endpoints/IEndpoint.cfc index 4ee66da20..4d3149e8e 100644 --- a/src/cfml/system/endpoints/IEndpoint.cfc +++ b/src/cfml/system/endpoints/IEndpoint.cfc @@ -8,10 +8,10 @@ * I am an endpoint. I can retreive packages for you. */ interface { - + /** * Accepts the name of a package, retrieves it, and returns a local folder path where the package is - * + * * @throws endpointException */ public string function resolvePackage( required string package, boolean verbose=false ); @@ -31,7 +31,7 @@ interface { * isOutdated = false, * version = '' * } - * + * * @throws endpointException */ public function getUpdate( required string package, required string version, boolean verbose=false ); diff --git a/src/cfml/system/endpoints/IEndpointInteractive.cfc b/src/cfml/system/endpoints/IEndpointInteractive.cfc index 9ab4ac8fe..d053c0fb3 100644 --- a/src/cfml/system/endpoints/IEndpointInteractive.cfc +++ b/src/cfml/system/endpoints/IEndpointInteractive.cfc @@ -5,11 +5,11 @@ ******************************************************************************** * @author Brad Wood, Luis Majano, Denny Valliant * -* I am an interactive endpoint. That means I can not only resolve packages, +* I am an interactive endpoint. That means I can not only resolve packages, * but be logged into and can have packages published to me. */ interface extends="IEndpoint" { - + // Returns access token public string function createUser( required string username, @@ -17,12 +17,12 @@ interface extends="IEndpoint" { required string email, required string firstName, required string lastName ); - + // Returns access token public string function login( required string userName, required string password ); - + public function publish( required string path ); - + public function unpublish( required string path, string version='' ); - + } \ No newline at end of file diff --git a/src/cfml/system/endpoints/Jar.cfc b/src/cfml/system/endpoints/Jar.cfc index dfd02e86b..251ce4f42 100644 --- a/src/cfml/system/endpoints/Jar.cfc +++ b/src/cfml/system/endpoints/Jar.cfc @@ -9,7 +9,7 @@ * I will spoof a package around the jar so CommandBox doesn't try to unzip the jar itself. */ component accessors=true implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="tempDir" inject="tempDir@constants"; @@ -17,24 +17,24 @@ component accessors=true implements="IEndpoint" singleton { property name="progressBar" inject="ProgressBar"; property name="CR" inject="CR@constants"; property name='formatterUtil' inject='formatter'; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'jar' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { - + var folderName = tempDir & '/' & 'temp#randRange( 1, 1000 )#'; directoryCreate( folderName ); var fullJarPath = folderName & '/' & getDefaultName( package ) & '.jar'; var fullBoxJSONPath = folderName & '/box.json'; - + consoleLogger.info( "Downloading [#package#]" ); - + try { // Download File var result = progressableDownloader.download( @@ -60,25 +60,25 @@ component accessors=true implements="IEndpoint" singleton { 'type' : 'jars' }; fileWrite( fullBoxJSONPath, formatterUtil.formatJSON( boxJSON ) ); - + // Here is where our alleged so-called "package" lives. return folderName; - + } public function getDefaultName( required string package ) { - + var baseURL = arguments.package; - + // strip query string, unless it possibly contains .jar like so: // https://search.maven.org/remotecontent?filepath=jline/jline/3.0.0.M1/jline-3.0.0.M1.jar if( !right( arguments.package, 4 ) == '.jar' ) { baseURL = listFirst( arguments.package, '?' ); } - + // Find last segment of URL (may or may not be a file) var fileName = listLast( baseURL, '/' ); - + // Check for file extension in URL var fileNameListLen = listLen( fileName, '.' ); if( fileNameListLen > 1 && listLast( fileName, '.' ) == 'jar' ) { @@ -93,7 +93,7 @@ component accessors=true implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + return result; } diff --git a/src/cfml/system/endpoints/RIAForge.cfc b/src/cfml/system/endpoints/RIAForge.cfc index f43e0f6df..9ae533918 100644 --- a/src/cfml/system/endpoints/RIAForge.cfc +++ b/src/cfml/system/endpoints/RIAForge.cfc @@ -9,19 +9,19 @@ * install riaforge:projectURLSlug */ component accessors="true" implements="IEndpoint" singleton { - + // DI property name="consoleLogger" inject="logbox:logger:console"; property name="HTTPEndpoint" inject="commandbox.system.endpoints.HTTP"; - + // Properties property name="namePrefixes" type="string"; - + function init() { setNamePrefixes( 'RIAForge' ); return this; } - + public string function resolvePackage( required string package, boolean verbose=false ) { // Defer to HTTP endpoint // This assumes that the download URL will point to a zip file. If not, all bets are off. @@ -37,7 +37,7 @@ component accessors="true" implements="IEndpoint" singleton { isOutdated = true, version = 'unknown' }; - + return result; } diff --git a/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc b/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc index c0cf40145..9ede71090 100644 --- a/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc +++ b/src/cfml/system/modules/JSONPrettyPrint/ModuleConfig.cfc @@ -1,5 +1,5 @@ component { - + this.name = "JSONPrettyPrint"; this.author = ""; this.webUrl = "https://github.com//JSONPrettyPrint"; diff --git a/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc b/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc index f0b1e042e..c5e4fa088 100644 --- a/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc +++ b/src/cfml/system/modules/JSONPrettyPrint/models/JSONPrettyPrint.cfc @@ -4,7 +4,7 @@ * www.coldbox.org | www.ortussolutions.com ******************************************************************************** * @author Brad Wood, Luis Majano -* +* */ component accessors="true" singleton alias='JSONPrettyPrint' { @@ -13,12 +13,12 @@ component accessors="true" singleton alias='JSONPrettyPrint' { * @json.hint A string containing JSON, or a complex value that can be serialized to JSON **/ public function formatJson( json ) { - + // Overload this method to accept a struct or array if( !isSimpleValue( arguments.json ) ) { arguments.json = serializeJSON( arguments.json ); } - + var retval = createObject("java","java.lang.StringBuilder").init(''); var str = json; var pos = 0; @@ -31,35 +31,35 @@ component accessors="true" singleton alias='JSONPrettyPrint' { for (var i=0; i 0 ); } diff --git a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc index e5d6df223..c40058688 100644 --- a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc +++ b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc @@ -2,12 +2,12 @@ * I am a new Model Object */ component accessors="true"{ - + // Properties property name='javaPropertyFile'; property name='path'; property name='syncedNames'; - + /** * Constructor @@ -17,7 +17,7 @@ component accessors="true"{ setJavaPropertyFile( createObject( 'java', 'java.util.Properties' ).init() ); return this; } - + /** * load */ @@ -28,17 +28,17 @@ component accessors="true"{ var propertyFile = getJavaPropertyFile(); propertyFile.load( BOMfis ); BOMfis.close(); - - + + var props = propertyFile.propertyNames(); var syncedNames = getSyncedNames(); while( props.hasMoreElements() ) { var prop = props.nextElement(); this[ prop ] = get( prop ); - syncedNames.append( prop ); + syncedNames.append( prop ); } setSyncedNames( syncedNames ); - + return this; } @@ -47,16 +47,16 @@ component accessors="true"{ */ function store( string path=variables.path ){ syncProperties(); - + if( !fileExists( arguments.path ) ) { directoryCreate( getDirectoryFromPath( arguments.path ), true, true ); fileWrite( arguments.path, '' ); } - + var fos = CreateObject( 'java', 'java.io.FileOutputStream' ).init( expandPath( arguments.path ) ); getJavaPropertyFile().store( fos, '' ); fos.close(); - + return this; } @@ -65,7 +65,7 @@ component accessors="true"{ */ function get( required string name, string defaultValue ){ if( structKeyExists( arguments, 'defaultValue' ) ) { - return getJavaPropertyFile().getProperty( name, defaultValue ); + return getJavaPropertyFile().getProperty( name, defaultValue ); } else if( exists( name ) ) { return getJavaPropertyFile().getProperty( name ); } else { @@ -78,14 +78,14 @@ component accessors="true"{ */ function set( required string name, required string value ){ getJavaPropertyFile().setProperty( name, value ); - + var syncedNames = getSyncedNames(); this[ name ] = value; if( !arrayContains( syncedNames, name ) ){ syncedNames.append( name ); } setSyncedNames( syncedNames ); - + return this; } @@ -95,7 +95,7 @@ component accessors="true"{ function remove( required string name ){ if( exists( name ) ) { getJavaPropertyFile().remove( name ); - + var syncedNames = getSyncedNames(); if( arrayFind( syncedNames, name ) ){ syncedNames.deleteAt( arrayFind( syncedNames, name ) ); @@ -122,7 +122,7 @@ component accessors="true"{ structAppend( result, getJavaPropertyFile() ); return result; } - + /** * Keeps public properties in sync with Java object */ @@ -130,7 +130,7 @@ component accessors="true"{ var syncedNames = getSyncedNames(); var ignore = listToArray( 'init,load,store,get,set,exists,remove,exists,getAsStruct,$mixed' ); var propertyFile = getJavaPropertyFile(); - + // This CFC's public properties for( var prop in this ) { // Set any new/updated properties in, excluding actual methods and non-simple values @@ -138,7 +138,7 @@ component accessors="true"{ set( prop, this[ prop ] ); } } - + // All the properties in the Java object var props = propertyFile.propertyNames(); while( props.hasMoreElements() ) { @@ -148,7 +148,7 @@ component accessors="true"{ remove( prop ); } } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules/semver/ModuleConfig.cfc b/src/cfml/system/modules/semver/ModuleConfig.cfc index b402a68d0..b61b916d3 100644 --- a/src/cfml/system/modules/semver/ModuleConfig.cfc +++ b/src/cfml/system/modules/semver/ModuleConfig.cfc @@ -1,7 +1,7 @@ component { - + function configure() { - + } - + } \ No newline at end of file diff --git a/src/cfml/system/modules/semver/models/SemanticVersion.cfc b/src/cfml/system/modules/semver/models/SemanticVersion.cfc index 585e7900c..5bbdddd77 100644 --- a/src/cfml/system/modules/semver/models/SemanticVersion.cfc +++ b/src/cfml/system/modules/semver/models/SemanticVersion.cfc @@ -1,4 +1,4 @@ -/** +/** ******************************************************************************** Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp www.coldbox.org | www.luismajano.com | www.ortussolutions.com @@ -10,7 +10,7 @@ www.coldbox.org | www.luismajano.com | www.ortussolutions.com * https://github.com/npm/node-semver */ component singleton{ - + /** * Constructor */ @@ -23,15 +23,15 @@ component singleton{ } function compare( - required string current, + required string current, required string target, boolean checkBuildID=true ) { - + // versions are identical if( isEQ( arguments.current, arguments.target, checkBuildID ) ) { return 0; } - + // first is 'smaller' than the second if( isNew( arguments.current, arguments.target, checkBuildID ) ) { return -1; @@ -39,19 +39,19 @@ component singleton{ } else { return 1; } - + } /** * Checks if target version is a newer semantic version than the passed current version - * Note: To confirm to semvar, I think this needs to defer to gt(). + * Note: To confirm to semvar, I think this needs to defer to gt(). * @current The current version of the system * @target The newer version received * @checkBuildID If true it will check build equality, else it will ignore it - * + * */ - boolean function isNew( - required string current, + boolean function isNew( + required string current, required string target, boolean checkBuildID=true ){ @@ -79,7 +79,7 @@ component singleton{ return true; } - // A little hacky, but less code than what I had. + // A little hacky, but less code than what I had. // Basically, an empty pre release ID needs to sort AFTER a non-empty one. if( !len( target.preReleaseID ) ) { target.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } if( !len( current.preReleaseID ) ) { current.preReleaseID = 'zzzzzzzzzzzzzzzzzz'; } @@ -92,14 +92,14 @@ component singleton{ lcase( target.preReleaseID ) gt lcase( current.preReleaseID ) ) { return true; } - + // BuildID verification is turned on? if( !arguments.checkBuildID ){ return false; } // Build Check if( target.major eq current.major AND target.minor eq current.minor AND - target.revision eq current.revision AND + target.revision eq current.revision AND target.preReleaseID eq current.preReleaseID AND target.buildID gt current.buildID ){ return true; @@ -118,26 +118,26 @@ component singleton{ /** * Decides whether a version satisfies a range - * + * */ boolean function satisfies( required string version, required string range ){ - + arguments.version = clean( arguments.version ); - + if( range == 'be' ) { return true; } - + if( range == 'stable' && !isPreRelease( version ) ) { return true; } else if( range == 'stable' ) { return false; } - // An array of comparator sets. At least one of the comparator sets needs to + // An array of comparator sets. At least one of the comparator sets needs to // satisfy. Each comparator of a given comparator set must match for the set to pass. var semverRange = buildRange( range ); - + // Only one of our comparatorSets in the range need to match for( var comparatorSet in semverRange ) { // If the version we're inspecting is a pre-release, don't consider it unless at least one comparator in this @@ -155,21 +155,21 @@ component singleton{ // If this comparatorSet passed, we've seen all we need to see if( setResult ) { return true; } } - + // If we made it here, none of the comparatorSets in our range matched return false; - - + + return isEQ( arguments.version, arguments.range, false ); } - + private function evaluateComparator( required struct comparator, version ) { switch( comparator.operator ) { case "<": - return isNew( arguments.version, comparator.version, false ); + return isNew( arguments.version, comparator.version, false ); break; case "<=": - return isNew( arguments.version, comparator.version, false ) || isEq( comparator.version, arguments.version, false ); + return isNew( arguments.version, comparator.version, false ) || isEq( comparator.version, arguments.version, false ); break; case ">": return isNew( comparator.version, arguments.version, false ); @@ -180,11 +180,11 @@ component singleton{ case "=": return isEq( comparator.version, arguments.version, false ); break; - default: + default: return false; } } - + private function interestedInPreReleasesOfThisVersion( required array comparatorSet, required string version ) { var sVersion = parseVersion( arguments.version ); // Look at each comparator @@ -197,43 +197,43 @@ component singleton{ return true; } } - return false; + return false; } - + private function buildRange( required string range ) { // A character that I hope will never be part of an actual range so split easier. // Comprator sets inside a range are delimited by " || " arguments.range = replaceNoCase( arguments.range, ' || ', '•', 'all' ); var semverRange = listToArray( arguments.range, '•' ); - + // An empty range becomes * if( !arrayLen( semverRange ) ) { semverRange = [ '*' ]; } - + // Loop over each comparator set and parse semverRange = semverRange.map( function( i ) { return buildComparatorSet( i ); } ); - + return semverRange; } private function buildComparatorSet( required string set ) { var comparatorSet = []; - + // Check for a hyphen range if( set contains ' - ' ) { set = replaceNoCase( set, ' - ', '•', 'all' ); var lowerBound = listFirst( set, '•' ); var upperBound = listLast( set, '•' ); - + lowerBound = replaceNoCase( lowerBound, '*', 'x', 'all' ); upperBound = replaceNoCase( upperBound, '*', 'x', 'all' ); - + sVersion = parseVersion( lowerBound, 'x' ); - - comparatorSet.append( + + comparatorSet.append( expandXRanges( { operator : '>=', sVersion : sVersion, @@ -241,10 +241,10 @@ component singleton{ } ), true ); - + sVersion = parseVersion( upperBound, 'x' ); - - comparatorSet.append( + + comparatorSet.append( expandXRanges( { operator : '<=', sVersion : sVersion, @@ -252,16 +252,16 @@ component singleton{ } ), true ); - + return comparatorSet; } - + // Comparators are delimited by whitespace for( var comparator in listToArray( set, ' ' ) ) { - + // standardize * to x comparator = replaceNoCase( comparator, '*', 'x', 'all' ); - // >=1.2.3 + // >=1.2.3 if( comparator.startsWith( '>=' ) ) { var version = right( comparator, len( comparator )-2 ); var operator = '>='; @@ -294,11 +294,11 @@ component singleton{ var version = comparator; var operator = '='; } - + // Missing bits become x. So 1.3 becomes 1.3.x sVersion = parseVersion( version, 'x' ); comparatorSet.append( - // Convert 1.x into multiple comparators + // Convert 1.x into multiple comparators expandXRanges( { operator : operator, sVersion : sVersion, @@ -306,127 +306,127 @@ component singleton{ } ), true ); - + } - + return comparatorSet; } private function expandXRanges( required struct sComparator ) { var comparatorSet = []; - + switch( sComparator.operator ) { case "<": // <1.1.x becomes <1.1.0 // <1.x becomes <1.0.0 - + if( sComparator.sVersion.major == 'x' ) { sComparator.sVersion.major = '0'; } if( sComparator.sVersion.minor == 'x' ) { sComparator.sVersion.minor = '0'; } - if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } + if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); + comparatorSet.append( sComparator ); break; case "<=": // <=1.x becomes <2.0.0 if( sComparator.sVersion.minor == 'x' ) { - + sComparator.sVersion.minor = '0'; sComparator.sVersion.revision = '0'; sComparator.sVersion.major=val( sComparator.sVersion.major )+1; sComparator.operator = '<'; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + // <=1.0.x becomes <1.1.0 } else if( sComparator.sVersion.revision == 'x' ) { - + sComparator.sVersion.revision = '0'; sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; sComparator.operator = '<'; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + } else { - comparatorSet.append( sComparator ); - } + comparatorSet.append( sComparator ); + } break; case ">": // >1.x becomes >=2.0.0 if( sComparator.sVersion.minor == 'x' ) { - + sComparator.sVersion.minor = '0'; sComparator.sVersion.revision = '0'; sComparator.sVersion.major=val( sComparator.sVersion.major )+1; sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + // >1.0.x becomes >=1.1.0 } else if( sComparator.sVersion.revision == 'x' ) { - + sComparator.sVersion.revision = '0'; sComparator.sVersion.minor=val(sComparator.sVersion.minor)+1; sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + } else { - comparatorSet.append( sComparator ); + comparatorSet.append( sComparator ); } break; case ">=": // >=1.1.x becomes >=1.1.0 // >=1.x becomes >=1.0.0 - + if( sComparator.sVersion.major == 'x' ) { sComparator.sVersion.major = '0'; } if( sComparator.sVersion.minor == 'x' ) { sComparator.sVersion.minor = '0'; } - if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } + if( sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.revision = '0'; } sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); + comparatorSet.append( sComparator ); break; case "=": // * becomes >=0.0.0 if( sComparator.sVersion.major == 'x' ) { - + sComparator.sVersion.major = 0; sComparator.sVersion.minor = 0; sComparator.sVersion.revision = 0; sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + // 1.x becomes >=1.0.0 < 2.0.0 } else if ( sComparator.sVersion.minor == 'x' ) { - + sComparator.sVersion.minor = 0; sComparator.sVersion.revision = 0; sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( duplicate( sComparator ) ); - + sComparator.sVersion.major=val( sComparator.sVersion.major )+1; sComparator.operator = '<'; sComparator.version = getVersionAsString( sComparator.sVersion ); - comparatorSet.append( sComparator ); - - + comparatorSet.append( sComparator ); + + // 1.0.x becomes >=1.0.0 < 1.1.0 } else if( sComparator.sVersion.revision == 'x' ) { - + sComparator.sVersion.revision = 0; sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( duplicate( sComparator ) ); - + sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; sComparator.operator = '<'; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + } else { - comparatorSet.append( sComparator ); + comparatorSet.append( sComparator ); } break; case "~": @@ -439,26 +439,26 @@ component singleton{ // Recursivley handle as an X range comparatorSet.append( expandXRanges( sComparator ), true ); } else { - + // ~0.2.3 becomes >=0.2.3 <0.3.0 // ~1.2.3 becomes >=1.2.3 <1.3.0 sComparator.operator = '>='; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( duplicate( sComparator ) ); - + sComparator.operator = '<'; sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; sComparator.sVersion.revision = 0; sComparator.sVersion.preReleaseID = ''; sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - } + } break; case "^": // ^1.2.3 becomes >=1.2.3 <2.0.0 // ^0.2.3 becomes >=0.2.3 <0.3.0 // ^0.0.3 becomes >=0.0.3 <0.0.4 - // ^1.2.3-beta.2 becomes >=1.2.3-beta.2 <2.0.0 + // ^1.2.3-beta.2 becomes >=1.2.3-beta.2 <2.0.0 // ^1.2.x becomes >=1.2.0 <2.0.0 // ^0.0.x becomes >=0.0.0 <0.1.0 // ^0.0 becomes >=0.0.0 <0.1.0 @@ -468,34 +468,34 @@ component singleton{ sComparator2.operator = '>='; if( sComparator2.sVersion.major == 'x' ) { sComparator2.sVersion.major = '0'; } if( sComparator2.sVersion.minor == 'x' ) { sComparator2.sVersion.minor = '0'; } - if( sComparator2.sVersion.revision == 'x' ) { sComparator2.sVersion.revision = '0'; } + if( sComparator2.sVersion.revision == 'x' ) { sComparator2.sVersion.revision = '0'; } sComparator2.version = getVersionAsString( sComparator2.sVersion ); comparatorSet.append( sComparator2 ); - + sComparator.operator = '<'; sComparator.sVersion.preReleaseID = ''; if( sComparator.sVersion.major != 0 || sComparator.sVersion.minor == 'x' ) { sComparator.sVersion.major=val( sComparator.sVersion.major )+1; sComparator.sVersion.minor = 0; - sComparator.sVersion.revision = 0; + sComparator.sVersion.revision = 0; } else if( sComparator.sVersion.minor != 0 || sComparator.sVersion.revision == 'x' ) { sComparator.sVersion.minor=val( sComparator.sVersion.minor )+1; sComparator.sVersion.revision = 0; } else { sComparator.sVersion.revision=val( sComparator.sVersion.revision )+1; } - + sComparator.version = getVersionAsString( sComparator.sVersion ); comparatorSet.append( sComparator ); - + break; } - + return comparatorSet; } /** - * Parse the semantic version. If no minor found, then 0. If not revision found, then 0. + * Parse the semantic version. If no minor found, then 0. If not revision found, then 0. * If not Bleeding Edge bit, then empty. If not buildID, then 0 * @return struct:{major,minor,revision,preReleaseID,buildid} */ @@ -571,9 +571,9 @@ component singleton{ var current = parseVersionAsString( arguments.current, checkBuildID ); var target = parseVersionAsString( arguments.target, checkBuildID ); - return ( current == target ); + return ( current == target ); } - + /** * True if a specific version, false if a range that could match multiple versions * version.hint A string that contains a version or a range @@ -581,7 +581,7 @@ component singleton{ boolean function isExactVersion( required string version ) { // Default any missing pieces to "x" so "3" becomes "3.x.x". arguments.version = getVersionAsString (parseVersion( clean( arguments.version ), 'x' ) ); - + if( version contains '*' ) return false; if( version contains 'x.' ) return false; if( version contains '.x' ) return false; diff --git a/src/cfml/system/modules/string-similarity/ModuleConfig.cfc b/src/cfml/system/modules/string-similarity/ModuleConfig.cfc index b402a68d0..b61b916d3 100644 --- a/src/cfml/system/modules/string-similarity/ModuleConfig.cfc +++ b/src/cfml/system/modules/string-similarity/ModuleConfig.cfc @@ -1,7 +1,7 @@ component { - + function configure() { - + } - + } \ No newline at end of file diff --git a/src/cfml/system/modules/string-similarity/models/StringSimilarity.cfc b/src/cfml/system/modules/string-similarity/models/StringSimilarity.cfc index 83faabe7f..7f66f8b2d 100644 --- a/src/cfml/system/modules/string-similarity/models/StringSimilarity.cfc +++ b/src/cfml/system/modules/string-similarity/models/StringSimilarity.cfc @@ -1,5 +1,5 @@ component { - + /** * StringSimilarity * Brad Wood @@ -12,9 +12,9 @@ component { * s1: First string to be compared * s2: Second string to be compared * maxOffset: Average number of characters that s1 will deviate from s2 at any given point. - * This is used to control how far ahead the function looks to try and find the + * This is used to control how far ahead the function looks to try and find the * end of a piece of inserted text. Play with it to suit. - * + * * 2016-50-20 James Moberg SunStarMedia.com * - Added VAR scope to 15 variables. (Increased performance from 15-32 to 0-15ms.) * - Added generateHTML flag (optional). If disabled, will return empty s1 & s2 strings. @@ -45,13 +45,13 @@ component { // These two strings will contain the "highlighted" version _s1 = createObject("java","java.lang.StringBuffer").init(javacast("int",len(s1)*3)); _s2 = createObject("java","java.lang.StringBuffer").init(javacast("int",len(s2)*3)); - // These characters will surround differences in the strings + // These characters will surround differences in the strings // (Inserted into _s1 and _s2) h1 = ""; h2 = ""; } - // If both strings are empty - if (not len(trim(s1)) and not len(trim(s2))){ + // If both strings are empty + if (not len(trim(s1)) and not len(trim(s2))){ return return_struct; } // If s2 is empty, but s1 isn't @@ -85,17 +85,17 @@ component { } } // The next two charactes did not match - // Now we will go into a sub-loop while we attempt to + // Now we will go into a sub-loop while we attempt to // find our place again. We will only search as long as // our maxOffset allows us to. else { - // Don't reset the offsets, just back them up so you + // Don't reset the offsets, just back them up so you // have a point of reference old_offset1 = offset1; old_offset2 = offset2; _s1_deviation = ""; _s2_deviation = ""; - // Loop for as long as allowed by our offset + // Loop for as long as allowed by our offset // to see if we can match up again for (i = 0; i lt maxOffset; i=i+1){ next_s1 = mid(s1,c + offset1 + i+1,3); // Increments each time through. @@ -155,7 +155,7 @@ component { } } } - c=c+1; + c=c+1; } // Anything left at the end of s1 is extra if (generateHTML){ diff --git a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/clean.cfc b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/clean.cfc index 4cac08176..f51db62dd 100644 --- a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/clean.cfc +++ b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/clean.cfc @@ -17,18 +17,18 @@ component { // DI property name='artifactService' inject='artifactService'; - + /** * @force.hint Set to true to skip the prompt * **/ function run( boolean force=false ) { - + if( arguments.force || confirm( "Really wipe out the entire artifacts cache? [y/n]" ) ){ var results = artifactService.cleanArtifacts(); print.redLine( "Artifacts directory cleaned of '#results#' items." ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/help.cfc b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/help.cfc index e669cebb1..3a6a24445 100644 --- a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/help.cfc +++ b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/help.cfc @@ -1,7 +1,7 @@ component excludeFromHelp=true { - + function run() { - + print.line() .yellowLine( 'The artifacts command will allow you to control your artifacts cache.' ) .yellowLine( 'From Listing its content to removing and purging.' ) diff --git a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/list.cfc b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/list.cfc index 1ce8c346d..58bf5bdf0 100644 --- a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/list.cfc +++ b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/list.cfc @@ -9,33 +9,33 @@ * {code:bash} * artifacts list coldbox-platform * {code} - * + * **/ component { - + // DI - property name='artifactService' inject='artifactService'; + property name='artifactService' inject='artifactService'; /** * @package.hint An optional package to filter the results by **/ function run( package='' ) { var results = artifactService.listArtifacts( arguments.package ); - + if( !results.count() ) { print.yellowLine( 'No artifacts found in cache.' ); return; } - + print.boldBlueLine( "Found #results.count()# artifact(s) (#artifactService.getArtifactDir()#)" ); for( var package in results ) { print.boldCyanLine( package & " - #results[ package ].size()# version(s)" ); for( var ver in results[ package ] ) { - print.yellowLine( " *#ver#" ); + print.yellowLine( " *#ver#" ); } } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/remove.cfc b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/remove.cfc index 640ddbf9a..644fb8856 100644 --- a/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/remove.cfc +++ b/src/cfml/system/modules_app/artifacts-commands/commands/artifacts/remove.cfc @@ -21,12 +21,12 @@ * {code:bash} * artifacts remove package-name --force * {code} - * + * **/ component { // DI - property name='artifactService' inject='artifactService'; + property name='artifactService' inject='artifactService'; /** * @package.hint Comma-delimited list of packages to remove diff --git a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/config.cfc b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/config.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/config.cfc +++ b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/config.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/help.cfc b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/help.cfc index 27cd8e0a9..95b98d7d8 100644 --- a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/help.cfc +++ b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/create/help.cfc @@ -1,7 +1,7 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use cachebox create' ); print.line(); diff --git a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/help.cfc b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/help.cfc index 1eff0c860..d61501786 100644 --- a/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/help.cfc +++ b/src/cfml/system/modules_app/cachebox-commands/commands/cachebox/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use cachebox' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app-wizard.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app-wizard.cfc index 5eccd8808..be262b6c5 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app-wizard.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app-wizard.cfc @@ -2,7 +2,7 @@ * Create a blank ColdBox app from one of our app skeletons by following our lovely wizard. **/ component extends="app" { - + /** * @name The name of the app you want to create * @skeleton The application skeleton you want to use @@ -26,7 +26,7 @@ component extends="app" { arguments.initWizard = true; arguments.directory = getCWD(); - super.run( argumentCollection=arguments ); + super.run( argumentCollection=arguments ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app.cfc index 166e98d66..06eaa2603 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/app.cfc @@ -36,18 +36,18 @@ * {code:bash} * coldbox create app myApp --installColdBox --installTestBox * {code} -* +* **/ component { // DI property name="packageService" inject="PackageService"; - + /** * Constructor */ function init(){ - + // Map these shortcut names to the actual ForgeBox slugs variables.templateMap = { 'Advanced' = 'cbtemplate-advanced', @@ -57,12 +57,12 @@ component { 'Elixir' = 'cbtemplate-elixir', 'rest' = 'cbtemplate-rest', 'Simple' = 'cbtemplate-simple', - 'SuperSimple' = 'cbtemplate-supersimple' + 'SuperSimple' = 'cbtemplate-supersimple' }; - + return this; } - + /** * @name The name of the app you want to create * @skeleton The name of the app skeleton to generate (or an endpoint ID like a forgebox slug) @@ -86,7 +86,7 @@ component { boolean wizard=false, boolean initWizard=false ) { - + // Check for wizard argument if( arguments.wizard ){ runCommand( 'coldbox create app-wizard' ); @@ -95,7 +95,7 @@ component { // This will make the directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory, if it doesn't exist, create it. if( !directoryExists( arguments.directory ) ) { directoryCreate( arguments.directory ); @@ -116,7 +116,7 @@ component { production = true, currentWorkingDirectory = arguments.directory ); - + // Check for the @appname@ in .project files if( fileExists( "#arguments.directory#/.project" ) ){ var sProject = fileRead( "#arguments.directory#/.project" ); @@ -126,24 +126,24 @@ component { // Init, if not a package as a Box Package if( arguments.init && !packageService.isPackage( arguments.directory ) ) { - var originalPath = getCWD(); + var originalPath = getCWD(); // init must be run from CWD shell.cd( arguments.directory ); command( 'init' ) .params( - name=arguments.name, + name=arguments.name, slug=replace( arguments.name, ' ', '', 'all' ), wizard=arguments.initWizard ) - .run(); + .run(); shell.cd( originalPath ); } - + // Install the ColdBox platform if( arguments.installColdBox || arguments.installColdBoxBE ) { - + // Flush out stuff from above print.toConsole(); - + packageService.installPackage( ID = 'coldbox#iif( arguments.installColdBoxBE, de( '-be' ), de( '' ) )#', directory = arguments.directory, @@ -156,10 +156,10 @@ component { // Install TestBox if( arguments.installTestBox ) { - + // Flush out stuff from above print.toConsole(); - + packageService.installPackage( ID = 'testbox', directory = arguments.directory, @@ -169,7 +169,7 @@ component { currentWorkingDirectory = arguments.directory ); } - + } /** diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/bdd.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/bdd.cfc index 2c3bc5097..62b057e96 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/bdd.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/bdd.cfc @@ -1,15 +1,15 @@ /** * Create a new BDD spec in an existing ColdBox-enabled application. Run this command in the root -* of your app for it to find the correct folder. By default, your new BDD spec will be created in /tests/specs but you can +* of your app for it to find the correct folder. By default, your new BDD spec will be created in /tests/specs but you can * override that with the directory param. * . * {code:bash} * coldbox create bdd mySpec * {code} -* +* **/ component { - + /** * @name.hint Name of the BDD spec to create without the .cfc. For packages, specify name as 'myPackage/myBDDSpec' * @open.hint Open the file once it is created diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/handler.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/handler.cfc index b8dae8370..9c54da923 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/handler.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/handler.cfc @@ -112,7 +112,7 @@ component aliases='coldbox create controller' { var handlerPath = '#arguments.directory#/#arguments.name#.cfc'; // Create dir if it doesn't exist directorycreate( getDirectoryFromPath( handlerPath ), true, true ); - + // Confirm it if( fileExists( handlerPath ) && !confirm( "The file '#getFileFromPath( handlerPath )#' already exists, overwrite it (y/n)?" ) ){ print.redLine( "Exiting..." ); @@ -138,4 +138,4 @@ component aliases='coldbox create controller' { if( arguments.open ){ openPath( handlerPath ); } } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/help.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/help.cfc index dce9140c0..338d3ca39 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/help.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/help.cfc @@ -1,7 +1,7 @@ component excludeFromHelp=true { - + function run() { - + print.line() .yellow( 'The ' ).boldYellow( 'coldbox create' ).yellowLine( ' namespace allows you to quickly scaffold applications ' ) .yellowLine( 'and individual app pieces. Use these commands to stub out placeholder files' ) diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor-test.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor-test.cfc index 2bd3be000..80d9dc1d2 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor-test.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor-test.cfc @@ -15,7 +15,7 @@ component { * @testsDirectory Your unit tests directory. Only used if tests is true * @open.hint Open the test once generated **/ - function run( + function run( required path, points='', testsDirectory='tests/specs/interceptors', @@ -43,7 +43,7 @@ component { if( len( arguments.points ) ) { var allTestsCases = ''; var thisTestCase = ''; - + for( var thisPoint in listToArray( arguments.points ) ) { thisTestCase = replaceNoCase( interceptorTestCase, '|point|', thisPoint, 'all' ); allTestsCases &= thisTestCase & CR & CR; @@ -63,13 +63,13 @@ component { print.redLine( "Exiting..." ); return; } - + // Create the tests file action='write' file='#testPath#' mode ='777' output='#interceptorTestContent#'; print.greenLine( 'Created #testPath#' ); // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor.cfc index c1fe27d3c..3c2d79464 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/interceptor.cfc @@ -22,7 +22,7 @@ component { * @script Generate content in script markup or tag markup * @open.hint Open the interceptor once generated **/ - function run( + function run( required name, points='', description="I am a new interceptor", @@ -71,7 +71,7 @@ component { var methodContent = ''; var allTestsCases = ''; var thisTestCase = ''; - + for( var thisPoint in listToArray( arguments.points ) ) { methodContent = methodContent & replaceNoCase( interceptorMethod, '|interceptionPoint|', thisPoint, 'all' ) & CR & CR; @@ -97,7 +97,7 @@ component { print.redLine( "Exiting..." ); return; } - + file action='write' file='#interceptorPath#' mode ='777' output='#interceptorContent#'; print.greenLine( '#interceptorPath#' ); @@ -109,11 +109,11 @@ component { file action='write' file='#testPath#' mode ='777' output='#interceptorTestContent#'; print.greenLine( 'Created #testPath#' ); // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } } // open file - if( arguments.open ){ openPath( interceptorPath ); } + if( arguments.open ){ openPath( interceptorPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/layout.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/layout.cfc index fc1eecc94..02df303e8 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/layout.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/layout.cfc @@ -1,41 +1,41 @@ /** * Create a new layout in an existing ColdBox application. Run this command in the root -* of your app for it to find the correct folder. By default, your new layout will be created in /layouts but you can +* of your app for it to find the correct folder. By default, your new layout will be created in /layouts but you can * override that with the directory param. * . * {code:bash} * coldbox create layout myLayout * {code} -* +* **/ component { - + /** * @arguments.name.hint Name of the layout to create without the .cfm. * @helper.hint Generate a helper file for this layout * @directory.hint The base directory to create your layout in and creates the directory if it does not exist. **/ - function run( + function run( required name, boolean helper=false, - directory='layouts' + directory='layouts' ){ - // This will make each directory canonical and absolute + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } - + // This help readability so the success messages aren't up against the previous command line print.line(); - + var layoutContent = '

#arguments.name# Layout

#CR###renderView()##'; var layoutHelperContent = ''; - + // Write out layout - var layoutPath = '#arguments.directory#/#arguments.name#.cfm'; + var layoutPath = '#arguments.directory#/#arguments.name#.cfm'; // Confirm it if( fileExists( layoutPath ) && !confirm( "The file '#getFileFromPath( layoutPath )#' already exists, overwrite it (y/n)?" ) ){ @@ -44,16 +44,16 @@ component { } file action='write' file='#layoutPath#' mode ='777' output='#layoutContent#'; - print.greenLine( 'Created #layoutPath#' ); - + print.greenLine( 'Created #layoutPath#' ); + if( arguments.helper ) { // Write out layout helper - var layoutHelperPath = '#arguments.directory#/#arguments.name#Helper.cfm'; + var layoutHelperPath = '#arguments.directory#/#arguments.name#Helper.cfm'; file action='write' file='#layoutHelperPath#' mode ='777' output='#layoutHelperContent#'; print.greenLine( 'Created #layoutHelperPath#' ); - + } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model-test.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model-test.cfc index 866212a5e..b77a0dac0 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model-test.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model-test.cfc @@ -1,6 +1,6 @@ /** * Create a new model bdd test in an existing ColdBox application. Make sure you are running this command in the root -* of your app for it to find the correct folder. +* of your app for it to find the correct folder. * . * {code:bash} * coldbox create model-test myModel --open @@ -25,7 +25,7 @@ component { * @testsDirectory.hint Your unit tests directory. Only used if tests is true * @open.hint Open the file once generated **/ - function run( + function run( required path, methods="", testsDirectory='tests/specs/unit', @@ -48,7 +48,7 @@ component { // Basic replacements modelTestContent = replaceNoCase( modelTestContent, '|modelName|', arguments.path, 'all' ); - + // Handle Methods if( len( arguments.methods ) ){ var allTestsCases = ""; @@ -78,14 +78,14 @@ component { print.redLine( "Exiting..." ); return; } - + // Create the tests file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } print.greenLine( 'Created #testPath#' ); // Open file? - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model.cfc index adb3f70a0..a46d5970d 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/model.cfc @@ -40,7 +40,7 @@ component { * @accessors Setup accessors to be true or not in the component * @properties Enter a list of properties to generate. You can add the type via semicolon separator. Ex: firstName,age:numeric,wheels:array **/ - function run( + function run( required name, methods="", persistence='transient', @@ -100,7 +100,7 @@ component { modelContent = replaceNoCase( modelContent, '|modelDescription|', arguments.description, 'all' ); modelTestContent = replaceNoCase( modelTestContent, '|modelName|', listChangeDelims( arguments.name, '.', '/\' ), 'all' ); modelTestContent = replaceNoCase( modelTestContent, '|modelPath|', listChangeDelims( modelTestPath, '.', '/\' ) & "." & listChangeDelims( arguments.name, '.', '/\' ), 'all' ); - + // Persistence switch ( Persistence ) { case 'Transient' : @@ -142,7 +142,7 @@ component { // Loop Over methods to generate them for( var thisMethod in listToArray( arguments.methods ) ) { if( thisMethod == 'init' ) { continue; } - + thisMethod = trim( thisMethod ); allMethods = allMethods & replaceNoCase( modelMethodContent, '|method|', thisMethod, 'all' ) & cr & cr; @@ -183,12 +183,12 @@ component { // Create the tests file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } print.greenLine( 'Created #testPath#' ); } // Open file? - if( arguments.open ){ openPath( modelPath ); } + if( arguments.open ){ openPath( modelPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/module.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/module.cfc index 92795742b..93df688f4 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/module.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/module.cfc @@ -4,11 +4,11 @@ * . * {code:bash} * coldbox create module myModule -* {code} -* +* {code} +* **/ component { - + /** * @name Name of the module to create. * @author Whoever wrote this module @@ -18,10 +18,10 @@ component { * @cfmapping A CF app mapping to create that points to the root of this module * @modelNamespace The namespace to use when mapping the models in this module * @dependencies The list of dependencies for this module - * @directory The base directory to create your model in and creates the directory if it does not exist. + * @directory The base directory to create your model in and creates the directory if it does not exist. * @script.hint Generate content in script markup or tag markup **/ - function run( + function run( required name, author='', authorURL='', @@ -32,27 +32,27 @@ component { dependencies="", directory='modules_app', boolean script=true - ){ - // This will make each directory canonical and absolute + ){ + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } // This help readability so the success messages aren't up against the previous command line print.line(); - + // Script? var scriptPrefix = ''; // TODO: Pull this from box.json if( arguments.script ) { - scriptPrefix = 'Script'; + scriptPrefix = 'Script'; } - + // Read in Module Config var moduleConfig = fileRead( '/coldbox-commands/templates/modules/ModuleConfig#scriptPrefix#.cfc' ); - + // Start Generation Replacing moduleConfig = replaceNoCase( moduleConfig, '@title@', arguments.name, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@author@', arguments.author, 'all'); @@ -62,9 +62,9 @@ component { moduleConfig = replaceNoCase( moduleConfig, '@cfmapping@', arguments.cfmapping, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@modelNamespace@', arguments.modelNamespace, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@dependencies@', serializeJSON( listToArray( arguments.dependencies ) ), 'all'); - + // Confirm it - if( directoryExists( arguments.directory & '/#arguments.name#' ) && + if( directoryExists( arguments.directory & '/#arguments.name#' ) && !confirm( "The module already exists, overwrite it (y/n)?" ) ){ print.redLine( "Exiting..." ); return; @@ -72,7 +72,7 @@ component { // Copy module template directoryCopy( '/coldbox-commands/templates/modules/', arguments.directory & '/#arguments.name#', true ); - + // Clean Files Out if( script ) { fileDelete( arguments.directory & '/#arguments.name#/handlers/Home.cfc' ); @@ -81,16 +81,16 @@ component { fileDelete( arguments.directory & '/#arguments.name#/handlers/HomeScript.cfc' ); } fileDelete( arguments.directory & '/#arguments.name#/ModuleConfigScript.cfc' ); - + // Write Out the New Config fileWrite( arguments.directory & '/#arguments.name#/ModuleConfig.cfc', moduleConfig ); - + var stuffAdded = directoryList( arguments.directory & '/#arguments.name#', true ); print.greenLine( 'Created ' & arguments.directory & '/#arguments.name#' ); for( var thing in stuffAdded ) { - print.greenLine( 'Created ' & thing ); + print.greenLine( 'Created ' & thing ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-crud.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-crud.cfc index 80a5ac50d..81e817a5a 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-crud.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-crud.cfc @@ -18,7 +18,7 @@ component { * @tests Generate the BDD tests for this CRUD operation * @testsDirectory Your integration tests directory. Only used if tests is true **/ - function run( + function run( required entity, pluralName="", handlersDirectory="handlers", @@ -35,7 +35,7 @@ component { var entityName = listLast( arguments.entity, "." ); var entityCFC = fileSystemUtil.makePathRelative( fileSystemUtil.resolvePath( replace( arguments.entity, ".", "/", "all" ) ) ); var entityPath = entityCFC & ".cfc"; - + // verify it if( !fileExists( entityPath ) ){ return error( "The entity #entityPath# does not exist, cannot continue, ciao!" ); @@ -45,7 +45,7 @@ component { // property Map var metadata = { properties = [], pk="" }; var md = getComponentMetadata( entityCFC ); - + // argument defaults if( !len( arguments.pluralname ) ){ arguments.pluralName = entityName & "s"; } @@ -57,13 +57,13 @@ component { entityDefaults( thisProperty ); // store the pk for convenience if( compareNoCase( thisProperty.fieldType, "id" ) EQ 0 ){ metadata.pk = thisProperty.name; } - + // Store only persistable columns if( thisProperty.isPersistable ){ arrayAppend( metadata.properties, thisProperty ); } } - + //********************** generate handler ************************************// // Read Handler Content @@ -72,7 +72,7 @@ component { hContent = replacenocase( hContent, "|entity|", entityName, "all" ); hContent = replacenocase( hContent, "|entityPlural|", arguments.pluralName, "all" ); hContent = replacenocase( hContent, "|pk|", metadata.pk, "all" ); - + // Write Out Handler var hpath = '#arguments.handlersDirectory#/#arguments.pluralName#.cfc'; // Create dir if it doesn't exist @@ -94,10 +94,10 @@ component { } //********************** generate table output ************************************// - + // Build table output for index savecontent variable="local.tableData"{ - include '/coldbox-commands/templates/crud/table.cfm'; + include '/coldbox-commands/templates/crud/table.cfm'; } tableData = replaceNoCase( tableData, "%cf", "#chr(60)#cf", "all" ); tableData = replaceNoCase( tableData, "%/cf", "#chr(60)#/cf", "all" ); @@ -111,7 +111,7 @@ component { } else { return error( "The entity: #entityName# has no properties, so I have no clue what to CRUD on dude!" ); } - + } /** diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-entity.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-entity.cfc index f8d1c3c2e..d9204290e 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-entity.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-entity.cfc @@ -16,13 +16,13 @@ * {code:bash} * // Basic * coldbox create orm-entity User --open -* +* * // Active Entity * coldbox create orm-entity User --open --activeEntity -* +* * // With Some Specifics * coldbox create orm-entity entityName=User table=users primaryKey=userID generator=uuid -* +* * // With some properties * coldbox create orm-entity entityName=User properties=firstname,lastname,email,createDate:timestamp,updatedate:timestamp,age:numeric * {code} @@ -45,7 +45,7 @@ component { * @script Generate as script or not, defaults to true * @open Open the file(s) once generated **/ - function run( + function run( required entityName, table="", directory="models", @@ -139,12 +139,12 @@ component { // Create the tests file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } print.greenLine( 'Created #testPath#' ); } // Open file? - if( arguments.open ){ openPath( modelPath ); } + if( arguments.open ){ openPath( modelPath ); } } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-event-handler.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-event-handler.cfc index b0e7ca327..cc14924db 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-event-handler.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-event-handler.cfc @@ -14,7 +14,7 @@ component { * @directory.hint The base directory to create your event handler in and creates the directory if it does not exist. * @open.hint Open the file once generated **/ - function run( + function run( required name, directory='models', boolean open=false @@ -43,7 +43,7 @@ component { print.greenLine( 'Created #modelPath#' ); // Open file? - if( arguments.open ){ openPath( modelPath ); } + if( arguments.open ){ openPath( modelPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-service.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-service.cfc index 2ea1749d1..0db05a926 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-service.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-service.cfc @@ -19,7 +19,7 @@ component { * @testsDirectory Your unit tests directory. Only used if tests is true * @open Open the file once generated **/ - function run( + function run( required serviceName, directory="models", boolean queryCaching=false, @@ -67,7 +67,7 @@ component { print.redLine( "Exiting..." ); return; } - + file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; print.greenLine( 'Created #modelPath#' ); @@ -78,12 +78,12 @@ component { // Create the tests file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } print.greenLine( 'Created #testPath#' ); } // Open file? - if( arguments.open ){ openPath( modelPath ); } + if( arguments.open ){ openPath( modelPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-virtual-service.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-virtual-service.cfc index 38a29c083..13ec88103 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-virtual-service.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/orm-virtual-service.cfc @@ -19,7 +19,7 @@ component { * @testsDirectory Your unit tests directory. Only used if tests is true * @open Open the file once generated **/ - function run( + function run( required entityName, directory="models", boolean queryCaching=false, @@ -67,7 +67,7 @@ component { print.redLine( "Exiting..." ); return; } - + file action='write' file='#modelPath#' mode ='777' output='#modelContent#'; print.greenLine( 'Created #modelPath#' ); @@ -78,12 +78,12 @@ component { // Create the tests file action='write' file='#testPath#' mode ='777' output='#modelTestContent#'; // open file - if( arguments.open ){ openPath( testPath ); } + if( arguments.open ){ openPath( testPath ); } print.greenLine( 'Created #testPath#' ); } // Open file? - if( arguments.open ){ openPath( modelPath ); } + if( arguments.open ){ openPath( modelPath ); } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/unit.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/unit.cfc index d0df1253e..7262b1d8f 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/unit.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/unit.cfc @@ -1,15 +1,15 @@ /** * Create a new xUnit Bundle in an existing ColdBox-enabled application. Run this command in the root -* of your app for it to find the correct folder. By default, your new xUnit Bundle will be created in /tests/specs but you can +* of your app for it to find the correct folder. By default, your new xUnit Bundle will be created in /tests/specs but you can * override that with the directory param. * . * {code:bash} * coldbox create unit myUnit * {code} -* +* **/ component { - + /** * @name.hint Name of the xUnit Bundle to create without the .cfc. For packages, specify name as 'myPackage/MyServiceTest' * @open.hint Open the file once it is created diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/view.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/view.cfc index 77fcae2d3..624d634b0 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/view.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/create/view.cfc @@ -32,7 +32,7 @@ component { var extendedPath = nameArray.slice(1, nameArrayLength - 1).toList('/'); arguments.directory &= '/#extendedPath#'; } - + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); @@ -69,4 +69,4 @@ component { } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/help.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/help.cfc index 002a02bf7..3a3b20dca 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/help.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/help.cfc @@ -1,14 +1,14 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellow( 'The ' ); print.boldYellow( 'coldbox' ); print.yellowLine( ' namespace is designed to help developers easily build applications using the ColdBox MVC platform.' ); print.yellowLine( 'Use these commands to stub out placeholder handlers, models, views, modules and much more.' ); print.yellowLine( 'There are commands to install ColdBox integrations into your IDE, run your application from the command line, ' ); print.yellowLine( 'and even generate reports on various aspects of your application structure.' ); print.yellowLine( 'Type help before any command name to get additional information on how to call that specific command.' ); - + print.line(); print.line(); diff --git a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc index b310185dd..4d687122c 100644 --- a/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc +++ b/src/cfml/system/modules_app/coldbox-commands/commands/coldbox/reinit.cfc @@ -11,11 +11,11 @@ * {code} **/ component aliases="fwreinit" { - + // DI property name="serverService" inject="ServerService"; property name="formatter" inject="formatter"; - + /** * @password The FWReinit password * @name Name of the CommandBox server to reinit @@ -28,7 +28,7 @@ component aliases="fwreinit" { } else { var thisURL = "#serverInfo.host#:#serverInfo.port#/?fwreinit=#arguments.password#"; print.greenLine( "Hitting...#thisURL#" ); - http result="local.results" + http result="local.results" url="#thisURL#"; if( findNoCase( "200", local.results.statusCode ) ){ @@ -38,8 +38,8 @@ component aliases="fwreinit" { .redline( "error detail: " & local.results.errorDetail ) .line( trim( formatter.HTML2ANSI( local.results.filecontent ) ) ); } - + } } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/module.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/module.cfc index abcc6675b..940d74734 100644 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/module.cfc +++ b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/module.cfc @@ -4,11 +4,11 @@ * . * {code:bash} * coldbox create module myModule -* {code} -* +* {code} +* **/ component { - + /** * @name Name of the module to create. * @author Whoever wrote this module @@ -18,10 +18,10 @@ component { * @cfmapping A CF app mapping to create that points to the root of this module * @modelNamespace The namespace to use when mapping the models in this module * @dependencies The list of dependencies for this module - * @directory The base directory to create your model in and creates the directory if it does not exist. + * @directory The base directory to create your model in and creates the directory if it does not exist. * @script.hint Generate content in script markup or tag markup **/ - function run( + function run( required name, author='', authorURL='', @@ -32,27 +32,27 @@ component { dependencies="", directory='modules/contentbox/modules_user', boolean script=true - ){ - // This will make each directory canonical and absolute + ){ + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } // This help readability so the success messages aren't up against the previous command line print.line(); - + // Script? var scriptPrefix = ''; // TODO: Pull this from box.json if( arguments.script ) { - scriptPrefix = 'Script'; + scriptPrefix = 'Script'; } - + // Read in Module Config var moduleConfig = fileRead( '/coldbox-commands/templates/modules/ModuleConfig#scriptPrefix#.cfc' ); - + // Start Generation Replacing moduleConfig = replaceNoCase( moduleConfig, '@title@', arguments.name, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@author@', arguments.author, 'all'); @@ -62,10 +62,10 @@ component { moduleConfig = replaceNoCase( moduleConfig, '@cfmapping@', arguments.cfmapping, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@modelNamespace@', arguments.modelNamespace, 'all'); moduleConfig = replaceNoCase( moduleConfig, '@dependencies@', serializeJSON( listToArray( arguments.dependencies ) ), 'all'); - + // Copy module template directoryCopy( '/coldbox-commands/templates/modules/', arguments.directory & '/#arguments.name#', true ); - + // Clean Files Out if( script ) { fileDelete( arguments.directory & '/#arguments.name#/handlers/Home.cfc' ); @@ -74,16 +74,16 @@ component { fileDelete( arguments.directory & '/#arguments.name#/handlers/HomeScript.cfc' ); } fileDelete( arguments.directory & '/#arguments.name#/ModuleConfigScript.cfc' ); - + // Write Out the New Config fileWrite( arguments.directory & '/#arguments.name#/ModuleConfig.cfc', moduleConfig ); - + var stuffAdded = directoryList( arguments.directory & '/#arguments.name#', true ); print.greenLine( 'Created ' & arguments.directory & '/#arguments.name#' ); for( var thing in stuffAdded ) { - print.greenLine( 'Created ' & thing ); + print.greenLine( 'Created ' & thing ); } - + } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc +++ b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/theme.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc +++ b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/create/widget.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/help.cfc b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/help.cfc index 886248ded..9ea134ea7 100644 --- a/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/help.cfc +++ b/src/cfml/system/modules_app/contentbox-commands/commands/contentbox/help.cfc @@ -1,14 +1,14 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellow( 'The ' ); print.boldYellow( 'ContentBox' ); print.yellowLine( ' namespace is designed to help developers easily build and maintain ContentBox CMS applications.' ); print.yellowLine( 'Use these commands to generate themes, widgets, modules and much more.' ); print.yellowLine( 'There are also commands to install, run and even update ContentBox. ' ); print.yellowLine( 'Type help before any command name to get additional information on how to call that specific command.' ); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/help.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/help.cfc index 0be97da6c..271591c02 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/help.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/help.cfc @@ -1,7 +1,7 @@ component excludeFromHelp=true { - + function run() { - + print.line() .yellow( 'The ' ).boldYellow( 'forgebox' ).yellowLine( ' namespace helps you interact with the ForgeBox online code repo.' ) .yellowLine( 'Use these commands to browse ForgeBox entries as well as download and install ForgeBox projects into your code.' ) diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/login.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/login.cfc index 56a37f45a..ea4e4be01 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/login.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/login.cfc @@ -6,14 +6,14 @@ * {code} **/ component { - - /** + + /** * @username.hint Username for this user * @password.hint Password for this user **/ - function run( + function run( string username='', - string password='' + string password='' ){ // Default the endpointName @@ -21,7 +21,7 @@ component { // Ask for username if not passed if( !len( arguments.username ) ) { - + // Info for ForgeBox print.line() .line( "Login with your ForgeBox ID to publish and manage packages in Forgebox.io. ") @@ -30,15 +30,15 @@ component { .line( "command to register a new account.") .line() .toConsole(); - + arguments.username = ask( 'Enter your username: ' ); } // Ask for password if not passed if( !len( arguments.password ) ) { - arguments.password = ask( 'Enter your password: ', '*' ); + arguments.password = ask( 'Enter your password: ', '*' ); } - + // Message user since there can be a couple-second delay here print.line() .yellowLine( 'Contacting ForgeBox...' ) @@ -48,7 +48,7 @@ component { command( 'endpoint login' ) .params( argumentCollection=arguments ) .run(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/my-contributions.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/my-contributions.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/my-contributions.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/my-contributions.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc index e8af02edc..bd51a811f 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/publish.cfc @@ -6,31 +6,31 @@ * {code} **/ component aliases="publish" { - + property name="configService" inject="configService"; - - /** + + /** * @directory The directory to publish **/ - function run( - string directory='' + function run( + string directory='' ){ - + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + if( !APIToken.len() ) { print.yellowLine( 'Please log into Forgebox to continue' ); command( 'forgebox login' ).run(); } - + // Default the endpointName arguments.endpointName = 'forgebox'; - + // Defer to the generic command command( 'endpoint publish' ) .params( argumentCollection=arguments ) .run(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/register.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/register.cfc index 0c9f51691..676ffbd43 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/register.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/register.cfc @@ -6,7 +6,7 @@ * {code} **/ component { - + /** * @username.hint Username for this user * @password.hint Password for this user @@ -14,21 +14,21 @@ component { * @firstName.hint First name of the user * @lastName.hint Last name of the user **/ - function run( + function run( required string username, required string password, required string email, required string firstName, required string lastName ) { - + // Default the endpointName arguments.endpointName = 'forgebox'; - + // Defer to the generic command command( 'endpoint register' ) .params( argumentCollection=arguments ) .run(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc index df23cfa4e..3bbd607c5 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/search.cfc @@ -1,5 +1,5 @@ /** - * Search for ForgeBox entries by keyword. Search is case-insensitive and will match text anywhere in the + * Search for ForgeBox entries by keyword. Search is case-insensitive and will match text anywhere in the * title, summary, or author name. * . * {code:bash} @@ -8,33 +8,33 @@ * . **/ component { - + // DI property name="forgeBox" inject="ForgeBox"; property name="semanticVersion" inject="semanticVersion@semver"; - + /** * @searchText.hint Text to search on **/ function run( searchText ) { - + // Default parameter arguments.searchText = arguments.searchText ?: ''; - + try { - + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + // Get the entries var entries = forgebox.getEntries( searchTerm = arguments.searchText, APIToken=APIToken ); - + // entrylink,createdate,lname,isactive,installinstructions,typename,version,hits,coldboxversion,sourceurl,slug,homeurl,typeslug, // downloads,entryid,fname,changelog,updatedate,downloadurl,title,entryrating,summary,username,description - + print.line(); for( var entry in entries.results ) { entry.versions.sort( function( a, b ) { return semanticVersion.compare( b.version, a.version ) } ); - print.blackOnWhite( ' #entry.title# ' ) + print.blackOnWhite( ' #entry.title# ' ) .boldText( ' ( #entry.user.fname# #entry.user.lname# )' ) .boldGreenLine( ' Rating: #repeatString( '*', val( entry.avgRating ) )#' ) .line( 'Versions: #entry.versions.map( function( i ){ return ' ' & i.version; } ).toList()#' ) @@ -45,15 +45,15 @@ component { .line() .line(); } - + print.line(); print.boldCyanline( " Showing #entries.count# of #entries.totalRecords# record#( entries.count == 1 ? '' : 's' )#." ); - + } catch( forgebox var e ) { // This can include "expected" errors such as "slug not found" return error( '#e.message##CR##e.detail#' ); } - + } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc index 75e3858c2..daad04a10 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/show.cfc @@ -1,5 +1,5 @@ /** - * Show forgeBox entries by slug or type. You can sort entires by most popular, recently updated, and newest. + * Show forgeBox entries by slug or type. You can sort entires by most popular, recently updated, and newest. * You can also filter for specific entry types such as cachebox, interceptors, modules, logbox, etc. * Pro Tip: The first parameter will accept a type or a slug. * . @@ -32,15 +32,15 @@ * **/ component aliases="show" { - + // DI property name="forgeBox" inject="ForgeBox"; property name="semanticVersion" inject="semanticVersion@semver"; - + function onDIComplete() { variables.forgeboxOrders = forgebox.ORDER; } - + /** * @orderBy.hint How to order results. Possible values are popular, new, installs, recent or a specific ForgeBox type * @orderBy.optionsUDF orderByComplete @@ -49,28 +49,28 @@ component aliases="show" { * @startRow.hint Row to start returning records on * @maxRows.hint Number of records to return * @slug.hint Slug of a specific ForgeBox entry to show. - * + * **/ - function run( + function run( orderBy='popular', type, number startRow, number maxRows, - slug + slug ){ var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + print.yellowLine( "Contacting ForgeBox, please wait..." ).toConsole(); - + // Default parameters arguments.type = arguments.type ?: ''; arguments.startRow = arguments.startRow ?: 1; arguments.maxRows = arguments.maxRows ?: 0; arguments.slug = arguments.slug ?: ''; var typeLookup = ''; - + // Validate orderBy - var orderLookup = forgeboxOrders.findKey( orderBy ); + var orderLookup = forgeboxOrders.findKey( orderBy ); if( !orderLookup.len() ) { // If there is a type supplied, quit here if( len( type ) ){ @@ -85,23 +85,23 @@ component aliases="show" { if( !len( slug ) ) { try { var entryData = forgebox.getEntry( orderBy, APIToken ); - slug = orderBy; + slug = orderBy; } catch( any e ) { if( e.detail contains 'The entry slug sent is invalid' ) { - error( 'Parameter [#orderBy#] isn''t a valid orderBy, type, or slug. Valid orderBys are [#lcase( listChangeDelims( forgeboxOrders.keyList(), ', ' ) )#] See possible types with "forgebox types".' ); + error( 'Parameter [#orderBy#] isn''t a valid orderBy, type, or slug. Valid orderBys are [#lcase( listChangeDelims( forgeboxOrders.keyList(), ', ' ) )#] See possible types with "forgebox types".' ); } else { - rethrow; + rethrow; } } - } - } + } + } } } - + // Validate Type if we got one if( len( type ) ) { typeLookup = lookupType( type ); - + // Were we able to resolve what they typed in? if( !len( typeLookup ) ) { error( 'Type value of [#type#] is invalid. See possible types with "forgebox types".' ); @@ -112,12 +112,12 @@ component aliases="show" { if( hasError() ){ return; } - + try { - - // We're displaying a single entry + + // We're displaying a single entry if( len( slug ) ) { - + // We might have gotten this above var entryData = entryData ?: forgebox.getEntry( slug, APIToken ); // numberOfRatings,boxjson,isActive,typeName,version,hits,sourceURL,slug,createdDate,typeSlug,downloads,updatedDate,entryID, @@ -125,7 +125,7 @@ component aliases="show" { if( !entryData.isActive ) { error( 'The ForgeBox entry [#entryData.title#] is inactive, we highly recommed NOT installing it or contact the author about it' ); } - + entryData.versions.sort( function( a, b ) { return semanticVersion.compare( b.version, a.version ) } ); print.line(); print.blackOnWhite( ' #entryData.title# ' ) @@ -136,9 +136,9 @@ component aliases="show" { .line() .line( 'Type: #entryData.typeName#' ) .line( 'Slug: "#entryData.slug#"' ) - .line( 'Summary: #entryData.summary#' ) + .line( 'Summary: #entryData.summary#' ) .text( 'Versions: ' ); - + var prevMajor = val( entryData.versions[ 1 ].version.listGetAt( 1, '.' ) ); var majorCount = 0; var versionLine = ''; @@ -166,8 +166,8 @@ component aliases="show" { if( lines > 0 ) { print.text( ' ' ); } print.line( versionLine & ( versionsSkipped > 0 ? ' ( #versionsSkipped# more...)' : '' ) ); } - - + + print.line( 'Created On: #dateFormat( entryData.createdDate )#' ) .line( 'Updated On: #dateFormat( entryData.updatedDate )#' ) .line( 'ForgeBox Views: #numberFormat( entryData.hits )#' ) @@ -180,21 +180,21 @@ component aliases="show" { .line() .cyanLine( 'Visit in ForgeBox at: #forgebox.getEndpointURL()#/view/#entryData.slug#' ) .line(); - + // List of entries } else { // Get the entries var entries = forgebox.getEntries( orderBy=orderBy, maxRows=maxRows, startRow=startRow, typeSlug=typeLookup, APIToken=APIToken ); - + // entrylink,createdate,lname,isactive,installinstructions,typename,version,hits,coldboxversion,sourceurl,slug,homeurl,typeslug, // downloads,entryid,fname,changelog,updatedate,downloadurl,title,entryrating,summary,username,description - + print.line(); var activeCount = 0; for( var entry in entries.results ) { if( entry.isactive ) { activeCount++; - print.blackOnWhite( ' #entry.title# ' ); + print.blackOnWhite( ' #entry.title# ' ); print.boldText( ' ( #entry.user.fname# #entry.user.lname# )' ); print.boldGreenLine( ' #repeatString( '*', val( entry.avgRating ) )#' ); print.line( 'Type: #entry.typeName#' ); @@ -204,24 +204,24 @@ component aliases="show" { print.line(); } } - + print.line(); print.boldCyanline( ' Found #activeCount# record#(activeCount == 1 ? '': 's')#.' ); - + } // end single entry check - + } catch( forgebox var e ) { // This can include "expected" errors such as "slug not found" return error( '#e.message##CR##e.detail#' ); } - + } - // Auto-complete + // Auto-complete function lookupType( type ) { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); var typeLookup = ''; - + // See if they entered a type name or slug for( var thistype in forgebox.getCachedTypes( APIToken=APIToken ) ) { if( thisType.typeName == type || thisType.typeSlug == type ) { @@ -229,34 +229,34 @@ component aliases="show" { break; } } - + // This will be empty if not found return typeLookup; - + } // Auto-complete list of types function typeComplete( result = [] ) { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + // Loop over types and append all active ForgeBox entries for( var thistype in forgebox.getCachedTypes( APIToken=APIToken ) ) { arguments.result.append( thisType.typeSlug ); } - + return arguments.result; } // Auto-complete list of orderBys (can also include types and slugs) function orderByComplete() { var result = [ 'popular', 'new', 'recent', 'installs' ]; - + // Add types result = typeComplete( result ); - + // For now, I'm not going to add slugs since it will always be too many to display without prompting the user - + return result; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc index b8273cf14..75e8c6766 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/slugcheck.cfc @@ -5,23 +5,23 @@ * forgebox slugcheck MyApp * {code} * . - + **/ component { - + // DI property name="forgeBox" inject="ForgeBox"; - + /** * @slug.hint The slug to verify in ForgeBox */ function run( required slug ) { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + if( !len( arguments.slug ) ) { return error( "Slug cannot be an empty string" ); } - + var exists = forgebox.isSlugAvailable( arguments.slug, APIToken ); if( exists ){ @@ -29,7 +29,7 @@ component { } else { print.redBoldLine( "The slug '#arguments.slug#' already exists in ForgeBox!" ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc index 60511a798..4a34bbb85 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/types.cfc @@ -5,19 +5,19 @@ * forgebox types * {code} * . - + **/ component { - + // DI property name="forgeBox" inject="ForgeBox"; - + /** * Run Command */ function run() { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + // typetotal,typename,typeid,typeslug print.line() .line( "Here is a listing of the available types in ForgeBox" ) @@ -28,7 +28,7 @@ component { print.boldText( type.typeName & "(#type.numberOfActiveEntries#)" ) .line( ' (#type.typeSlug#)' ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/unpublish.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/unpublish.cfc index 1dec52241..4c038db39 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/unpublish.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/unpublish.cfc @@ -6,26 +6,26 @@ * {code} **/ component aliases="unpublish" { - - /** + + /** * @version The directory to publish * @directory The directory to publish * @force Skip the prompt **/ - function run( + function run( string version='', string directory='', - boolean force=false - ){ - + boolean force=false + ){ + // Default the endpointName arguments.endpointName = 'forgebox'; - + // Defer to the generic command command( 'endpoint unpublish' ) .params( argumentCollection=arguments ) .run(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/use.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/use.cfc index 3f2f1005f..c4eea3874 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/use.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/use.cfc @@ -14,18 +14,18 @@ component { property name="forgeBox" inject="ForgeBox"; property name="configService" inject="ConfigService"; - - /** + + /** * @username The ForgeBox username to switch to. * @skipLogin If username isn't authenticated, retuen an error instead of prompting with login **/ function run( required string username, boolean skipLogin=false ){ - + var tokens = configService.getSetting( 'endpoints.forgebox.tokens', {} ); if( !len( arguments.username ) ) { error( 'Please provide a ForgeBox username to use.' ); } - + // If this username exists if( tokens.keyExists( arguments.username ) ) { // Set the active token diff --git a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/whoami.cfc b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/whoami.cfc index 1aa76c2f4..38c8bc6e8 100644 --- a/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/whoami.cfc +++ b/src/cfml/system/modules_app/forgebox-commands/commands/forgebox/whoami.cfc @@ -9,8 +9,8 @@ component { property name="forgeBox" inject="ForgeBox"; property name="configService" inject="ConfigService"; - - /** + + /** * **/ function run(){ @@ -20,14 +20,14 @@ component { error( 'You don''t have a Forgebox API token set.', 'Use "forgebox login" to authenticate as a user.' ); } userData = forgebox.whoami( APIToken ); - + print.boldLine( '#userData.fname# #userData.lname# (#userData.username#)' ) .line( userData.email ); - + } catch( forgebox var e ) { // This can include "expected" errors such as "Email already in use" error( e.message, e.detail ); - } + } } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/games-commands/commands/game/snake.cfc b/src/cfml/system/modules_app/games-commands/commands/game/snake.cfc index 2f7755614..7881e852c 100644 --- a/src/cfml/system/modules_app/games-commands/commands/game/snake.cfc +++ b/src/cfml/system/modules_app/games-commands/commands/game/snake.cfc @@ -1,7 +1,7 @@ /** -* Play a fun, retro-style snake game. The "snake" is on the loose and you need to gobble up as many juicy apples as you can. +* Play a fun, retro-style snake game. The "snake" is on the loose and you need to gobble up as many juicy apples as you can. * Use the S, F, E, and C keys on your keyboard to move left, right, up and down respectively. If you have a 10-key pad, you can also use 4, 6, 8, and 2. -* But be careful- if you run into a wall or into your own tail, the game is over! The snake will grow every time he eats and apple, and once you +* But be careful- if you run into a wall or into your own tail, the game is over! The snake will grow every time he eats and apple, and once you * clear all the apples, more will appear for your chomping pleasure. * . * Press Q to quit the game at any time. @@ -13,68 +13,68 @@ **/ component aliases="snake" { - + processingdirective pageEncoding='UTF-8'; - + property name='p' inject='print'; function run() { - + variables.directionOpposites = { 'up' = 'down', 'down' = 'up', 'left' = 'right', 'right' = 'left' }; - // ╚ ╔ ╩ ╦ ╠ ═ ╬ ╣ ║ ╗ ╝ - - + // ╚ ╔ ╩ ╦ ╠ ? ╬ ╣ ║ ╗ ? + + variables.height = 17; variables.width = 53; //variables.height = shell.getTermHeight()-13; //variables.width = shell.getTermWidth()-3; variables.centerX = round( variables.width / 2 ); variables.centerY = round( variables.height / 2 ); - + resetGame(); - - - variables.gameHeader = - '╔═════════════════════════════════════════════════════╗' & cr & + + + variables.gameHeader = + '╔?????????????????????????????????????????????????????╗' & cr & '║ ' & p.boldGreen( 'CommandBox Snake' ) & ' ║' & cr & '║ by Brad Wood ║░' & cr & - '╠═════════════════════════════════════════════════════╣░'; - + '╠?????????????????????????????????????????????????????╣░'; + // Initialize an array with an index for each row variables.gameSurface = arrayNew( 2 ); var i = 0; // For each row... while( ++i <= variables.height ) { // Initialize it as an array of characters for each column - //variables.gameSurface[ i ] = []; + //variables.gameSurface[ i ] = []; loop from=1 to=variables.width index='j' { variables.gameSurface[ i ][ j ] = ' '; - } + } } - + variables.gameFooter = - '╠═════════════════════════════════════════════════════╣░' & cr & + '╠?????????????????????????????????????????????????????╣░' & cr & '║ ' & p.bold( 'S' ) & ' or ' & p.bold( '4' ) & ' moves left ║░' & cr & '║ ' & p.bold( 'F' ) & ' or ' & p.bold( '6' ) & ' moves right ║░' & cr & '║ ' & p.bold( 'E' ) & ' or ' & p.bold( '8' ) & ' moves up ║░' & cr & '║ ' & p.bold( 'C' ) & ' or ' & p.bold( '2' ) & ' moves down ║░' & cr & '║ ║░' & cr & '║ Press ' & p.bold( 'Q' ) & ' to quit ║░' & cr & - '╚═════════════════════════════════════════════════════╝░' & cr & + '╚??????????????????????????????????????????????????????░' & cr & ' ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░'; - - - var h = p.bold( '═' ); + + + var h = p.bold( '?' ); var v = p.bold( '║' ); var ul = p.bold( '╔' ); var ur = p.bold( '╗' ); var bl = p.bold( '╚' ); - var br = p.bold( '╝' ); + var br = p.bold( '?' ); var sh = p.bold( '░' ); var s = ' '; @@ -87,16 +87,16 @@ component aliases="snake" { [ bl, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, h, br, sh ], [ s, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh, sh ] ]; - + // Flush out anything stored up print.toConsole(); // Start with a blank slate shell.clearScreen(); - - + + // This lets the thread know we're still running' variables.snakeRun = true; - + try { // This thread will keep redrawing the screen while the main thread waits for user input threadName = 'snakeDrawer#createUUID()#'; @@ -106,24 +106,24 @@ component aliases="snake" { while( variables.snakeRun ) { // Move and re-draw if not in an invalid state if( !variables.collision ) { - variables.collision = !move( getNextDirection() ); + variables.collision = !move( getNextDirection() ); printGame(); } // Decrease this to speed up the game sleep( 300 ); - } + } } catch( any e ) { logger.error( e.message & ' ' & e.detail, e.stacktrace ); } - + } // End thread - + var key = ''; while( true ) { - + // Detect user input key = shell.waitForKey(); - + if( isQuit( key ) ) { break; } else if( isLeft( key ) ) { @@ -137,7 +137,7 @@ component aliases="snake" { } else if( isRetry( key ) ) { resetGame(); } - + } } catch ( any e ) { @@ -147,12 +147,12 @@ component aliases="snake" { thread action="join" name=threadName; rethrow; } - + // We're done with the game, clean up. variables.snakeRun = false; // Wait until the thread finishes its last draw thread action="join" name=threadName; - + } /* ************************************************************************************* @@ -160,37 +160,37 @@ component aliases="snake" { ************************************************************************************* */ private function printGame() { - + // Reset cursor to upper left hand corner print.text( chr( 27 ) & '[H' ).toConsole(); - + print.line( variables.gameHeader ); - + var thisGameSurface = duplicate( variables.gameSurface ); - + // Overlay the snake for( var part in variables.body ) { thisGameSurface[ part.y ][ part.x ] = p.green( '0' ); } - + // Overlay the apples for( var apple in variables.apples ) { thisGameSurface[ apple.y ][ apple.x ] = p.redBold( '@' ); } - - + + // If boom-booms happened, overlay message if( variables.collision ) { - + // Add in score thisScore = NumberFormat( variables.biteCount, "000" ); gameOverMessage[ 4 ][ 18 ] = mid( thisScore, 1, 1 ); gameOverMessage[ 4 ][ 19 ] = mid( thisScore, 2, 1 ); gameOverMessage[ 4 ][ 20 ] = mid( thisScore, 3, 1 ); - + // Find the offset of the upper left corner var startX = variables.centerX - ( round( gameOverMessage[1].len() / 2 ) ); - var startY = variables.centerY - ( round( gameOverMessage.len() / 2 ) ); + var startY = variables.centerY - ( round( gameOverMessage.len() / 2 ) ); var YOffset = 0; for( var line in gameOverMessage ) { @@ -200,23 +200,23 @@ component aliases="snake" { } YOffset++; } - + } - + // Now that we've build up the array of characters, spit them out to the console for( var row in thisGameSurface ) { print.text( '║' ); - for( var col in row ) { + for( var col in row ) { print.text( col ); } print.line( '║░' ); - + } - + print.line( variables.gameFooter ); - + print.toConsole(); - + } @@ -224,26 +224,26 @@ component aliases="snake" { // This needs to be synchronized with getNextDirection() private function go( newDirection ) { lock name='snake_direction' type='exclusive' timeout=2 { - + // Figure out where we'll be going right before this direction is used if( variables.direction.len() ) { var preceedingDirection = variables.direction.first(); } else { - var preceedingDirection = variables.lastDirection; + var preceedingDirection = variables.lastDirection; } - + // Firstly, don't add additional directions that are the same as where we're already headed // so we don't stack up redundant junk in the queue that makes the snake appear unresponsive. - // Secondly, only obey if the new direction isn't in the opposite (since that's an annoying instant "game over") - // UNLESS the snake is stil a baby-- then it can go anywhere it wants + // Secondly, only obey if the new direction isn't in the opposite (since that's an annoying instant "game over") + // UNLESS the snake is stil a baby-- then it can go anywhere it wants if( arguments.newDirection != preceedingDirection && ( arguments.newDirection != variables.directionOpposites[ preceedingDirection ] || isBaby() ) ) { - variables.direction.prepend( newDirection ); + variables.direction.prepend( newDirection ); } } } - + // This needs to be synchronized with go() private function getNextDirection() { lock name='snake_direction' type='exclusive' timeout=2 { @@ -257,17 +257,17 @@ component aliases="snake" { // Otherwise, just go the last place we went for lack of something better nextDirection = variables.lastDirection; } - + // Remember where we are going variables.lastDirection = nextDirection; return nextDirection; } } - + private function move( required direction ) { var head = variables.body[1]; var newHead = duplicate( head ); - + // Move the head switch( arguments.direction ) { case 'up': @@ -282,35 +282,35 @@ component aliases="snake" { case 'right': newHead.x++; break; - + } - + // If the snake bites an apple, it grows by one if( !bite( newHead ) ) { // Move tail variables.body.deleteAt( variables.body.len() ); } - + // If we hit something, the move failed if( isWallCollision( newHead ) || isSnakeCollision( newHead ) ) { return false; } - + // Move the snakes head variables.body.prepend( newHead ); - + // Move successful return true; } // This is a baby snake? i.e. Only 1 body segment. private function isBaby() { - return variables.body.len() == 1; + return variables.body.len() == 1; } private function resetGame() { - + // An array of coordinates that represent where the snake is // He starts in the bottom center with a lenth of "1" variables.body = [ @@ -319,16 +319,16 @@ component aliases="snake" { y : variables.height-1 } ]; - + // Number of apples to start the game with variables.appleCount = 6; variables.biteCount = 0; - + // An array of apples variables.apples = []; - + seedApples(); - + // Direction is an array to capture multiple key strokes that are // pressed between screen refreshes variables.direction = [ 'up' ]; @@ -336,26 +336,26 @@ component aliases="snake" { variables.lastDirection = 'up'; variables.collision = false; } - + private function seedApples() { - + // Randomly seed our apples while( variables.apples.len() < variables.appleCount ) { var newApple = { x : randRange( 1, variables.width ), y : randRange( 1, variables.height ) }; - + // Make sure we don't double-stack our apples, or put them on the snake if( !isSnakeCollision( newApple ) && !isAppleCollision( newApple ) ) { - variables.apples.append( newApple ); + variables.apples.append( newApple ); } } - + } - + private function isWallCollision( location ) { - + // Check collision with outside of play area if( location.x < 1 @@ -365,25 +365,25 @@ component aliases="snake" { ) { return true; } - + return false; } - - + + private function isSnakeCollision( location ) { - + // Check collision with snake for( piece in variables.body ) { - if( piece.x == location.x && piece.y == location.y ) { + if( piece.x == location.x && piece.y == location.y ) { return true; } } - + return false; } - + private function bite( location ) { - + // Check to see if we reached an apple for( apple in variables.apples ) { if( apple.x == location.x && apple.y == location.y ) { @@ -391,62 +391,62 @@ component aliases="snake" { variables.biteCount++; // Remove that apple from the game area variables.apples.delete( apple ); - + // If that was the last apple if( !variables.apples.len() ) { // Add some more! variables.appleCount += 6; - seedApples(); + seedApples(); } - + return true; } } - + return false; - + } - + private function isAppleCollision( location ) { - + // Check to see if this location is an an apple for( apple in variables.apples ) { if( apple.x == location.x && apple.y == location.y ) { return true; } } - + return false; - + } - + private function isQuit( key ) { // q or Q return ( key == 113 || key == 81 ); } - + private function isRetry( key ) { // r or R return ( key == 114 || key == 82 ); } - + private function isUp( key ) { - // e or E + // e or E return ( key == 101 || key == 69 || key == 56 ); } - + private function isDown( key ) { - // c or C + // c or C return ( key == 99 || key == 67 || key == 50 ); } - + private function isLeft( key ) { - // s or S + // s or S return ( key == 115 || key == 83 || key == 52 ); } - + private function isRight( key ) { - // f or F + // f or F return ( key == 102 || key == 70 || key == 54 ); } diff --git a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/appender.cfc b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/appender.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/appender.cfc +++ b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/appender.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/config.cfc b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/config.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/config.cfc +++ b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/config.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/help.cfc b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/help.cfc index b05fec6ec..7e80e0fd8 100644 --- a/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/help.cfc +++ b/src/cfml/system/modules_app/logbox-commands/commands/logbox/create/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use logbox create' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/logbox-commands/commands/logbox/help.cfc b/src/cfml/system/modules_app/logbox-commands/commands/logbox/help.cfc index 4bf0ea640..ee6ba6818 100644 --- a/src/cfml/system/modules_app/logbox-commands/commands/logbox/help.cfc +++ b/src/cfml/system/modules_app/logbox-commands/commands/logbox/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use logbox' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/endpoint/login.cfc b/src/cfml/system/modules_app/package-commands/commands/endpoint/login.cfc index 9a67078b2..be497525b 100644 --- a/src/cfml/system/modules_app/package-commands/commands/endpoint/login.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/endpoint/login.cfc @@ -6,29 +6,29 @@ * {code} **/ component { - - property name="EndpointService" inject="EndpointService"; - - /** + + property name="EndpointService" inject="EndpointService"; + + /** * @endpointName.hint Name of the endpoint to log in to * @username.hint Username for this user * @password.hint Password for this user **/ - function run( + function run( required string endpointName, required string username, required string password ) { - + try { - + endpointService.loginEndpointUser( argumentCollection=arguments ); - + } catch( endpointException var e ) { // This can include "expected" errors such as "Email already in use" error( e.message, e.detail ); } - - print.greenLine( 'User [#arguments.username#] authenticated successfully with [#arguments.endpointName#]' ); + + print.greenLine( 'User [#arguments.username#] authenticated successfully with [#arguments.endpointName#]' ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/endpoint/publish.cfc b/src/cfml/system/modules_app/package-commands/commands/endpoint/publish.cfc index d3e0ae9c3..2103e4d75 100644 --- a/src/cfml/system/modules_app/package-commands/commands/endpoint/publish.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/endpoint/publish.cfc @@ -6,36 +6,36 @@ * {code} **/ component { - + property name="endpointService" inject="EndpointService"; property name="packageService" inject="PackageService"; - property name='interceptorService' inject='interceptorService'; - - /** + property name='interceptorService' inject='interceptorService'; + + /** * @endpointName Name of the endpoint for which to publish the package * @directory The directory being published **/ - function run( + function run( required string endpointName, - string directory='' - ){ + string directory='' + ){ // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); var boxJSON = packageService.readPackageDescriptor( arguments.directory ); interceptorService.announceInterception( 'prePublish', { publishArgs=arguments, boxJSON=boxJSON } ); - + try { - + endpointService.publishEndpointPackage( argumentCollection=arguments ); - + } catch( endpointException var e ) { // This can include "expected" errors such as "Email already in use" error( e.message, e.detail ); } - + interceptorService.announceInterception( 'postPublish', { publishArgs=arguments, boxJSON=boxJSON } ); - + print.greenLine( 'Package published successfully in [#arguments.endpointName#]' ); } diff --git a/src/cfml/system/modules_app/package-commands/commands/endpoint/register.cfc b/src/cfml/system/modules_app/package-commands/commands/endpoint/register.cfc index 2047e2ed8..a06e18326 100644 --- a/src/cfml/system/modules_app/package-commands/commands/endpoint/register.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/endpoint/register.cfc @@ -2,14 +2,14 @@ * Registers a new user with an endpoint. The endpoint must be interactive. * . * {code:bash} - * endpoint register + * endpoint register * {code} **/ component { - - property name="EndpointService" inject="EndpointService"; - - /** + + property name="EndpointService" inject="EndpointService"; + + /** * @endpointName.hint Name of the endpoint for which to create the user * @username.hint Username for this user * @password.hint Password for this user @@ -17,24 +17,24 @@ component { * @firstName.hint First name of the user * @lastName.hint Last name of the user **/ - function run( + function run( required string endpointName, required string username, required string password, required string email, required string firstName, required string lastName ) { - + try { - + endpointService.createEndpointUser( argumentCollection=arguments ); - + } catch( endpointException var e ) { // This can include "expected" errors such as "Email already in use" error( e.message, e.detail ); } - - print.greenLine( 'User [#arguments.username#] created successfully in [#arguments.endpointName#]' ); + + print.greenLine( 'User [#arguments.username#] created successfully in [#arguments.endpointName#]' ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc b/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc index e81985e1d..9fc46842b 100644 --- a/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/endpoint/unpublish.cfc @@ -7,23 +7,23 @@ * {code} **/ component { - + property name="endpointService" inject="EndpointService"; property name="packageService" inject="PackageService"; - property name='interceptorService' inject='interceptorService'; - - /** + property name='interceptorService' inject='interceptorService'; + + /** * @endpointName Name of the endpoint for which to unpublish the package * @version The version being unpublished * @directory The directory being unpublished * @force Skip the prompt **/ - function run( + function run( required string endpointName, string version='', string directory='', boolean force=false - ){ + ){ // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); var boxJSON = packageService.readPackageDescriptor( arguments.directory ); @@ -33,22 +33,22 @@ component { } interceptorService.announceInterception( 'preUnpublish', { unpublishArgs=arguments, boxJSON=boxJSON } ); - + try { - + endpointService.unpublishEndpointPackage( argumentCollection=arguments ); - + } catch( endpointException var e ) { // This can include "expected" errors such as "Email already in use" error( e.message, e.detail ); } - + interceptorService.announceInterception( 'postUnpublish', { unpublishArgs=arguments, boxJSON=boxJSON } ); - + if( len( arguments.version ) ) { - print.greenLine( 'Package version [#boxJSON.slug#@#arguments.version#] unpublished successfully in [#arguments.endpointName#]' ); + print.greenLine( 'Package version [#boxJSON.slug#@#arguments.version#] unpublished successfully in [#arguments.endpointName#]' ); } else { - print.greenLine( 'Package [#boxJSON.slug#] unpublished successfully in [#arguments.endpointName#]' ); + print.greenLine( 'Package [#boxJSON.slug#] unpublished successfully in [#arguments.endpointName#]' ); } } diff --git a/src/cfml/system/modules_app/package-commands/commands/package/bugs.cfc b/src/cfml/system/modules_app/package-commands/commands/package/bugs.cfc index 3bf2440e8..10cf2fb11 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/bugs.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/bugs.cfc @@ -11,28 +11,28 @@ * {code} **/ component aliases="bugs" { - + property name="packageService" inject="PackageService"; - + /** * run **/ function run(){ - + // package check if( !packageService.isPackage( getCWD() ) ) { return error( '#getCWD()# is not a package!' ); } - + var boxJSON = packageService.readPackageDescriptor( getCWD() ); - + if( len( boxJSON.bugs ) and isValid( "URL", boxJSON.bugs ) ){ print.greenLine( "Opening: #boxJSON.bugs#" ); openURL( boxJSON.bugs ); } else { print.redLine( "The 'bugs' set in the descriptor is not valid: " & boxJSON.bugs ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc b/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc index 915f0d4ff..f89ed2008 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/clear.cfc @@ -9,55 +9,55 @@ * . **/ component { - + property name="packageService" inject="PackageService"; - property name="JSONService" inject="JSONService"; - - /** - * @property.hint Name of the property to clear + property name="JSONService" inject="JSONService"; + + /** + * @property.hint Name of the property to clear * @property.optionsUDF completeProperty * @system.hint When true, show box.json data in the global CommandBox folder **/ function run( required string property, boolean system=false ) { - + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // Check and see if box.json exists if( !packageService.isPackage( directory ) ) { return error( 'File [#packageService.getDescriptorPath( directory )#] does not exist. Use the "init" command to create it.' ); } - + if( arguments.property == 'name' ) { - return error( '[name] is a required property and cannot be cleared.' ); + return error( '[name] is a required property and cannot be cleared.' ); } if( arguments.property == 'slug' ) { - return error( '[slug] is a required property and cannot be cleared.' ); + return error( '[slug] is a required property and cannot be cleared.' ); } var boxJSON = packageService.readPackageDescriptorRaw( directory ); - + try { JSONService.clear( boxJSON, arguments.property ); } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { rethrow; - } - + } + print.greenLine( 'Removed #arguments.property#' ); - + // Write the file back out. PackageService.writePackageDescriptor( boxJSON, directory ); - + } // Dynamic completion for property name based on contents of box.json function completeProperty() { var directory = fileSystemUtil.resolvePath( '' ); - return packageService.completeProperty( directory ); + return packageService.completeProperty( directory ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/documentation.cfc b/src/cfml/system/modules_app/package-commands/commands/package/documentation.cfc index 61c9cbe97..371078dcd 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/documentation.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/documentation.cfc @@ -11,28 +11,28 @@ * {code} **/ component aliases="docs,documentation" { - + property name="packageService" inject="PackageService"; - + /** * run **/ function run(){ - + // package check if( !packageService.isPackage( getCWD() ) ) { return error( '#getCWD()# is not a package!' ); } - + var boxJSON = packageService.readPackageDescriptor( getCWD() ); - + if( len( boxJSON.documentation ) and isValid( "URL", boxJSON.documentation ) ){ print.greenLine( "Opening: #boxJSON.documentation#" ); openURL( boxJSON.documentation ); } else { print.redLine( "The 'documentation' set in the descriptor is not valid: " & boxJSON.documentation ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/help.cfc b/src/cfml/system/modules_app/package-commands/commands/package/help.cfc index 8e07d155d..e5d476b52 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/help.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellow( 'The ' ); print.boldYellow( 'package' ); print.yellowLine( ' namespace is for dealing with packages and their box.json descriptor file' ); print.yellowLine( 'Use these commands to initialize a package, set, and retreive values from the box.json descriptor.' ); print.yellowLine( 'Type help before any command name to get additional information on how to call that specific command.' ); - + print.line(); print.line(); diff --git a/src/cfml/system/modules_app/package-commands/commands/package/homepage.cfc b/src/cfml/system/modules_app/package-commands/commands/package/homepage.cfc index a99c3a7c2..7c35aecbe 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/homepage.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/homepage.cfc @@ -11,28 +11,28 @@ * {code} **/ component aliases="homepage" { - + property name="packageService" inject="PackageService"; - + /** * run **/ function run(){ - + // package check if( !packageService.isPackage( getCWD() ) ) { return error( '#getCWD()# is not a package!' ); } - + var boxJSON = packageService.readPackageDescriptor( getCWD() ); - + if( len( boxJSON.homepage ) and isValid( "URL", boxJSON.homepage ) ){ print.greenLine( "Opening: #boxJSON.homepage#" ); openURL( boxJSON.homepage ); } else { print.redLine( "The 'homepage' set in the descriptor is not valid: " & boxJSON.homepage ); } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/init-wizard.cfc b/src/cfml/system/modules_app/package-commands/commands/package/init-wizard.cfc index 34e4c7419..328dbbac9 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/init-wizard.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/init-wizard.cfc @@ -4,7 +4,7 @@ component extends="init" { /** - * @name The human-readable name for this package + * @name The human-readable name for this package * @slug The ForgeBox or unique slug for this package (no spaces or special chars) * @version The version for this package, please use semantic versioning - 0.0.0 * @private Would you like to mark your package as private, which prevents it to submit it to ForgeBox @@ -14,8 +14,8 @@ component extends="init" { * @homepage Your package's homepage URL * @ignoreList Add commonly ignored files to the package's ignore list **/ - function run( - required name, + function run( + required name, required slug, required version, required boolean private, @@ -27,6 +27,6 @@ component extends="init" { ){ // turn off wizard arguments.wizard = false; - super.run( argumentCollection=arguments ); + super.run( argumentCollection=arguments ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/init.cfc b/src/cfml/system/modules_app/package-commands/commands/package/init.cfc index 73f8e5e71..946b26e4f 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/init.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/init.cfc @@ -11,7 +11,7 @@ * init --wizard * {code} * . - * Pass in an arguments you want and a property in the box.json will be initialized with the + * Pass in an arguments you want and a property in the box.json will be initialized with the * same name as the argument name using the argument value. * {code:bash} * init name="My App" slug=myApp version=1.0.0.0 @@ -24,7 +24,7 @@ component aliases="init" { property name="PackageService" inject="PackageService"; /** - * @name The human-readable name for this package + * @name The human-readable name for this package * @slug The ForgeBox or unique slug for this package (no spaces or special chars) * @version The version for this package, please use semantic versioning - 0.0.0 * @private Would you like to mark your package as private, which prevents it to submit it to ForgeBox @@ -32,8 +32,8 @@ component aliases="init" { * @ignoreList Add commonly ignored files to the package's ignore list * @wizard Run the init wizard, defaults to false **/ - function run( - name="My Package", + function run( + name="My Package", slug="my-package", version="0.0.0", boolean private=false, @@ -46,20 +46,20 @@ component aliases="init" { runCommand( 'package init-wizard' ); return; } - + // Clean this up so it doesn't get written as a property structDelete( arguments, "wizard" ); - + // This will make each directory canonical and absolute var directory = getCWD(); - + // Read current box.json if it exists, otherwise, get a new one var boxJSON = PackageService.readPackageDescriptorTemplate( directory ); // Don't use these defaults if the existing box.json already has something useful if( len( boxJSON.name ) && arguments.name == 'My Package' ) { structDelete( arguments, 'name' ); - } + } if( len( boxJSON.slug ) && arguments.slug == 'my-package' ) { structDelete( arguments, 'slug' ); } @@ -78,14 +78,14 @@ component aliases="init" { if( isJSON( propertyValue ) ) { evaluate( '#fullPropertyName# = deserializeJSON( arguments[ arg ] )' ); } else { - evaluate( '#fullPropertyName# = arguments[ arg ]' ); + evaluate( '#fullPropertyName# = arguments[ arg ]' ); } print.magentaLine( '- Set #arg# = #arguments[ arg ]#' ); } - + // Write the file back out PackageService.writePackageDescriptor( boxJSON, directory ); - + // Info message print.yellowLine( 'Package Initialized & Created ' & directory & 'box.json' ).toConsole(); } diff --git a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc index 719050d7b..19ab91cba 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/install.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/install.cfc @@ -134,7 +134,7 @@ component aliases="install" { if( arguments.system ) { arguments.currentWorkingDirectory = expandPath( '/commandbox' ); } else { - arguments.currentWorkingDirectory = getCWD(); + arguments.currentWorkingDirectory = getCWD(); } // Make ID an array arguments.IDArray = listToArray( arguments.ID ); @@ -166,7 +166,7 @@ component aliases="install" { try { var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); // Get auto-complete options - return forgebox.slugSearch( searchTerm=arguments.paramSoFar, APIToken=APIToken ); + return forgebox.slugSearch( searchTerm=arguments.paramSoFar, APIToken=APIToken ); } catch( forgebox var e ) { // Gracefully handle ForgeBox issues print @@ -181,4 +181,3 @@ component aliases="install" { } } - diff --git a/src/cfml/system/modules_app/package-commands/commands/package/list.cfc b/src/cfml/system/modules_app/package-commands/commands/package/list.cfc index 8abb683e0..be2e40b82 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/list.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/list.cfc @@ -20,27 +20,27 @@ * {code} **/ component aliases="list" { - + processingdirective pageEncoding='UTF-8'; - - property name="packageService" inject="PackageService"; - - /** + + property name="packageService" inject="PackageService"; + + /** * @verbose.hint Outputs additional informaiton about each package * @json.hint Outputs results as JSON - * @system.hint When true, list packages from the global CommandBox module's folder + * @system.hint When true, list packages from the global CommandBox module's folder **/ function run( boolean verbose=false, boolean JSON=false, boolean system=false ) { - + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // package check if( !packageService.isPackage( directory ) ) { return error( '#directory# is not a package!' ); @@ -51,12 +51,12 @@ component aliases="list" { // JSON output if( arguments.JSON ) { print.line( formatterUtil.formatJson( serializeJSON( tree ) ) ); - return; + return; } // normal output print.green( 'Dependency Hierarchy for ' ).boldCyanLine( "#tree.name# (#tree.version#)" ); printDependencies( tree, '', arguments.verbose ); - + } /** @@ -72,22 +72,22 @@ component aliases="list" { var isLast = ( i == depCount ); var branch = ( isLast ? '└' : '├' ) & '─' & ( childDepCount ? '┬' : '─' ); var branchCont = ( isLast ? ' ' : '│' ) & ' ' & ( childDepCount ? '│' : ' ' ); - + print.text( prefix & branch & ' ' ); - + print[ ( dependency.dev ? 'boldYellowline' : 'boldLine' ) ]( '#dependencyName# (#dependency.packageVersion#)' ); - + if( arguments.verbose ) { if( len( dependency.name ) ) { print.text( prefix & branchCont & ' ' ); - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ); } if( len( dependency.shortDescription ) ) { print.text( prefix & branchCont & ' ' ); - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ); } } // end verbose? - + printDependencies( dependency, prefix & ( isLast ? ' ' : '│ ' ), arguments.verbose ); } } diff --git a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc index b41a50049..499724373 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/outdated.cfc @@ -19,38 +19,38 @@ * {code} **/ component aliases="outdated" { - + processingdirective pageEncoding='UTF-8'; - + // DI property name="packageService" inject="PackageService"; property name="semanticVersion" inject="semanticVersion@semver"; - - /** + + /** * @verbose.hint Outputs additional information about each package * @json.hint Outputs results as JSON - * @system.hint When true, check the global CommandBox module's folder + * @system.hint When true, check the global CommandBox module's folder **/ function run( boolean verbose=false, boolean JSON=false, boolean system=false ) { - + if( arguments.JSON ) { arguments.verbose = false; } - + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // package check if( !packageService.isPackage( directory ) ) { return error( '#directory# is not a package!' ); } - + // echo output if( !arguments.JSON ) { print.yellowLine( "Resolving Dependencies, please wait..." ).toConsole(); @@ -62,7 +62,7 @@ component aliases="outdated" { // JSON output if( arguments.JSON ) { print.line( formatterUtil.formatJson( serializeJSON( aOutdatedDependencies ) ) ); - return; + return; } // normal output @@ -76,25 +76,25 @@ component aliases="outdated" { } else { print.boldYellowLine( 'There are no outdated dependencies!' ); } - + } /** * Pretty print dependencies */ private function printDependencies( required array data, boolean verbose ) { - - for( var dependency in arguments.data ){ + + for( var dependency in arguments.data ){ // print it out print[ ( dependency.dev ? 'boldYellow' : 'bold' ) ]( '* #dependency.slug# (#dependency.packageVersion#)' ) .boldRedLine( ' ─> new version: #dependency.newVersion#' ); - // verbose data + // verbose data if( arguments.verbose ) { if( len( dependency.name ) ) { - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ); } if( len( dependency.shortDescription ) ) { - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ); } print.line(); } // end verbose? diff --git a/src/cfml/system/modules_app/package-commands/commands/package/run-script.cfc b/src/cfml/system/modules_app/package-commands/commands/package/run-script.cfc index a63f0be8a..86eb08d07 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/run-script.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/run-script.cfc @@ -1,5 +1,5 @@ /** - * Runs a package script, by name. Scripts are stored in box.json. + * Runs a package script, by name. Scripts are stored in box.json. * . * {code:bash} * run-script myScript @@ -7,28 +7,28 @@ * . **/ component aliases="run-script" { - + property name="packageService" inject="PackageService"; - + /** * @scriptName Name of the script to run * @scriptName.optionsUDF scriptNameComplete * @directory The path to your package **/ function run( required string scriptname, string directory='' ){ - - // This will make each directory canonical and absolute + + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // package check if( !packageService.isPackage( arguments.directory ) ) { return error( '#arguments.directory# is not a package!' ); } - + packageService.runScript( arguments.scriptName, arguments.directory, false ); - + } - + function scriptNameComplete() { var boxJSON = packageService.readPackageDescriptor( shell.pwd() ); return boxJSON.scripts.keyArray(); diff --git a/src/cfml/system/modules_app/package-commands/commands/package/set.cfc b/src/cfml/system/modules_app/package-commands/commands/package/set.cfc index ae6a9b718..dea6f4557 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/set.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/set.cfc @@ -37,30 +37,30 @@ * {code:bash} * package set contributors="[ 'brad@coldbox.org' ]" --append * {code} - * + * **/ component { - + property name="packageService" inject="PackageService"; - property name="JSONService" inject="JSONService"; - + property name="JSONService" inject="JSONService"; + /** * This param is a dummy param just to get the custom completor to work. - * The actual parameter names will be whatever property name the user wants to set - * @_.hint Pass any number of property names in followed by the value to set - * @_.optionsUDF completeProperty + * The actual parameter names will be whatever property name the user wants to set + * @_.hint Pass any number of property names in followed by the value to set + * @_.optionsUDF completeProperty * @append.hint If setting an array or struct, set to true to append instead of overwriting. * @system.hint When true, show box.json data in the global CommandBox folder **/ function run( _, boolean append=false, boolean system=false ) { - var thisAppend = arguments.append; - + var thisAppend = arguments.append; + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // Remove dummy args structDelete( arguments, '_' ); structDelete( arguments, 'append' ); @@ -73,15 +73,15 @@ component { // Read without defaulted values var boxJSON = packageService.readPackageDescriptorRaw( directory ); - var results = JSONService.set( boxJSON, arguments, thisAppend ); + var results = JSONService.set( boxJSON, arguments, thisAppend ); // Write the file back out. PackageService.writePackageDescriptor( boxJSON, directory ); - + for( var message in results ) { print.greeLine( message ); } - + } // Dynamic completion for property name based on contents of box.json diff --git a/src/cfml/system/modules_app/package-commands/commands/package/show.cfc b/src/cfml/system/modules_app/package-commands/commands/package/show.cfc index 123b1072f..4c086d21e 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/show.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/show.cfc @@ -27,41 +27,41 @@ * . **/ component { - + property name="packageService" inject="PackageService"; property name="JSONService" inject="JSONService"; - + /** * @property.hint The name of the property to show. Can nested to get "deep" properties * @property.optionsUDF completeProperty * @system.hint When true, show box.json data in the global CommandBox folder **/ function run( string property='', boolean system=false ) { - + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // Check and see if box.json exists if( !packageService.isPackage( directory ) ) { return error( 'File [#packageService.getDescriptorPath( directory )#] does not exist. Use the "init" command to create it.' ); } - + // Read without defaulted values var boxJSON = packageService.readPackageDescriptorRaw( directory ); try { - + var propertyValue = JSONService.show( boxJSON, arguments.property ); - + if( isSimpleValue( propertyValue ) ) { print.line( propertyValue ); } else { - print.line( formatterUtil.formatJson( propertyValue ) ); + print.line( formatterUtil.formatJson( propertyValue ) ); } - + } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { @@ -73,6 +73,6 @@ component { // Dynamic completion for property name based on contents of box.json function completeProperty() { var directory = fileSystemUtil.resolvePath( '' ); - return packageService.completeProperty( directory ); + return packageService.completeProperty( directory ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc b/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc index eef12b0c2..3dffd7da9 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/uninstall.cfc @@ -1,9 +1,9 @@ /** * Uninstall a package from your application. The installation path is pulled from box.json based on package name. - * If the package being uninstalled has a box.json, any dependencies and devDependencies + * If the package being uninstalled has a box.json, any dependencies and devDependencies * will also be uninstalled as well. * . - * If a directory is supplied, the package will be looked for in that directory. Otherwise, the box.json for the packge will be + * If a directory is supplied, the package will be looked for in that directory. Otherwise, the box.json for the packge will be * inspected for an install path for that package. Lasty, the command will look in the current directory for a folder named after the package. * . * Uninstall the feeds package @@ -18,51 +18,51 @@ * . **/ component aliases="uninstall" { - + // DI property name="forgeBox" inject="ForgeBox"; property name="packageService" inject="PackageService"; - + /** - * @slug.hint Slug of the package to uninstall. + * @slug.hint Slug of the package to uninstall. * @slug.optionsUDF slugComplete * @directory.hint The directory the package is currently installed in including the container folder * @save.hint Remove package as a dependancy in box.json (if it exists) * @system.hint When true, uninstall this package from the global CommandBox module's folder **/ - function run( + function run( required string slug='', string directory, boolean save=true, boolean system=false ){ - - // Don't default the dir param since we need to differentiate whether the user actually + + // Don't default the dir param since we need to differentiate whether the user actually // specifically typed in a param or not since it overrides the package's box.json install dir. if( structKeyExists( arguments, 'directory' ) ) { - + arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { return error( 'The directory [#arguments.directory#] doesn''t exist.' ); } - + } - + if( arguments.system ) { arguments.currentWorkingDirectory = expandPath( '/commandbox' ); } else { - arguments.currentWorkingDirectory = getCWD(); + arguments.currentWorkingDirectory = getCWD(); } - + // Convert slug to array arguments.slug = listToArray( arguments.slug ); // iterate and uninstall. for( var thisSlug in arguments.slug ){ arguments.ID = thisSlug; // Uninstall this package. - // Don't pass directory unless you intend to override the box.json of the package being uninstalled + // Don't pass directory unless you intend to override the box.json of the package being uninstalled packageService.uninstallPackage( argumentCollection = arguments ); } } @@ -71,13 +71,13 @@ component aliases="uninstall" { function slugComplete() { var results = []; var directory = getCWD(); - + if( packageService.isPackage( directory ) ) { var BoxJSON = packageService.readPackageDescriptor( directory ); results.append( BoxJSON.installPaths.keyArray(), true ); } - + return results; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc index 72ca4ebe3..8d6b337a0 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/update.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/update.cfc @@ -27,16 +27,16 @@ * {code} **/ component aliases="update" { - + processingdirective pageEncoding='UTF-8'; - + // DI property name="packageService" inject="PackageService"; property name="semanticVersion" inject="semanticVersion@semver"; property name='parser' inject='Parser'; - - /** - * Update all or one outdated dependencies + + /** + * Update all or one outdated dependencies * @slug A comma-delimmited list of slugs to update. Pass nothing to update all packages. * @slug.optionsUDF slugComplete * @verbose Outputs additional information about each package @@ -48,18 +48,18 @@ component aliases="update" { boolean verbose=false, boolean force=false, boolean system=false ) { - + if( arguments.system ) { var directory = expandPath( '/commandbox' ); } else { - var directory = getCWD(); + var directory = getCWD(); } - + // package check if( !packageService.isPackage( directory ) ) { return error( '#directory# is not a package!' ); } - + // echo output print.yellowLine( "Resolving Dependencies, please wait..." ).toConsole(); @@ -70,7 +70,7 @@ component aliases="update" { verbose=arguments.verbose, includeSlugs=arguments.slug ); - + // Advice initial notice if( dependenciesToUpdate.len() ){ print.green( 'Found ' ) @@ -89,7 +89,7 @@ component aliases="update" { // iterate and update for( var dependency in dependenciesToUpdate ){ - + // Contains an endpoint if( dependency.version contains ':' ) { var oldID = dependency.version; @@ -98,37 +98,37 @@ component aliases="update" { var oldID = dependency.slug & '@' & dependency.Version; var newID = dependency.slug & '@' & dependency.newVersion; } - + print.magentaLine( "Starting update of #oldID# ").toConsole(); // install it command( 'install' ) - .params( + .params( ID=newID, verbose=arguments.verbose, directory=dependency.directory ) .flags( 'force', '!save' ) .run( echo=arguments.verbose ) } - + } /** * Pretty print dependencies */ private function printDependencies( required array data, boolean verbose ) { - + for( var dependency in arguments.data ){ // print it out print[ ( dependency.dev ? 'boldYellow' : 'bold' ) ]( '* #dependency.slug# (#dependency.version#)' ) .boldRedLine( ' ─> new version: #dependency.newVersion#' ) .toConsole(); - // verbose data + // verbose data if( arguments.verbose ) { if( len( dependency.name ) ) { - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ).toConsole(); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.name ).toConsole(); } if( len( dependency.shortDescription ) ) { - print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ).toConsole(); + print[ ( dependency.dev ? 'yellowLine' : 'line' ) ]( dependency.shortDescription ).toConsole(); } print.line().toConsole(); } // end verbose? @@ -140,12 +140,12 @@ component aliases="update" { function slugComplete() { var results = []; var directory = getCWD(); - + if( packageService.isPackage( directory ) ) { var BoxJSON = packageService.readPackageDescriptor( directory ); results.append( BoxJSON.installPaths.keyArray(), true ); } - + return results; } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/commands/package/version.cfc b/src/cfml/system/modules_app/package-commands/commands/package/version.cfc index 88d322004..18114dbe6 100644 --- a/src/cfml/system/modules_app/package-commands/commands/package/version.cfc +++ b/src/cfml/system/modules_app/package-commands/commands/package/version.cfc @@ -14,7 +14,7 @@ * {code} * . * "Bump" the existing version number up by one unit and save in your box.json. - * Specify the part of the version to increase with the major, minor, or patch parameter. + * Specify the part of the version to increase with the major, minor, or patch parameter. * Note, "package version" is aliased as "bump". * . * {code:bash} @@ -23,17 +23,17 @@ * bump --patch * {code} * . - * If multiple version parts are specified, the "larger" one will be used starting with major. + * If multiple version parts are specified, the "larger" one will be used starting with major. * If a version AND a flag are both supplied, the version will be used and the flag(s) ignored. * - * If your package is a Git repo AND it is clean, this command will attempt to tag it with the new version number. + * If your package is a Git repo AND it is clean, this command will attempt to tag it with the new version number. * You can provide an optional commit message for this tag: * . * {code:bash} * bump --major message="finalizing release" * {code} - * - * If you don't want the tagging functionality, provide the "tagVersion" flag or turn + * + * If you don't want the tagging functionality, provide the "tagVersion" flag or turn * off the setting globally with config setting. * . * {code:bash} @@ -42,13 +42,13 @@ * {code} **/ component aliases="bump" { - + property name='packageService' inject='PackageService'; property name='configService' inject='ConfigService'; property name='semanticVersion' inject='provider:semanticVersion@semver'; property name='interceptorService' inject='interceptorService'; - - /** + + /** * @version The new version to set into this package * @message The message to use when commiting the new tag * @tagVersion Whether or not to tag the repo @@ -70,51 +70,51 @@ component aliases="bump" { ) { // the CWD is our "package" arguments.directory = getCWD(); - + // Read the box.json. Missing values will NOT be defaulted. var boxJSON = packageService.readPackageDescriptorRaw( arguments.directory ); var versionObject = semanticVersion.parseVersion( trim( boxJSON.version ?: '' ) ); - + if( len( arguments.version ) ) { - + // Set a specific version arguments.version = semanticVersion.clean( arguments.version ); setVersion( argumentCollection=arguments ); - + } else if( structKeyExists( arguments, 'major' ) && arguments.major ) { - + // Bump major versionObject.major = val( versionObject.major ) + 1; versionObject.minor = 0; versionObject.revision = 0; arguments.version = semanticVersion.getVersionAsString( versionObject ); setVersion( argumentCollection=arguments ); - + } else if( structKeyExists( arguments, 'minor' ) && arguments.minor ) { - + // Bump minor versionObject.major = val( versionObject.major ); versionObject.minor = val( versionObject.minor ) + 1; versionObject.revision = 0; arguments.version = semanticVersion.getVersionAsString( versionObject ); setVersion( argumentCollection=arguments ); - + } else if( structKeyExists( arguments, 'patch' ) && arguments.patch ) { - - // Bump patch + + // Bump patch versionObject.major = val( versionObject.major ); versionObject.minor = val( versionObject.minor ); versionObject.revision = val( versionObject.revision ) + 1; arguments.version = semanticVersion.getVersionAsString( versionObject ); setVersion( argumentCollection=arguments ); - + } else { - + // Output the version return command( 'package show version' ) .run( returnOutput=true ); - } - + } + } function setVersion( required string version, boolean tagVersion, string message, string directory, required boolean force ) { @@ -124,9 +124,9 @@ component aliases="bump" { command( 'package set' ) .params( version=arguments.version ) .run(); - + interceptorService.announceInterception( 'postVersion', { versionArgs=arguments } ); - + // If this package is also a Git repository var repoPath = '#arguments.directory#/.git'; arguments.tagVersion = arguments.tagVersion ?: ConfigService.getSetting( 'tagVersion', true ); @@ -134,16 +134,16 @@ component aliases="bump" { print.yellowLine( 'Package is a Git repo. Tagging...' ); try { - + // The main Git API var GitAPI = createObject( 'java', 'org.eclipse.jgit.api.Git' ); - + var git = GitAPI.open( createObject( 'java', 'java.io.File' ).init( repoPath ) ); var diffs = git.diff() .setCached( true ) .setShowNameAndStatusOnly( true ) .call(); - + // Make sure there aren't staged file ready to commit (clean working dir) if( arrayLen( diffs ) && !arguments.force ) { print.line() @@ -153,37 +153,37 @@ component aliases="bump" { } error( 'Cannot tag Git repo. Please commit file, or use --force flag to skip this check' ); } - + arguments.message = arguments.message ?: ConfigService.getSetting( 'tagVersionMessage', '${version}' ); arguments.message = replaceNoCase( arguments.message, '${version}', arguments.version, 'all' ); arguments.tagPrefix = arguments.tagPrefix ?: ConfigService.getSetting( 'tagPrefix', 'v' ); - + // Add the box.json git.add() .addFilepattern( 'box.json' ) .call(); - + // Commit the box.json git.commit() - .setMessage( arguments.message ) + .setMessage( arguments.message ) .call(); - + // Tag this version git.tag() .setName( '#arguments.tagPrefix##arguments.version#' ) .setMessage( arguments.message ) .call(); - + print.yellowLine( 'Tag [#arguments.tagPrefix##arguments.version#] created.' ).toConsole(); } catch( any var e ) { logger.error( 'Error tagging Git repository with new version.', e ); error( 'Error tagging Git repository with new version.', e.message & ' ' & e.detail ); } - + } // end is Git repo and are we tagging? - + interceptorService.announceInterception( 'onRelease', { directory=arguments.directory, version=arguments.version } ); - + } - -} + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc b/src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc index a1a9f7c08..15d335832 100644 --- a/src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc +++ b/src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc @@ -12,7 +12,7 @@ component { property name="packageService" inject="packageService"; property name="shell" inject="shell"; property name='consoleLogger' inject='logbox:logger:console'; - + function onCLIStart() { processScripts( 'onCLIStart' ); } function onCLIExit() { processScripts( 'onCLIExit' ); } function preCommand() { processScripts( 'preCommand' ); } @@ -21,39 +21,39 @@ component { function postModuleLoad() { processScripts( 'postModuleLoad' ); } function preModuleUnLoad() { processScripts( 'preModuleUnLoad' ); } function postModuleUnload() { processScripts( 'postModuleUnload' ); } - + function preServerStart() { processScripts( 'preServerStart' ); } function onServerInstall() { processScripts( 'onServerInstall', interceptData.serverinfo.webroot ); } function onServerStart() { processScripts( 'onServerStart', interceptData.serverinfo.webroot ); } function onServerStop() { processScripts( 'onServerStop', interceptData.serverinfo.webroot ); } function preServerForget() { processScripts( 'preServerForget', interceptData.serverinfo.webroot ); } function postServerForget() { processScripts( 'postServerForget', interceptData.serverinfo.webroot ); } - + function onException() { processScripts( 'onException' ); } - + // preInstall gets package requesting the installation because dep isn't installed yet function preInstall() { processScripts( 'preInstall', interceptData.packagePathRequestingInstallation ); } - + // onInstall gets package requesting the installation because dep isn't installed yet function onInstall() { processScripts( 'onInstall', interceptData.packagePathRequestingInstallation ); } - + // postInstall runs in the newly installed package function postInstall() { processScripts( 'postInstall', interceptData.installDirectory ); } - + // preUninstall runs in the package that's about to be uninstalled function preUninstall() { processScripts( 'preUninstall', interceptData.uninstallDirectory ); } - + // postUninstall gets package that requested uninstallation because dep isn't there any longer function postUninstall() { processScripts( 'postUninstall', interceptData.uninstallArgs.packagePathRequestingUninstallation ); } - + function preVersion() { processScripts( 'preVersion' ); } function postVersion() { processScripts( 'postVersion' ); } function onRelease() { processScripts( 'onRelease' ); } function prePublish() { processScripts( 'prePublish' ); } function postPublish() { processScripts( 'postPublish' ); } - + function processScripts( required string interceptionPoint, string directory=shell.pwd() ) { packageService.runScript( arguments.interceptionPoint, arguments.directory ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/cd.cfc b/src/cfml/system/modules_app/server-commands/commands/server/cd.cfc index 90cbc26c2..fc991759d 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/cd.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/cd.cfc @@ -16,7 +16,7 @@ component { * @name.optionsUDF serverNameComplete **/ function run( string name="" ){ - + // Discover by shortname var serverInfo = serverService.getServerInfoByName( arguments.name ); @@ -28,9 +28,9 @@ component { var cdCommand = 'cd ' & '"#parser.escapeArg( serverInfo.webroot )#"'; print.yellowLine( '> ' & cdCommand ); runCommand( cdCommand ); - + } - + function serverNameComplete() { return serverService.getServerNames(); } diff --git a/src/cfml/system/modules_app/server-commands/commands/server/clear.cfc b/src/cfml/system/modules_app/server-commands/commands/server/clear.cfc index 042a9d188..857a14747 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/clear.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/clear.cfc @@ -9,19 +9,19 @@ * . **/ component { - + property name="serverService" inject="ServerService"; - property name="JSONService" inject="JSONService"; - - /** - * @property.hint Name of the property to clear + property name="JSONService" inject="JSONService"; + + /** + * @property.hint Name of the property to clear * @property.optionsUDF completeProperty * @serverConfigFile The path to the server's JSON file. **/ function run( required string property, String serverConfigFile='' ) { - + // As a convenient shorcut, allow the serverConfigFile and propery parameter to be reversed because // "server show foo.json name" reads better than "server show name foo.json" but maintains backwards compat // for the simple use case of no JSON file as in "server show name" @@ -30,7 +30,7 @@ component { if( listLen( arguments.property, '.' ) > 1 && listLast( arguments.property, '.' ) == 'json' && fileExists( tmpPropertyResolved ) ) { // If so, swap the property into the server config param. arguments.property = arguments.serverConfigFile; - arguments.serverConfigFile = tmpPropertyResolved; + arguments.serverConfigFile = tmpPropertyResolved; } else if( len( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); if( !fileExists( arguments.serverConfigFile ) ) { @@ -39,27 +39,27 @@ component { } // Default the server.json in the CWD var thisServerConfigFile = ( len( arguments.serverConfigFile ) ? arguments.serverConfigFile : getCWD() & '/server.json' ); - + var serverJSON = ServerService.readServerJSON( thisServerConfigFile ); - + try { JSONService.clear( serverJSON, arguments.property ); } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { rethrow; - } - + } + print.greenLine( 'Removed #arguments.property#' ); - + // Write the file back out. ServerService.saveServerJSON( thisServerConfigFile, serverJSON ); - + } // Dynamic completion for property name based on contents of server.json function completeProperty() { - return serverService.completeProperty( getCWD() ); + return serverService.completeProperty( getCWD() ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/forget.cfc b/src/cfml/system/modules_app/server-commands/commands/server/forget.cfc index d5ead7fde..ee6fbd2b6 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/forget.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/forget.cfc @@ -29,13 +29,13 @@ component { String serverConfigFile, Boolean all=false, Boolean force=false - ){ + ){ if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); - } + } var serverInfo = serverService.resolveServerDetails( arguments ).serverinfo; var servers = arguments.all ? serverService.getServers() : { "#serverInfo.id#": serverInfo }; @@ -56,7 +56,7 @@ component { var askMessage = arguments.all ? "Really forget & delete all servers (#arrayToList( serverService.getServerNames() )#) forever [y/n]?" : "Really forget & delete server '#serverinfo.name#' forever [y/n]?"; - + if( arguments.force || confirm( askMessage ) ){ servers.each( function( ID ){ print @@ -68,7 +68,7 @@ component { } } - + private function runningServerCheck( required struct serverInfo ) { if( serverService.isServerRunning( serverInfo ) ) { print.redBoldLine( 'Server "#serverInfo.name#" (#serverInfo.webroot#) appears to still be running!' ) @@ -88,7 +88,7 @@ component { return servers[ arguments.ID ].name; } ); } - + function serverNameComplete() { return serverService.getServerNames(); } diff --git a/src/cfml/system/modules_app/server-commands/commands/server/help.cfc b/src/cfml/system/modules_app/server-commands/commands/server/help.cfc index 7fb91cb2f..32d8c71a4 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/help.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/help.cfc @@ -1,11 +1,11 @@ component excludeFromHelp=true { - + function run() { - + print.line() .yellow( 'The ' ).boldYellow( 'server' ).yellowLine( ' namespace contains commands that allow you to start, stop, ' ) .yellowLine( 'and manage the embedded CFML server to run your code quickly and easily.' ) - .yellowLine( 'Each server will start in its own process and run until you stop it.' ) + .yellowLine( 'Each server will start in its own process and run until you stop it.' ) .line() .line(); diff --git a/src/cfml/system/modules_app/server-commands/commands/server/list.cfc b/src/cfml/system/modules_app/server-commands/commands/server/list.cfc index 0177039f7..dd72fcf47 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/list.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/list.cfc @@ -86,10 +86,10 @@ component { .bold( status, statusColors.keyExists( status ) ? statusColors[ status ] : 'yellow' ) .bold( ')' ) .line(); - + if( arguments.verbose ) { - print.indentedLine( "host: " & thisServerInfo.host ); + print.indentedLine( "host: " & thisServerInfo.host ); if( len( thisServerInfo.engineName ) ) { print.indentedLine( "CF Engine: " & thisServerInfo.engineName & ' ' & thisServerInfo.engineVersion ); } @@ -100,7 +100,7 @@ component { } if( len( thisServerInfo.dateLastStarted ) ) { print.indentedLine( 'Last Started: ' & datetimeFormat( thisServerInfo.dateLastStarted ) ); - } + } print.indentedLine( "HTTPEnable: " & thisServerInfo.HTTPEnable ) .indentedLine( "port: " & thisServerInfo.port ) .indentedLine( "SSLEnable: " & thisServerInfo.SSLEnable ) @@ -136,7 +136,7 @@ component { } if( len( thisServerInfo.dateLastStarted ) ) { print.indentedLine( 'Last Started: ' & datetimeFormat( thisServerInfo.dateLastStarted ) ); - } + } }// end verbose } // End "filter" if diff --git a/src/cfml/system/modules_app/server-commands/commands/server/log.cfc b/src/cfml/system/modules_app/server-commands/commands/server/log.cfc index f11c3e514..e569048df 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/log.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/log.cfc @@ -27,10 +27,10 @@ component { ){ if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); - } + } var serverDetails = serverService.resolveServerDetails( arguments ); var serverInfo = serverDetails.serverInfo; @@ -38,28 +38,28 @@ component { if( serverDetails.serverIsNew ){ error( "The server you requested was not found.", "You can use the 'server list' command to get all the available servers." ); } - + var logfile = serverInfo.logdir & "/server.out.txt"; if( fileExists( logfile) ){ - + if( follow ) { command( 'tail' ) .params( logfile, 50 ) .flags( 'follow' ) .run(); } else { - return fileRead( logfile ); + return fileRead( logfile ); } - + } else { print.boldRedLine( "No log file found for '#serverInfo.webroot#'!" ) .line( "#logFile#" ); } } - + function serverNameComplete() { return serverService.getServerNames(); } - -} + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/open.cfc b/src/cfml/system/modules_app/server-commands/commands/server/open.cfc index 60cceb3f7..145fb0373 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/open.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/open.cfc @@ -12,10 +12,10 @@ * {code} **/ component { - + // DI property name="serverService" inject="ServerService"; - + /** * @URI An additional URI to go to when opening the server browser, else it just opens localhost:port * @name.hint the short name of the server @@ -23,7 +23,7 @@ component { * @directory.hint web root for the server * @serverConfigFile The path to the server's JSON file. **/ - function run( + function run( URI="/", string name, string directory, @@ -31,13 +31,13 @@ component { ){ if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); - } + } var serverDetails = serverService.resolveServerDetails( arguments ); var serverInfo = serverDetails.serverInfo; - + if( serverDetails.serverIsNew ){ print.boldRedLine( "No server configurations found so have no clue what to open buddy!" ); } else { @@ -48,17 +48,17 @@ component { var thisURL = "#serverInfo.host#:#serverInfo.port##arguments.URI#"; print.greenLine( "Opening...#thisURL#" ); openURL( thisURL ); - - + + } } - + /** * Complete server names */ function serverNameComplete() { return serverService.getServerNames(); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/restart.cfc b/src/cfml/system/modules_app/server-commands/commands/server/restart.cfc index 8d3d9efd0..5ee4c8678 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/restart.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/restart.cfc @@ -30,10 +30,10 @@ component aliases="restart" { ){ if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); - } + } var serverDetails = serverService.resolveServerDetails( arguments ); var serverInfo = serverDetails.serverInfo; @@ -49,14 +49,14 @@ component aliases="restart" { print.boldCyanLine( "Trying to stop server..." ); print.yellowLine( '> ' & stopCommand ); runCommand( stopCommand ); - + // start up server print.line().boldCyanLine( "Trying to start server..." ); print.yellowLine( '> ' & startCommand ); runCommand( startCommand ); } - + function serverNameComplete() { return serverService.getServerNames(); } diff --git a/src/cfml/system/modules_app/server-commands/commands/server/set.cfc b/src/cfml/system/modules_app/server-commands/commands/server/set.cfc index b133c746b..d9b6ac3c0 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/set.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/set.cfc @@ -36,49 +36,49 @@ * {code:bash} * server set aliases="[ '/includes' ]" --append * {code} - * + * **/ component { - + property name="ServerService" inject="ServerService"; - property name="JSONService" inject="JSONService"; - + property name="JSONService" inject="JSONService"; + /** * This param is a dummy param just to get the custom completor to work. - * The actual parameter names will be whatever property name the user wants to set - * @_.hint Pass any number of property names in followed by the value to set + * The actual parameter names will be whatever property name the user wants to set + * @_.hint Pass any number of property names in followed by the value to set * @_.optionsUDF completeProperty - * @serverConfigFile The path to the server's JSON file. + * @serverConfigFile The path to the server's JSON file. * @append.hint If setting an array or struct, set to true to append instead of overwriting. **/ - function run( + function run( _, String serverConfigFile='', boolean append=false ) { - + var thisAppend = arguments.append; if( len( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); } var thisServerConfigFile = ( len( arguments.serverConfigFile ) ? arguments.serverConfigFile : getCWD() & '/server.json' ); - + // Remove dummy args structDelete( arguments, '_' ); structDelete( arguments, 'append' ); - structDelete( arguments, 'serverConfigFile' ); + structDelete( arguments, 'serverConfigFile' ); var serverJSON = ServerService.readServerJSON( thisServerConfigFile ); - var results = JSONService.set( serverJSON, arguments, thisAppend ); + var results = JSONService.set( serverJSON, arguments, thisAppend ); // Write the file back out. ServerService.saveServerJSON( thisServerConfigFile, serverJSON ); - + for( var message in results ) { print.greeLine( message ); } - + } // Dynamic completion for property name based on contents of server.json diff --git a/src/cfml/system/modules_app/server-commands/commands/server/show.cfc b/src/cfml/system/modules_app/server-commands/commands/server/show.cfc index 66b2cb45e..2bbdc37ac 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/show.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/show.cfc @@ -17,13 +17,13 @@ * {code:bash} * server show aliases[2] * {code} - * + * **/ component { - + property name="ServerService" inject="ServerService"; property name="JSONService" inject="JSONService"; - + /** * @property.hint The name of the property to show. Can nested to get "deep" properties * @property.optionsUDF completeProperty @@ -32,7 +32,7 @@ component { function run( string property='', String serverConfigFile='' ) { - + // As a convenient shorcut, allow the serverConfigFile and propery parameter to be reversed because // "server show foo.json name" reads better than "server show name foo.json" but maintains backwards compat // for the simple use case of no JSON file as in "server show name" @@ -41,7 +41,7 @@ component { if( listLen( arguments.property, '.' ) > 1 && listLast( arguments.property, '.' ) == 'json' && fileExists( tmpPropertyResolved ) ) { // If so, swap the property into the server config param. arguments.property = arguments.serverConfigFile; - arguments.serverConfigFile = tmpPropertyResolved; + arguments.serverConfigFile = tmpPropertyResolved; } else if( len( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); if( !fileExists( arguments.serverConfigFile ) ) { @@ -50,20 +50,20 @@ component { } // Default the server.json in the CWD var thisServerConfigFile = ( len( arguments.serverConfigFile ) ? arguments.serverConfigFile : getCWD() & '/server.json' ); - + // Read without defaulted values var serverJSON = ServerService.readServerJSON( thisServerConfigFile ); try { - + var propertyValue = JSONService.show( serverJSON, arguments.property ); - + if( isSimpleValue( propertyValue ) ) { print.line( propertyValue ); } else { - print.line( formatterUtil.formatJson( propertyValue ) ); + print.line( formatterUtil.formatJson( propertyValue ) ); } - + } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { @@ -74,6 +74,6 @@ component { // Dynamic completion for property name based on contents of box.json function completeProperty() { - return ServerService.completeProperty( getCWD() ); + return ServerService.completeProperty( getCWD() ); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc index 3f8980a11..d9b1cc0b3 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/start.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/start.cfc @@ -133,39 +133,39 @@ component aliases="start" { arguments.rewritesEnable = arguments.rewritesEnabled; structDelete( arguments, 'rewritesEnabled' ); } - + // changed trayIcon to trayIconFile, but let's keep them both working for backwards compat if( structKeyExists( arguments, 'trayIconFile' ) ) { arguments.trayIcon = arguments.trayIconFile; structDelete( arguments, 'trayIconFile' ); } - + try { - + // startup the server return serverService.start( serverProps = arguments ); - - // endpointException exception type is used when the endpoint has an issue that needs displayed, - // but I don't want to "blow up" the console with a full error. + + // endpointException exception type is used when the endpoint has an issue that needs displayed, + // but I don't want to "blow up" the console with a full error. } catch( endpointException var e ) { error( e.message, e.detail ); } } - + /** * Complete server names */ function serverNameComplete() { return serverService.getServerNames(); } - + /** * Complete cfengine names */ function cfengineNameComplete( string paramSoFar ) { - + var APIToken = configService.getSetting( 'endpoints.forgebox.APIToken', '' ); - + try { // Get auto-complete options return forgebox.slugSearch( arguments.paramSoFar, 'cf-engines', APIToken ); @@ -182,4 +182,4 @@ component aliases="start" { return []; } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/server-commands/commands/server/status.cfc b/src/cfml/system/modules_app/server-commands/commands/server/status.cfc index 5e9e2bb17..9af7d2e90 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/status.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/status.cfc @@ -12,29 +12,29 @@ * {code} * . * Or specifiy the web root directory. If name and directory are both specified, name takes precedence. - * + * * {code:bash} * server status directory=C:\path\to\server * {code} * . * Show all registered servers with the --showAll flag - * + * * {code:bash} * server status --showAll * {code} * . * Get extra information about the server and how it was last started/stopped with the --verbose flag - * + * * {code:bash} * server status --verbose * {code} - * . + * . **/ component aliases='status,server info' { // DI property name='serverService' inject='ServerService'; - + /** * Show server status * @@ -64,18 +64,18 @@ component aliases='status,server info' { // Display ALL as JSON? if( arguments.showALL && arguments.json ){ - print.line( + print.line( formatterUtil.formatJson( serializeJSON( servers ) ) ); return; } - + if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); - } + } var serverDetails = serverService.resolveServerDetails( arguments ); var serverInfo = serverDetails.serverInfo; @@ -83,7 +83,7 @@ component aliases='status,server info' { var statusColors = { running : 'green', starting : 'yellow', - stopped : 'red' + stopped : 'red' }; for( var thisKey in servers ){ @@ -91,52 +91,52 @@ component aliases='status,server info' { // If this is a server match OR are we just showing everything if( thisServerInfo.id == serverInfo.id || arguments.showAll ){ - + // Null Checks, to guarantee correct struct. structAppend( thisServerInfo, serverService.newServerInfoStruct(), false ); - + // Are we doing JSON? if( arguments.json ){ - + // Are we outputing a specific propery if( len( arguments.property ) ) { - + // If the key doesn't exist, give a useful error if( !isDefined( 'thisServerInfo.#arguments.property#' ) ) { error( "The propery [#arguments.property#] isn't defined in the JSON.", "Valid keys are: " & chr( 10 ) & " - " & thisServerInfo.keyList().lCase().listChangeDelims( chr( 10 ) & " - " ) ); } - + // Output a single property var thisValue = evaluate( 'thisServerInfo.#arguments.property#' ); - // Output simple values directly so they're useful + // Output simple values directly so they're useful if( isSimpleValue( thisValue ) ) { print.line( thisValue ); // Format Complex values as JSON } else { - print.line( + print.line( formatterUtil.formatJson( serializeJSON( thisValue ) ) - ); + ); } - + } else { - + // Output the entire object - print.line( + print.line( formatterUtil.formatJson( serializeJSON( thisServerInfo ) ) ); - + } - + continue; } print.line().boldText( thisServerInfo.name ); - + var status = serverService.isServerRunning( thisServerInfo ) ? 'running' : 'stopped';; print.boldtext( ' (' ) .bold( status, statusColors.keyExists( status ) ? statusColors[ status ] : 'yellow' ) .bold( ')' ); - + print.indentedLine( thisServerInfo.host & ':' & thisServerInfo.port & ' --> ' & thisServerInfo.webroot ); if( len( serverInfo.engineName ) ) { print.indentedLine( 'CF Engine: ' & serverInfo.engineName & ' ' & serverInfo.engineVersion ); @@ -146,19 +146,19 @@ component aliases='status,server info' { } if( len( serverInfo.dateLastStarted ) ) { print.indentedLine( 'Last Started: ' & datetimeFormat( serverInfo.dateLastStarted ) ); - } + } print.line(); print.indentedLine( 'Last status message: ' ); print.indentedLine( thisServerInfo.statusInfo.result ); - + if( arguments.verbose ) { - + print.indentedLine( trim( thisServerInfo.statusInfo.command ) ); // Put each --arg or -arg on a new line var args = trim( reReplaceNoCase( thisServerInfo.statusInfo.arguments, ' (-|"-)', cr & '\1', 'all' ) ); print.indentedIndentedLine( args ) - .line(); - + .line(); + } } // End "filter" if } @@ -168,14 +168,14 @@ component aliases='status,server info' { print.boldRedLine( 'No server configurations found!' ); } } - + /** * AutoComplete server names */ function serverNameComplete() { return serverService.getServerNames(); } - + /** * AutoComplete serverInfo properties */ diff --git a/src/cfml/system/modules_app/server-commands/commands/server/stop.cfc b/src/cfml/system/modules_app/server-commands/commands/server/stop.cfc index 18c8664ae..15ab98e5a 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/stop.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/stop.cfc @@ -27,37 +27,37 @@ component aliases="stop" { String serverConfigFile, boolean forget=false, boolean all=false ){ - - + + if( arguments.all ) { var servers = serverService.getServers(); } else { - + if( !isNull( arguments.directory ) ) { arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - } + } if( !isNull( arguments.serverConfigFile ) ) { arguments.serverConfigFile = fileSystemUtil.resolvePath( arguments.serverConfigFile ); } - + // Look up the server that we're starting var servers = { id: serverService.resolveServerDetails( arguments ).serverinfo }; - + } // End "all" check // Stop the server(s) for( var id in servers ) { var serverInfo = servers[ id ]; - + if( !serverService.isServerRunning( serverInfo ) ) { if( structCount( servers ) == 1 ) { print.yellowLine( serverInfo.name & ' already stopped.' ).toConsole(); } continue; } - + print.yellowLine( 'Stopping ' & serverInfo.name & '...' ).toConsole(); - + var results = serverService.stop( serverInfo ); if( results.error ){ print.boldWhiteOnRedLine( 'ERROR' ); @@ -65,16 +65,16 @@ component aliases="stop" { } else { print.line( results.messages ); } - + if( arguments.forget ) { print.yellowLine( 'forgetting ' & serverInfo.name & '...' ).toConsole(); - print.line( serverService.forget( serverInfo ) ); + print.line( serverService.forget( serverInfo ) ); } } - - + + } - + function serverNameComplete() { return serverService.getServerNames(); } diff --git a/src/cfml/system/modules_app/system-commands/commands/browse.cfc b/src/cfml/system/modules_app/system-commands/commands/browse.cfc index 5182b5d08..e4fdb5e26 100644 --- a/src/cfml/system/modules_app/system-commands/commands/browse.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/browse.cfc @@ -1,11 +1,11 @@ /** - * Open a browser to the passed URI. + * Open a browser to the passed URI. * . * Concatenate two files and output them to the screen * {code:bash} * browse localhost:8116 * {code} - * + * **/ component { diff --git a/src/cfml/system/modules_app/system-commands/commands/cat.cfc b/src/cfml/system/modules_app/system-commands/commands/cat.cfc index d3c2fc6b6..59023febe 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cat.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cat.cfc @@ -1,5 +1,5 @@ /** - * Read any number of files and return their concatenated contents. By default, the + * Read any number of files and return their concatenated contents. By default, the * the output is displayed on the console, but it can also be piped or redirected. * . * Output a single file @@ -16,53 +16,53 @@ * {code:bash} * cat file1.txt file2.txt > combined.txt * {code} - * + * **/ component aliases="type" { /** - * You can have as many args as you want, but I'm including 4 just so + * You can have as many args as you want, but I'm including 4 just so * auto-complete will at least work for the first 4 since it's based on arg name. - * + * * @file1.hint File to output * @file2.hint File to concatenate to previous file * @file3.hint File to concatenate to previous file(s) * @file4.hint File to concatenate to previous file(s) **/ function run( required Globber file1, Globber file2, Globber file3, Globber file4 ) { - + var buffer = ''; - + for( var arg in arguments ) { var file = arguments[ arg ]; - + if( !isNull( file ) ) { - + if( isSimpleValue( file ) ) { // Make file canonical and absolute file = fileSystemUtil.resolvePath( file ); - + if( !fileExists( file ) ){ return error( "File: #file# does not exist!" ); } - + if( buffer.len() ) { buffer &= CR } buffer &= fileRead( file ); - + } else { - + file.apply( function( thisFile ) { if( buffer.len() ) { buffer &= CR } buffer &= fileRead( thisFile ); } ); - + } - + } - - + + } - + return buffer; } diff --git a/src/cfml/system/modules_app/system-commands/commands/cd.cfc b/src/cfml/system/modules_app/system-commands/commands/cd.cfc index a19150de2..e50f70532 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cd.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cd.cfc @@ -9,7 +9,7 @@ * As with any file and folder parameters, you can traverse "up" a directory. * {code:bash} * cd ../../tests - * {code} + * {code} **/ component { @@ -17,14 +17,14 @@ component { * @directory.hint The directory to change to **/ function run( directory="" ) { - + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + if( !directoryExists( arguments.directory ) ) { return error( "#arguments.directory#: No such file or directory" ); } - + return shell.cd( arguments.directory ); } diff --git a/src/cfml/system/modules_app/system-commands/commands/cfml.cfc b/src/cfml/system/modules_app/system-commands/commands/cfml.cfc index d5888057e..93c326482 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cfml.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cfml.cfc @@ -1,40 +1,40 @@ /** - * I am a shortcut to run single CFML functions via the REPL. This example runs the now() function. - * It is the equivalent to "repl now()". + * I am a shortcut to run single CFML functions via the REPL. This example runs the now() function. + * It is the equivalent to "repl now()". * . * {code:bash} * cfml now * {code} - * + * * As a handy shortcut, you can invoke the "cfml" command by simply typing the name of the CFML * function, preceded by a # sign. - * + * * {code:bash} * #now * {code} - * + * * When you pass parameters into this command, they will be passed directly along to the CFML function. - * + * * {code:bash} * #hash mypass * #reverse abc * {code} * - * This really gets useful when you start piping input into CFML functions. Like other CFML commands, piped + * This really gets useful when you start piping input into CFML functions. Like other CFML commands, piped * input will get passed as the first parameter to the function. This allows you to chain CFML functions - * from the command line like so. (Outputs "OOF") - * + * from the command line like so. (Outputs "OOF") + * * {code:bash} * #listGetAt www.foo.com 2 . | #ucase | #reverse * {code} - * - * Since this command defers to the REPL for execution, complex return values such as arrays or structs will be + * + * Since this command defers to the REPL for execution, complex return values such as arrays or structs will be * serialized as JSON on output. As a convenience, if the first input to an array or struct function looks like - * JSON, it will be passed directly as a literal instead of a string. + * JSON, it will be passed directly as a literal instead of a string. * . - * The first example averages an array. The second outputs an array of dependency names in your app by manipulating + * The first example averages an array. The second outputs an array of dependency names in your app by manipulating * the JSON object that comes back from the "package list" command. - * + * * {code:bash} * #arrayAvg [1,2,3] * package list --JSON | #structFind dependencies | #structKeyArray @@ -42,12 +42,12 @@ * * You must use positional parameters if you are piping data to a CFML function, but you do have the option to use * named parameters otherwise. Those names will be passed along directly to the CFML function, so use the CF docs to make sure - * you're using the correct parameter name. - * + * you're using the correct parameter name. + * * {code:bash} * #directoryList path=D:\\ listInfo=name * {code} - * + * **/ component{ @@ -60,18 +60,18 @@ component{ ){ var functionText = arguments.name & '( '; - + // Additional param go into the function if( arrayLen( arguments ) > 1 ) { - + // Positional params if( isNumeric( listGetAt( structKeyList( arguments ), 2 ) ) ) { - + var i = 1; while( ++i <= arrayLen( arguments ) ) { - + functionText &= ( i>2 ? ', ' : '' ); - + // If this is a struct or array function, we have at least one param, and it's JSON, just pass it in as complex data. if( ( left( arguments.name, 5 ) == 'array' || left( arguments.name, 6 ) == 'struct' ) && i==2 && isJSON( arguments[ i ] ) ) { @@ -79,32 +79,32 @@ component{ } else { functionText &= '"#escapeArg( arguments[ i ] )#"'; } - + } // end param loop - + // Named params } else { - + var i = 0; for( var param in arguments ) { if( param=='name' ) { - continue; - } + continue; + } i++; - - functionText &= ( i>1 ? ', ' : '' ); - + + functionText &= ( i>1 ? ', ' : '' ); + functionText &= '#param#="#escapeArg( arguments[ param ] )#"'; - + } // end param loop - + } - - + + } // end additional params? - + functionText &= ' )'; // Run our function via the REPL @@ -114,10 +114,10 @@ component{ // Print out the results print.text( result ); - + // Try to do some "smart" debugging if the response was an error - // Todo, need to have a more explicit 'error' code that comes back - if( result contains 'error' ) { + // Todo, need to have a more explicit 'error' code that comes back + if( result contains 'error' ) { print.yellowline( "Here is the last CFML function that was run" ) .line() .line( functionText ) @@ -131,7 +131,7 @@ component{ return arguments.arg; } - // A complex value serialized as JSON differs from CFML struct literals in that + // A complex value serialized as JSON differs from CFML struct literals in that // double quotes are \" instead of "". Any escaped double quotes must be converted // to the CFML version to work as an object literal. private function convertJSONEscapesToCFML( required string arg ) { diff --git a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc index 84bdeb3a9..b1777e773 100644 --- a/src/cfml/system/modules_app/system-commands/commands/checksum.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/checksum.cfc @@ -1,5 +1,5 @@ /** - * Generate checksum for a file or a directory via a globbing pattern. + * Generate checksum for a file or a directory via a globbing pattern. * Default is MD5, but SHA-1, SHA-256, and SHA-512 can also be used. * . * {code:bash} @@ -28,7 +28,7 @@ * {code} * * Control the format of the hash with the "format" parameter. - * + * * {code:bash} * - "checksum" (default) -- just the hash * - "md5sum" -- The format of GNU textutils md5sum @@ -41,7 +41,7 @@ * checksum path=myFile.zip verify=2A95F32028087699CCBEB09AFDA0348C * {code} * - **/ + **/ component { variables.algorithms = 'md5,sha1,sha-1,sha-256,sha-512'; @@ -72,31 +72,31 @@ component { } // Default extension is algorithm name extension = extension ?: algorithm; - + // validate format if( !variables.formats.listFindNoCase( format ) ) { error( 'The checksum format [#format#] is not supported' ); } - + // Validate algorithm if( !variables.algorithms.listFindNoCase( algorithm ) ) { error( 'The hashing algorithm [#algorithm#] is not supported' ); } - + // If file or glog doesn't exist, error. if( !path.count() ) { error( "File or globbing pattern doesn't exist. I can't hash thin air! [#path.getPattern()#]" ); } - + // If verifying a hash, only one file can be matched if( verify.len() && path.count() > 1 ) { error( 'You can only verify a single hash/file at a time.' ); } - + // Loop over matched globbing patterns path.apply( function( thisPath ){ var thisHash = hash( fileReadBinary( thisPath ), algorithm ); - + // Verifying incoming hash if( verify.len() ) { // Doesn't match @@ -108,10 +108,10 @@ component { return; } } - + // Default output format is just the checksum var formattedHash = thisHash; - + // Match the format of GNU textutils md5sum if( format == 'md5sum' ) { var formattedHash = thisHash & ' *' & listLast( thisPath, '/\' ); @@ -125,29 +125,29 @@ component { fileWrite( thisPath & '.' & extension, formattedHash ); // If outputting } else { - + print .text( formattedHash ) .toConsole(); - + // If we're doing more than one hash, put a line break in. if( path.count() > 1 ) { print.line(); } - + } } ); - + } - + function algorithmComplete() { return variables.algorithms.listToArray(); } - + function formatComplete() { return variables.formats.listToArray(); } - - - + + + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/config/clear.cfc b/src/cfml/system/modules_app/system-commands/commands/config/clear.cfc index ca3b59051..d16c1851d 100644 --- a/src/cfml/system/modules_app/system-commands/commands/config/clear.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/config/clear.cfc @@ -5,39 +5,39 @@ * {code:bash} * config clear description * {code} - * + * **/ component { - + property name="ConfigService" inject="ConfigService"; - property name="JSONService" inject="JSONService"; - - /** - * @property.hint Name of the property to clear + property name="JSONService" inject="JSONService"; + + /** + * @property.hint Name of the property to clear * @property.optionsUDF completeProperty **/ function run( required string property ) { - + var configSettings = ConfigService.getconfigSettings(); - + try { JSONService.clear( configSettings, arguments.property ); } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { rethrow; - } - + } + print.greenLine( 'Removed #arguments.property#' ); - + // Write the file back out. ConfigService.setConfigSettings( configSettings ); - + } // Dynamic completion for property name based on contents of box.json function completeProperty() { - return ConfigService.completeProperty(); + return ConfigService.completeProperty(); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/config/set.cfc b/src/cfml/system/modules_app/system-commands/commands/config/set.cfc index 4b7805e51..d89102e20 100644 --- a/src/cfml/system/modules_app/system-commands/commands/config/set.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/config/set.cfc @@ -35,38 +35,38 @@ * {code:bash} * config set myArraySetting="[ 'another value' ]" --append * {code} - * + * **/ component { - + property name="ConfigService" inject="ConfigService"; - property name="JSONService" inject="JSONService"; - + property name="JSONService" inject="JSONService"; + /** * This param is a dummy param just to get the custom completor to work. - * The actual parameter names will be whatever property name the user wants to set - * @_.hint Pass any number of property names in followed by the value to set - * @_.optionsUDF completeProperty + * The actual parameter names will be whatever property name the user wants to set + * @_.hint Pass any number of property names in followed by the value to set + * @_.optionsUDF completeProperty * @append.hint If setting an array or struct, set to true to append instead of overwriting. **/ function run( _, boolean append=false ) { var thisAppend = arguments.append; - + // Remove dummy args structDelete( arguments, '_' ); structDelete( arguments, 'append' ); var configSettings = ConfigService.getconfigSettings(); - var results = JSONService.set( configSettings, arguments, thisAppend ); + var results = JSONService.set( configSettings, arguments, thisAppend ); // Write the file back out. ConfigService.setConfigSettings( configSettings ); - + for( var message in results ) { print.greeLine( message ); } - + } // Dynamic completion for property name based on contents of box.json diff --git a/src/cfml/system/modules_app/system-commands/commands/config/show.cfc b/src/cfml/system/modules_app/system-commands/commands/config/show.cfc index 74f7cc7d5..6fb77b3c0 100644 --- a/src/cfml/system/modules_app/system-commands/commands/config/show.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/config/show.cfc @@ -19,28 +19,28 @@ * . **/ component { - + property name="ConfigService" inject="ConfigService"; property name="JSONService" inject="JSONService"; - + /** * @property.hint The name of the property to show. Can nested to get "deep" properties * @property.optionsUDF completeProperty **/ function run( string property='' ) { - + var configSettings = ConfigService.getconfigSettings(); try { - + var propertyValue = JSONService.show( configSettings, arguments.property ); - + if( isSimpleValue( propertyValue ) ) { print.line( propertyValue ); } else { - print.line( formatterUtil.formatJson( propertyValue ) ); + print.line( formatterUtil.formatJson( propertyValue ) ); } - + } catch( JSONException var e ) { error( e.message ); } catch( any var e ) { @@ -51,6 +51,6 @@ component { // Dynamic completion for property name based on contents of commandbox.json function completeProperty() { - return ConfigService.completeProperty(); + return ConfigService.completeProperty(); } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/cp.cfc b/src/cfml/system/modules_app/system-commands/commands/cp.cfc index 046798fc9..3f3dee7d2 100644 --- a/src/cfml/system/modules_app/system-commands/commands/cp.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/cp.cfc @@ -16,7 +16,7 @@ * cp foo/ bar/ * {code} * - **/ + **/ component aliases="copy" { /** @@ -26,16 +26,16 @@ component aliases="copy" { * @filter.hint A directory copy filter string that uses "*" as a wildcard, for example, "*.cfm" **/ function run( required Globber path, required newPath, boolean recurse=false, string filter="*" ) { - + // Make path canonical and absolute var thisNewPath = fileSystemUtil.resolvePath( arguments.newPath ); - + if( path.count() > 1 && !directoryExists( thisNewPath ) ) { error( '[#thisNewPath#] is not a directory.' ); } - + path.apply( function( thisPath ){ - + // It's a directory if( directoryExists( thisPath ) ) { // rename directory @@ -47,11 +47,11 @@ component aliases="copy" { DirectoryCreate( getDirectoryFromPath( thisNewPath ), true, true ); fileCopy( thisPath, thisNewPath ); print.greenLine( "File copied to #thisNewPath#" ); - } else { + } else { return error( "File/directory does not exist: #thisPath#" ); } - + } ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/delete.cfc b/src/cfml/system/modules_app/system-commands/commands/delete.cfc index b5f37e315..a22dae72a 100644 --- a/src/cfml/system/modules_app/system-commands/commands/delete.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/delete.cfc @@ -17,7 +17,7 @@ * {code:bash} * delete myFolder/ --recurse * {code} - **/ + **/ component aliases="rm,del" { /** @@ -26,55 +26,55 @@ component aliases="rm,del" { * @recurse.hint Delete sub directories **/ function run( required Globber path, Boolean force=false, Boolean recurse=false ) { - + path.apply( function( thisPath ) { // It's a directory if( directoryExists( thisPath ) ) { - + var subMessage = recurse ? ' and all its subdirectories' : ''; - + if( force || confirm( "Delete #thisPath##subMessage#? [y/n]" ) ) { - + if( directoryList( thisPath ).len() && !recurse ) { return error( 'Directory [#thisPath#] is not empty! Use the "recurse" parameter to override' ); } - // Catch this to gracefully handle where the OS or another program + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { directoryDelete( thisPath, recurse ); - print.greenLine( "Deleted #thisPath#" ); + print.greenLine( "Deleted #thisPath#" ); } catch( any e ) { error( '#e.message##CR#The folder is possibly locked by another program.' ); logger.error( '#e.message# #e.detail#' , e.stackTrace ); } } else { - print.redLine( "Cancelled!" ); + print.redLine( "Cancelled!" ); } - - + + // It's a file } else if( fileExists( thisPath ) ){ - + if( force || confirm( "Delete #thisPath#? [y/n]" ) ) { - - // Catch this to gracefully handle where the OS or another program + + // Catch this to gracefully handle where the OS or another program // has the file locked. try { fileDelete( thisPath ); - print.greenLine( "Deleted #thisPath#" ); + print.greenLine( "Deleted #thisPath#" ); } catch( any e ) { error( '#e.message##CR#The file is possibly locked by another program.' ); logger.error( '#e.message# #e.detail#' , e.stackTrace ); } } else { - print.redLine( "Cancelled!" ); + print.redLine( "Cancelled!" ); } - - } else { + + } else { return error( "File/directory does not exist: #thisPath#" ); } - } ); + } ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/dir.cfc b/src/cfml/system/modules_app/system-commands/commands/dir.cfc index f3607217d..e8d2ae254 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -10,37 +10,37 @@ * {code:bash} * dir samples/ --recurse * {code} - * + * **/ component aliases="ls,ll,directory" { /** * @directory.hint The directory to list the contents of or a file Globbing path to filter on - * @recurse.hint Include nested files and folders + * @recurse.hint Include nested files and folders **/ function run( Globber directory=globber( ( getCWD().endsWith( '/' ) || getCWD().endsWith( '\' ) ? getCWD() : getCWD() & '/' ) ), Boolean recurse=false ) { - - // If the user gives us an existing directory foo, change it to the + + // If the user gives us an existing directory foo, change it to the // glob pattern foo/* or foo/** if doing a recursive listing. if( directoryExists( directory.getPattern() ) ){ directory.setPattern( directory.getPattern() & '*' & ( recurse ? '*' : '' ) ); } - + // TODO: Add ability to re-sort this based on user input var results = directory .asQuery() .matches(); - + for( var x=1; x lte results.recordcount; x++ ) { var printCommand = ( results.type[ x ] eq "File" ? "green" : "white" ); - print[ printCommand & "line" ]( + print[ printCommand & "line" ]( results.type[ x ] & " " & ( results.type[ x ] eq "Dir" ? " " : "" ) & //padding results.attributes[ x ] & " " & numberFormat( results.size[ x ], "999999999" ) & " " & dateTimeFormat( results.dateLastModified[ x ], "MMM dd,yyyy HH:mm:ss" ) & " " & - cleanRecursiveDir( arguments.directory.getBaseDir(), results.directory[ x ] ) & results.name[ x ] & ( results.type[ x ] == "Dir" ? "/" : "" ) + cleanRecursiveDir( arguments.directory.getBaseDir(), results.directory[ x ] ) & results.name[ x ] & ( results.type[ x ] == "Dir" ? "/" : "" ) ); } diff --git a/src/cfml/system/modules_app/system-commands/commands/echo.cfc b/src/cfml/system/modules_app/system-commands/commands/echo.cfc index 7cad653aa..e873d6654 100644 --- a/src/cfml/system/modules_app/system-commands/commands/echo.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/echo.cfc @@ -10,7 +10,7 @@ * {code:bash} * echo "Step 3 complete" >> log.txt * {code} - * + * **/ component { diff --git a/src/cfml/system/modules_app/system-commands/commands/edit.cfc b/src/cfml/system/modules_app/system-commands/commands/edit.cfc index 41206a12e..4f4c74f45 100644 --- a/src/cfml/system/modules_app/system-commands/commands/edit.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/edit.cfc @@ -1,5 +1,5 @@ /** - * Open a path in the native OS application in order to edit it. If you pass in a + * Open a path in the native OS application in order to edit it. If you pass in a * folder, it will try to open the folder in an explorer or finder window. * Passing no path, or an empty string will open the current working directory * . @@ -7,7 +7,7 @@ * edit index.cfm * open myApp/ * {code} - * + * **/ component aliases="open" { @@ -15,21 +15,21 @@ component aliases="open" { * @path.hint Path to open natively. **/ function run( Globber path=globber( getCWD() ) ) { - + path.apply( function( thisPath ) { - + if( !fileExists( thisPath ) AND !directoryExists( thisPath ) ){ return error( "Path: #thisPath# does not exist, cannot open it!" ); } - + if( fileSystemUtil.openNatively( thisPath ) ){ print.line( "Resource Opened!" ); } else { error( "Unsupported OS, cannot open path." ); - }; - + }; + } ); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/execute.cfc b/src/cfml/system/modules_app/system-commands/commands/execute.cfc index 3b4b7badd..3934b94c9 100644 --- a/src/cfml/system/modules_app/system-commands/commands/execute.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/execute.cfc @@ -16,12 +16,12 @@ * {code} * . * If you're using positional parameters, they will be available as ${position} in the variables scope. - * variables.$1, variables.$2 + * variables.$1, variables.$2 * . * {code:bash} * execute myFile.cfm bar baz * {code} - + **/ component aliases="exec"{ @@ -38,10 +38,10 @@ component aliases="exec"{ if( !fileExists( arguments.file ) ){ return error( "File: #arguments.file# does not exist!" ); } - + // Parse arguments var vars = parseArguments( arguments ); - + try{ // we use the executor to capture output thread safely var out = wirebox.getInstance( "Executor" ).runFile( arguments.file, vars ); @@ -58,7 +58,7 @@ component aliases="exec"{ */ private struct function parseArguments( required args ){ var parsedArgs = {}; - + for( var arg in args ) { argName = arg; if( !isNull( args[arg] ) && arg != 'file' ) { @@ -75,5 +75,5 @@ component aliases="exec"{ private void function clearTemplateCache() { pagePoolClear(); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/fileAppend.cfc b/src/cfml/system/modules_app/system-commands/commands/fileAppend.cfc index f9f089544..ae189425e 100644 --- a/src/cfml/system/modules_app/system-commands/commands/fileAppend.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/fileAppend.cfc @@ -16,7 +16,7 @@ * {code:bash} * echo "Step 3 complete" >> log.txt * {code} - * + * **/ component excludeFromHelp=true { @@ -25,20 +25,20 @@ component excludeFromHelp=true { * @file.hint File to append to **/ function run( required contents='', required string file ) { - + // This will make the file path canonical and absolute arguments.file = fileSystemUtil.resolvePath( arguments.file ); // Clean out any ANI escape codes from the text arguments.contents = print.unansi( arguments.contents ); - + // Append to the file - file - action = "append" - file = "#arguments.file#" - output = "#arguments.contents#" + file + action = "append" + file = "#arguments.file#" + output = "#arguments.contents#" addNewLine = "yes"; - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/fileWrite.cfc b/src/cfml/system/modules_app/system-commands/commands/fileWrite.cfc index e99bdd0ea..47e8b6420 100644 --- a/src/cfml/system/modules_app/system-commands/commands/fileWrite.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/fileWrite.cfc @@ -1,5 +1,5 @@ /** - * Write a file, overwriting it if it exists. + * Write a file, overwriting it if it exists. * . * {code:bash} * fileWrite "My file contents" file.txt @@ -16,7 +16,7 @@ * {code:bash} * dir > fileList.txt * {code} - * + * **/ component excludeFromHelp=true { @@ -25,7 +25,7 @@ component excludeFromHelp=true { * @file.hint File to write to **/ function run( required contents='', required string file ) { - + // This will make the file path canonical and absolute arguments.file = fileSystemUtil.resolvePath( arguments.file ); @@ -34,7 +34,7 @@ component excludeFromHelp=true { // Write the file fileWrite( arguments.file, arguments.contents ); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/grep.cfc b/src/cfml/system/modules_app/system-commands/commands/grep.cfc index 349248573..d3e6afefb 100644 --- a/src/cfml/system/modules_app/system-commands/commands/grep.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/grep.cfc @@ -1,5 +1,5 @@ /** - * Search through string input and filter only matching lines. Pipe input in and supply a regular expression. + * Search through string input and filter only matching lines. Pipe input in and supply a regular expression. * . * Find Brad's ForgeBox entries * {code:bash} @@ -15,27 +15,27 @@ * {code:bash} * cat myLogFile.txt | grep "variable .* undefined" * {code} - * + * **/ component excludeFromHelp=true { - + /** * @input.hint The piped input to be checked. * @expression.hint A regular expression to match against each line of the input. Only matching lines will be output. **/ function run( input='', expression='' ) { // Turn output into an array, breaking on carriage returns - var content = listToArray( arguments.input, CR ); - + var content = listToArray( arguments.input, CR ); + // Loop over content for( var line in content ) { - + // Does it match if( reFindNoCase( arguments.expression, line ) ) { // print it out - print.line( line ); + print.line( line ); } - + } } diff --git a/src/cfml/system/modules_app/system-commands/commands/help.cfc b/src/cfml/system/modules_app/system-commands/commands/help.cfc index 052649f46..76d795f70 100644 --- a/src/cfml/system/modules_app/system-commands/commands/help.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/help.cfc @@ -23,7 +23,7 @@ component aliases="h,/?,?,--help,-help" { property name="commandService" inject="CommandService"; - + /** * @command.hint The command to get help for. If blank, displays help for all commands **/ @@ -31,51 +31,51 @@ component aliases="h,/?,?,--help,-help" { // Auto-help will display help for all commands at this // level in the command structure and below. Default to all var autoHelpRoot = ''; - + // CommandBox Help banner print.line(); print.greenLine( repeatString( '*', 50 ) ); print.greenText( '* CommandBox Help' ); if( len( command ) ) { - print.greenText( ' for ' ); - print.boldGreenText( '#command#' ); + print.greenText( ' for ' ); + print.boldGreenText( '#command#' ); } print.line(); print.greenLine( repeatString( '*', 50 ) ); print.line(); - + var commandHierarchy = commandService.getCommandHierarchy(); var foundCommand = false; var commandRoot = ''; - var commandRootSpaces = ''; - + var commandRootSpaces = ''; + // If we're getting help for a specific command if( len( command ) ) { // Resolve the string to the first command (help | more will just be "help") var commandInfo = commandService.resolveCommand( line=command )[1]; - + // Display auto help for however far we made it in the command hierarchy commandHierarchy = commandInfo.commandReference; foundCommand = commandInfo.found; commandRoot = commandInfo.commandString; commandRootSpaces = listChangeDelims( commandRoot, ' ', '.' ); - + // If the user typed something that wasn't exactly matched, let them know if( !len( commandInfo.commandString ) || commandRootSpaces != command ) { - print.redLine( 'Command [#command#] not found.' ); - print.line(); + print.redLine( 'Command [#command#] not found.' ); + print.line(); } - + // If no command was found but there is an applicable help command for the namespace // other than the main help that we're in now... if( !foundCommand && commandInfo.closestHelpCommand != 'help' ) { // Run it to output some context-specific help for this namespace runCommand( commandInfo.closestHelpCommand ); - + } - + } - + // Help for a single command if( foundCommand ) { printCommandHelp( command, commandInfo ); @@ -83,7 +83,7 @@ component aliases="h,/?,?,--help,-help" { } else { var commands = []; var namespaces = []; - + // Get all the commands and nested namespaces at this level. for( var node in commandHierarchy ) { var thisCommand = commandHierarchy[ node ]; @@ -98,65 +98,65 @@ component aliases="h,/?,?,--help,-help" { // Also don't include if the command is flagged to hide from help if( originalCommandName == listAppend( commandRoot, node, '.' ) && !excludeFromHelp ) { commands.append( node ); - } + } // Is this node a namespace - } else { - namespaces.append( node ); + } else { + namespaces.append( node ); } } // End loop over this level in the hierachy - - + + // Sort each list commands.sort( 'text' ); namespaces.sort( 'text' ); - + // If there are commands if( commands.len() ) { print.blackOnYellowline( 'Here is a list of commands in this namespace:' ); print.line(); - + // Show them for( var command in commands ) { print.line( commandRootSpaces & ' ' & command ); } - + print.line(); - + } - + // If there are namepaces if( namespaces.len() ) { print.line(); - + print.blackOnYellowline( 'Here is a list of nested namespaces:' ); print.line(); - + // Show them for( var namespace in namespaces ) { print.line( commandRootSpaces & ' ' & namespace ); } - + print.line(); - + } print.line(); print.yellowText( 'To get further help on any of the items above, type ' ); print.boldYellowText( '"help command name"' ); print.YellowLine( '.' ); - + } - - + + return; } - + /** * Outputs help information for a single command. * - * @command.hint String command + * @command.hint String command * @commandInfo.hint Reference to Command CFC **/ - + private function printCommandHelp( required string command, required any commandInfo ) { var commandRefernce = commandInfo.commandReference; // Original command name, to tell if "command" is an alias @@ -173,35 +173,35 @@ component aliases="h,/?,?,--help,-help" { aliases.delete( command ); aliases.prepend( originalCommandName ); } - - + + // Output command name print.line(); print.blackOnWhiteLine( ' #command# ' ); print.line(); - + // Aliases if( aliases.len() ) { print.line(); print.line( 'Aliases: #arrayToList( aliases, ', ' )#' ); - print.line(); + print.line(); } - + // Output the hint if it exists if( len( commandHint ) ) { - - // Clean up lines with only a period which is my work around for the Railo bug ignoring + + // Clean up lines with only a period which is my work around for the Railo bug ignoring // line breaks in componenet annotations: https://issues.jboss.org/browse/RAILO-3128 commandHint = reReplace( commandHint, '\n\s*\.\s*\n', cr&cr, 'all' ); - + // Find code blocks - // A {code} block on it's own line with an optional ":brush" inside it + // A {code} block on it's own line with an optional ":brush" inside it // followed by any amount of text // followed by another {code} block on it's own line var codeRegex = '(\n?\s*{\s*code\s*(:.*?)?\s*}\s*\n)(.*?)(\n\s*{\s*code\s*}\s*\n?)'; // Clear formatting ahead of the code so it's white, and turn the yellow back on. ANSI escape sequences hard-coded here commandHint = reReplaceNoCase( commandHint, codeRegex, '#cr##cr##chr( 27 )#[0m\3#cr##cr##chr( 27 )#[33m', 'all' ); - + print.yellowText( "#commandHint#"); print.line(); } @@ -214,25 +214,25 @@ component aliases="h,/?,?,--help,-help" { print.text( chr(9) & chr(9) ); // Required? if( param.required ) { - print.redText( 'required ' ); + print.redText( 'required ' ); } // Param type if( param.type != 'any' ) { - print.text( '#param.type# ' ); + print.text( '#param.type# ' ); } print.magentaText( '#param.name# ' ); // Default value if( !isNull(param.default) && param.default!= '[runtime expression]' ) { - print.text( '= "#param.default#" ' ); + print.text( '= "#param.default#" ' ); } // param Hint if( !isNull(param.hint)) { - print.yellowText( '(#param.hint#)' ); - } - print.line(); + print.yellowText( '(#param.hint#)' ); + } + print.line(); } // End parameter loop } // End are there params? - print.line(); + print.line(); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/history.cfc b/src/cfml/system/modules_app/system-commands/commands/history.cfc index 9dbecd64b..660da7b1e 100644 --- a/src/cfml/system/modules_app/system-commands/commands/history.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/history.cfc @@ -11,7 +11,7 @@ * history --clear * {code} * . - * There are separate histories for commands, script REPL and tag REPL. + * There are separate histories for commands, script REPL and tag REPL. * Use the "type" paramater to specifiy which history you want to view or clear. * . * {code:bash} @@ -25,30 +25,30 @@ * {code:bash} * history type=scriptREPL --clear * {code} - * + * **/ component { - + property name="commandHistoryFile" inject="commandHistoryFile@java"; property name="REPLScriptHistoryFile" inject="REPLScriptHistoryFile@java"; property name="REPLTagHistoryFile" inject="REPLTagHistoryFile@java"; - + /** - * @clear.hint Erase your history. + * @clear.hint Erase your history. * @type.hint The type of history to interact with. Values are "command", "scriptREPL", and "tagREPL" * @type.options command,scriptREPL,tagREPL **/ function run( boolean clear=false, string type='command' ) { // Get the Java JLine.History object if( arguments.type == 'scriptREPL' ) { - var history = variables.REPLScriptHistoryFile; + var history = variables.REPLScriptHistoryFile; } else if( arguments.type == 'tagREPL' ) { - var history = variables.REPLTagHistoryFile; + var history = variables.REPLTagHistoryFile; } else { - var history = variables.commandHistoryFile; + var history = variables.commandHistoryFile; } - // Clear the history? + // Clear the history? if( arguments.clear ) { history.clear(); print.greenLine( 'History cleared.' ); @@ -60,9 +60,9 @@ component { while( historyIterator.hasNext() ) { print.line( listRest( historyIterator.next(), ':' ) ); } - + } // end clear? - + } diff --git a/src/cfml/system/modules_app/system-commands/commands/info.cfc b/src/cfml/system/modules_app/system-commands/commands/info.cfc index 60e945cbd..430e9b943 100644 --- a/src/cfml/system/modules_app/system-commands/commands/info.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/info.cfc @@ -2,25 +2,25 @@ * Display basic information about the shell and some cool ASCII art. * . * {code:bash} - * info + * info * {code} * **/ component aliases="about" { function run() { - + var width = 100; - + shellVersion = shell.getVersion(); CFMLEngine = server.coldfusion.productName; if( structKeyExists( server, CFMLEngine ) ) { - CFMLVersion = '#server[ CFMLEngine ].version# #server[ CFMLEngine ].state# (#server[ CFMLEngine ].versionName#)'; + CFMLVersion = '#server[ CFMLEngine ].version# #server[ CFMLEngine ].state# (#server[ CFMLEngine ].versionName#)'; } else { - CFMLVersion = server.coldfusion.productVersion; + CFMLVersion = server.coldfusion.productVersion; } javaVersion = '#server.java.version# (#server.java.vendor#)'; - + print.line(); print.greenLine( '****************************************************************************************************' ); print.greenText( '* ' ); @@ -28,7 +28,7 @@ component aliases="about" { print.greenLine( ' *' ); print.greenLine( '****************************************************************************************************' ); print.greenLine( '* *' ); - print.greenLine( '* *' ); + print.greenLine( '* *' ); print.green( '*' ); print.magenta( ' CommandBox Version: ' ); print.white( '#shellVersion##repeatString( ' ', width - 24 - len( shellVersion ) )#' ); print.greenLine( '*' ); print.green( '*' ); print.magenta( ' CFML Engine: ' ); print.white( '#CFMLEngine##repeatString( ' ', width - 24 - len( CFMLEngine ) )#' ); print.greenLine( '*' ); print.green( '*' ); print.magenta( ' CFML Version: ' ); print.white( '#CFMLVersion##repeatString( ' ', width - 24 - len( CFMLVersion ) )#' ); print.greenLine( '*' ); @@ -38,7 +38,7 @@ component aliases="about" { print.greenLine( '* *' ); print.greenLine( '****************************************************************************************************' ); print.line(); - + print.line(' ``````````````````````````````````````````````````````````````````````````````````````````` '); print.line(' `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.` '); print.line(' `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,` '); @@ -87,9 +87,8 @@ component aliases="about" { print.line(' `.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,.` '); print.line(' `..,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,..` '); print.line(' ````````````````````````````````````````````````````````````````````````````````````````` '); - + } } - diff --git a/src/cfml/system/modules_app/system-commands/commands/mkdir.cfc b/src/cfml/system/modules_app/system-commands/commands/mkdir.cfc index 7676a8dd5..22ece7c0e 100644 --- a/src/cfml/system/modules_app/system-commands/commands/mkdir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/mkdir.cfc @@ -2,13 +2,13 @@ * Create a new directory. * . * {code:bash} - * mkdir newDir + * mkdir newDir * {code} * * You can also change your current working directory to the new path with the cd flag. * . * {code:bash} - * mkdir newDir --cd + * mkdir newDir --cd * {code} * **/ @@ -19,27 +19,27 @@ component { * @cd.hint CD into the directory after creating **/ function run( required String directory, boolean cd=false ) { - + // Validate directory if( !len( arguments.directory ) ) { - return error( 'Please provide a directory name.' ); + return error( 'Please provide a directory name.' ); } - - // This will make each directory canonical and absolute + + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Create dir. Ignore if it exists and also create parent folders if missing directorycreate( arguments.directory, true, true ); - + print.greenLine( 'Created #arguments.directory#' ); - + // Optionally change into the new dir if( arguments.cd ) { command( 'cd' ) .params( arguments.directory ) .run(); } - + } diff --git a/src/cfml/system/modules_app/system-commands/commands/more.cfc b/src/cfml/system/modules_app/system-commands/commands/more.cfc index 1d4af9343..9db18a286 100644 --- a/src/cfml/system/modules_app/system-commands/commands/more.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/more.cfc @@ -3,11 +3,11 @@ * Press space to advance one line at a time, Ctrl-c, ESC, or "q" to abort and any other key to advance one page at a time. * . * {code:bash} - * forgebox show | more + * forgebox show | more * {code} **/ component excludeFromHelp=true { - + /** * @input.hint The piped input to be displayed. **/ @@ -15,11 +15,11 @@ component excludeFromHelp=true { // Get terminal height var termHeight = shell.getTermHeight()-2; // Turn output into an array, breaking on carriage returns - var content = listToArray( arguments.input, CR ); + var content = listToArray( arguments.input, CR ); var key= ''; var i = 0; var StopAtLine = termHeight; - + // Loop over content while( ++i <= content.len() ) { if( i > StopAtLine ) { @@ -36,12 +36,12 @@ component excludeFromHelp=true { // Everything else is one page } else { // 13 => enter - StopAtLine += termHeight; + StopAtLine += termHeight; } } // print out a line print.line( content[ i ] ); - + } } diff --git a/src/cfml/system/modules_app/system-commands/commands/mv.cfc b/src/cfml/system/modules_app/system-commands/commands/mv.cfc index e9ba61809..3216306ad 100644 --- a/src/cfml/system/modules_app/system-commands/commands/mv.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/mv.cfc @@ -3,7 +3,7 @@ * . * Rename a file * {code:bash} - * mv sample.html sample.htm + * mv sample.html sample.htm * {code} * . * Move a file @@ -13,15 +13,15 @@ * . * Rename a directory * {code:bash} - * mv foo/ bar/ + * mv foo/ bar/ * {code} * . * Move a directory * {code:bash} - * mv foo/ bar/foo/ + * mv foo/ bar/foo/ * {code} * - **/ + **/ component aliases="rename" { /** @@ -29,14 +29,14 @@ component aliases="rename" { * @newPath.hint The new name of the file or directory **/ function run( required Globber path, required newPath ) { - + // Make path canonical and absolute var thisNewPath = fileSystemUtil.resolvePath( arguments.newPath ); - + if( path.count() > 1 && !directoryExists( thisNewPath ) ) { error( '[#thisNewPath#] is not a directory.' ); } - + path.apply( function( thisPath ){ print.redLine( thisPath ); // It's a directory @@ -49,11 +49,11 @@ component aliases="rename" { // move file fileMove( thisPath, thisNewPath ); print.greenLine( "File renamed/moved to #thisNewPath#" ); - } else { + } else { return error( "File/directory does not exist: #thisPath#" ); - } + } } ); - + } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/pause.cfc b/src/cfml/system/modules_app/system-commands/commands/pause.cfc index 059a7c728..8e82d122b 100644 --- a/src/cfml/system/modules_app/system-commands/commands/pause.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/pause.cfc @@ -1,6 +1,6 @@ /** * This commnd waits for the user to press a key to continue. You could use this in a boxr recipe -* to pause execution so you can see the previous commands' output before the windows closes if +* to pause execution so you can see the previous commands' output before the windows closes if * calling it from a shortcut to a native OS prompt that closes as soon as it's complete. * . * {code:bash} @@ -12,7 +12,7 @@ component excludeFromHelp=true { function run() { waitForKey( 'Press any key to continue...' ); - print.line(); + print.line(); } diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc index 7109cfb9d..acc35152e 100644 --- a/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/clear.cfc @@ -4,10 +4,10 @@ * {code:bash} * propertyFile clear my.name * {code} - * + * **/ component { - + /** * @propertyFilePath The path to the property file to interact with * @propertyName The name of the property to clear @@ -19,16 +19,16 @@ component { // This will make each directory canonical and absolute propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); - + // Create and load property file object propertyFile( propertyFilePath ) .remove( propertyName ) .store(); - + print .greenLine( 'Property removed!' ) .line( propertyName ); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc index 58c7b8bdd..a3a857687 100644 --- a/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/set.cfc @@ -4,10 +4,10 @@ * {code:bash} * propertyFile set name=mySetting * {code} - * + * **/ component { - + /** * @propertyFilePath The path to the property file to interact with * @propertyName The name of the property to set @@ -21,16 +21,16 @@ component { // This will make each directory canonical and absolute propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); - + // Create and load property file object propertyFile( propertyFilePath ) .set( propertyName, propertyValue ) .store(); - + print .greenLine( 'Property set!' ) .line( propertyName & ' = ' & propertyValue ); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc b/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc index cc2621336..84a72ed76 100644 --- a/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/propertyFile/show.cfc @@ -7,10 +7,10 @@ * propertyFile show property.name.here * propertyFile show --JSON * {code} - * + * **/ component { - + /** * @propertyFilePath The path to the property file to interact with * @propertyName The name of the property to show @@ -21,13 +21,13 @@ component { string propertyName='', boolean JSON=false ) { - + // This will make each directory canonical and absolute propertyFilePath = fileSystemUtil.resolvePath( propertyFilePath ); - + // Create and load property file object var propertyFile = propertyFile( propertyFilePath ); - + // JSON output takes precedence if( JSON ) { print.text( formatterUtil.formatJson( propertyFile.getAsStruct() ) ); @@ -42,7 +42,7 @@ component { print.line( i & ' = ' & properties[ i ] ); } ); } - + } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/pwd.cfc b/src/cfml/system/modules_app/system-commands/commands/pwd.cfc index ada56f07d..9f4731669 100644 --- a/src/cfml/system/modules_app/system-commands/commands/pwd.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/pwd.cfc @@ -4,7 +4,7 @@ * {code:bash} * pwd * {code} - * + * **/ component { diff --git a/src/cfml/system/modules_app/system-commands/commands/quit.cfc b/src/cfml/system/modules_app/system-commands/commands/quit.cfc index d47f77901..4c86e3aad 100644 --- a/src/cfml/system/modules_app/system-commands/commands/quit.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/quit.cfc @@ -1,5 +1,5 @@ /** -* Exits out of the shell. If the CommandBox binary was executed directly, the shell will close. If the +* Exits out of the shell. If the CommandBox binary was executed directly, the shell will close. If the * CommandBox binary was run from your OS's native shell, you will be returned there. * . * {code:bash} @@ -16,5 +16,5 @@ component aliases="exit,q,e" { function run() { shell.exit(); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/recipe.cfc b/src/cfml/system/modules_app/system-commands/commands/recipe.cfc index 2b66dd778..7f446dbda 100644 --- a/src/cfml/system/modules_app/system-commands/commands/recipe.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/recipe.cfc @@ -6,10 +6,10 @@ * {code:bash} * recipe myRecipe.boxr * {code} - * . - * You can also bind the recipe with arguments that will be replaced inside of your recipe. - * Pass any arguments as additional parameters to the recipe command. - * Named arguments will be accessable inside the recipe as $arg1Name, $arg2Name, etc. + * . + * You can also bind the recipe with arguments that will be replaced inside of your recipe. + * Pass any arguments as additional parameters to the recipe command. + * Named arguments will be accessable inside the recipe as $arg1Name, $arg2Name, etc. * Positional args will be avaialble as $1, $2, etc. * . * Recipe will receive $name and $action @@ -27,7 +27,7 @@ * $arg1 may contain spaces * {code:bash} * rm "$arg1" - * {code} + * {code} * . * If an argument is not bound, no error will be thrown, and the name of the argument will be left in the command. * . @@ -35,20 +35,20 @@ * This can be useful for debugging or confirming the success of commands with no output. Echo is on by default. * Note, "echo off" doesn't suppress the output of the commands, just the printing of the command and its arguments prior to execution. * This does not use the actual "echo" command and is a feature that only applies during the execution of recipes. - * + * * {code:bash} * echo on * # Now you see me * echo off - * # Now you don't - * {code} - * + * # Now you don't + * {code} + * **/ component { - + // DI Properties property name='parser' inject='Parser'; - + /** * @recipeFile.hint The name of the recipe file to execute including extension. Any text file may be used. **/ @@ -57,32 +57,32 @@ component { var originalPath = getCWD(); // Make file canonical and absolute arguments.recipeFile = fileSystemUtil.resolvePath( arguments.recipeFile ); - + // Validate the file if( !fileExists( arguments.recipeFile ) ){ return error( "File: #arguments.recipeFile# does not exist!" ); } - + var isEcho = true; - + // read it var recipe = fileRead( arguments.recipeFile ); - + // Parse arguments var sArgs = parseArguments( arguments ); - + // bind commands with arguments recipe = bindArgs( recipe, sArgs ); - + // split commands using carriage returns and/or line feeds var commands = listToArray( recipe, chr( 10 ) & chr( 13 ) ); - + // iterate and execute. for( var thisCommand in commands ){ thisCommand = trim( thisCommand ); - + // Ignore blank lines and comments. - // Comments are any line that starts with a hash followed by some form of whitespace. + // Comments are any line that starts with a hash followed by some form of whitespace. if( !thisCommand.len() || reFindNoCase( '##\s', thisCommand ) ) { continue; } @@ -97,11 +97,11 @@ component { print.line( thisCommand ); continue; } - + try{ // If echo is on, display the command if( isEcho ) { - print.line( thisCommand ); + print.line( thisCommand ); } // run Command runCommand( thisCommand ); @@ -112,7 +112,7 @@ component { } } - // cd to original path just incase + // cd to original path just incase shell.cd( originalPath ); } @@ -133,7 +133,7 @@ component { */ private struct function parseArguments( required args ){ var parsedArgs = {}; - + for( var arg in args ) { argName = arg; if( !isNull( args[arg] ) && arg != 'recipeFile' ) { diff --git a/src/cfml/system/modules_app/system-commands/commands/reload.cfc b/src/cfml/system/modules_app/system-commands/commands/reload.cfc index 126b7fdf5..01581ba46 100644 --- a/src/cfml/system/modules_app/system-commands/commands/reload.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/reload.cfc @@ -1,6 +1,6 @@ /** - * Reload CommandBox. This is a maintenance operation to recreate the shell and reload all commands in - * the command folders. Use this if developing commands to quickly reload your changes after modifying + * Reload CommandBox. This is a maintenance operation to recreate the shell and reload all commands in + * the command folders. Use this if developing commands to quickly reload your changes after modifying * the command's CFC file. All files will be recreated except /system/BootStrap.cfm. * . * {code:bash} diff --git a/src/cfml/system/modules_app/system-commands/commands/repl.cfc b/src/cfml/system/modules_app/system-commands/commands/repl.cfc index 8c657b4f1..57096592a 100644 --- a/src/cfml/system/modules_app/system-commands/commands/repl.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/repl.cfc @@ -1,5 +1,5 @@ /** - * The REPL (Read-Eval-Print-Loop) command allows you to write and execute a-la-carte CFML code right in + * The REPL (Read-Eval-Print-Loop) command allows you to write and execute a-la-carte CFML code right in * your console. Variables set in will be available on subsequent lines. * . * {code:bash} @@ -13,9 +13,9 @@ * repl --!script * {code} * . - * The REPL has a separate command history for scripts and tags. Use the up-arrow to look at previous + * The REPL has a separate command history for scripts and tags. Use the up-arrow to look at previous * lines in the history. The REPLs histories can be managed by the "history" command. - * + * **/ component { @@ -33,12 +33,12 @@ component { * @directory.hint Directory to start the REPL in (defaults to current working directory). **/ function run( string input, boolean script=true, string directory='' ){ - + var quit = false; var results = ""; var executor = wirebox.getInstance( "executor" ); var newHistory = arguments.script ? variables.REPLScriptHistoryFile : variables.REPLTagHistoryFile; - + arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); // Setup REPL history file @@ -48,7 +48,7 @@ component { print.cyanLine( "Enter any valid CFML code in the following prompt in order to evaluate it and print out any results (if any)" ); print.line( "Type 'quit' or 'q' to exit!" ).toConsole(); } - + // Loop until they choose to quit while( !quit ){ @@ -57,41 +57,41 @@ component { REPLParser.startCommand(); REPLParser.addCommandLines( arguments.input ); quit = true; - + // Else, collect the code via a prompt } else { - + // start new command REPLParser.startCommand(); - + do { // ask repl if ( arrayLen( REPLParser.getCommandLines() ) == 0 ) { var command = ask( ( arguments.script ? 'CFSCRIPT' : 'CFML' ) & '-REPL: ' ); } else { var command = ask( "..." ); - + // allow ability to break out of adding additional lines if ( trim(command) == 'exit' || trim(command) == '' ) { break; } } - + // add command to our parser REPLParser.addCommandLine( command ); - + } while ( !REPLParser.isCommandComplete() ); - + } // REPL command is complete. get entire command as string var cfml = REPLParser.getCommandAsString(); - + // quitting if( listFindNoCase( 'quit,q,exit', cfml ) ){ quit = true; } else { - + // evaluate it try { @@ -111,7 +111,7 @@ component { results = REPLParser.serializeOutput( results ); print.line( results, structKeyExists( arguments, 'input' ) ? '' : 'boldRed' ) } - + } catch( any e ){ // flush out anything in buffer print.toConsole(); @@ -135,7 +135,7 @@ component { } // flush history out newHistory.flush(); - // set back original history + // set back original history shell.getReader().setHistory( commandHistoryFile ); } @@ -160,4 +160,4 @@ component { return variableType; } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/run.cfc b/src/cfml/system/modules_app/system-commands/commands/run.cfc index c27305956..8efcbb0ed 100644 --- a/src/cfml/system/modules_app/system-commands/commands/run.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/run.cfc @@ -1,5 +1,5 @@ /** - * Execute an operating system level command in the native shell. The binary must be in the PATH, or you can specify the full + * Execute an operating system level command in the native shell. The binary must be in the PATH, or you can specify the full * path to it. This command will wait for the OS exectuable to complete but will flush the output as it is received. * . * {code:bash} @@ -8,7 +8,7 @@ * {code} * . * A shortcut for running OS binaries is to prefix the binary with "!". In this mode, any other params need to be positional. - * There is no CommandBox parsing applied to the command's arguments. They are passed straight to the native shell. + * There is no CommandBox parsing applied to the command's arguments. They are passed straight to the native shell. * . * {code:bash} * !myApp.exe @@ -37,7 +37,7 @@ * **/ component{ - + property name="configService" inject="configService"; /** @@ -46,7 +46,7 @@ component{ function run( required command ){ - + // Prep the command to run in the OS-specific shell if( fileSystemUtil.isWindows() ) { // Pass through Windows' command shell, /a outputs ANSI formatting, /c runs as a command @@ -57,13 +57,13 @@ component{ var nativeShell = configService.getSetting( 'nativeShell', '/bin/bash' ); commandArray = [ nativeShell, '-i', '-c', arguments.command & ' && ( exit $? > /dev/null )' ]; } - + try{ // grab the current working directory var CWDFile = createObject( 'java', 'java.io.File' ).init( fileSystemUtil.resolvePath( '' ) ); var exitCode = createObject( "java", "java.lang.ProcessBuilder" ) .init( commandArray ) - // Do you believe in magic + // Do you believe in magic // This works great on Mac/Windows. // On Linux, the standard input (keyboard) is not being piped to the background process. .inheritIO() @@ -73,10 +73,10 @@ component{ .start() // waits for it to exit, returning the exit code .waitFor(); - + if( exitCode != 0 ) { error( 'Command returned failing exit code [#exitCode#]' ); - } + } } catch( any e ){ error( '#e.message##CR##e.detail#' ); @@ -84,4 +84,4 @@ component{ } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/sed.cfc b/src/cfml/system/modules_app/system-commands/commands/sed.cfc index 0840333b2..bec45a18c 100644 --- a/src/cfml/system/modules_app/system-commands/commands/sed.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/sed.cfc @@ -23,7 +23,7 @@ * . * The delimiter in the subsdtitute command does not have to be "/". Whatever character * that immediatley follows the "s" will be used. This can be useful where the regex - * and/or replacement text contain a "/". + * and/or replacement text contain a "/". * . * This example uses a tilde (~) as the delimiter. It reads a file, replaces all instances * of a given file path, and writes the file back out. @@ -36,7 +36,7 @@ component { // DI Properties property name='parser' inject='Parser'; - + /** * @inputOrFile.hint The text to process, or a file name to read with --file * @commands.hint The command to perform on the input text. Ex: s/replaceMe/withMe/g @@ -47,32 +47,32 @@ component { required string commands, boolean file=false ) { - + // Treat input as a file path if( arguments.file ) { - arguments.inputOrFile = runCommand( command="cat '#parser.escapeArg( arguments.inputOrFile )#'", returnOutput=true ); + arguments.inputOrFile = runCommand( command="cat '#parser.escapeArg( arguments.inputOrFile )#'", returnOutput=true ); } - + // Turn output into an array, breaking on carriage returns var inputLines = listToArray( arguments.inputOrFile, CR ); arguments.commands = trim( arguments.commands ); - + // Only support a single command right now if( left( arguments.commands, 1 ) == 's' ) { substitute( inputLines, right( arguments.commands, len( arguments.commands ) -1 ) ); } else { return error( 'Unknown command: [#arguments.commands#]. Type "sed help" for assistance.' ); } - + } private function substitute( inputLines, command ) { var commandParts = parseCommandParts( arguments.command ); if( hasError() ) { return; } var flags = parseFlags( commandParts.flags ); - + try { - + // Loop over content for( var line in inputLines ) { if( flags.caseInsensitive ) { @@ -80,13 +80,13 @@ component { } else { line = REReplace( line, commandParts.regex, commandParts.replacement, ( flags.global ? 'all' : 'one' ) ); } - + print.line( line ); - + } // End loop over inputLines - + } catch ( any var e ) { - // Any errors here are most likley from bad regex. Control the "error" and + // Any errors here are most likley from bad regex. Control the "error" and // include some additional debugging information. return error( e.message & CR & @@ -94,7 +94,7 @@ component { 'Replacement: ' & commandParts.replacement ); } - + } private function parseCommandParts( command ) { @@ -102,18 +102,18 @@ component { // The next char is the delimiter. (doesn't have to be "/") var delimiter = left( str, 1 ); str = right( str, len( str ) -1 ); - + var strLen = str.length(); var isEscaped = false; var char = ''; var phase = 1; - + var commandParts = { regex = '', replacement = '', flags = '' }; - + // closure to help building up each part var appendStr = function() { // phase 1 is the regex @@ -123,19 +123,19 @@ component { // everything else is the flags else { commandParts.flags &= char; } }; - + // Not using list manipulation since the list delimiter is variable // AND can appear escaped with a backslash in the actual values. for (var i=0; i 1 ) { - var rawText = true; - } + var rawText = true; + } var filePath = fileSystemUtil.resolvePath( arguments.path ); if( !fileExists( filePath ) ){ var rawText = true; } - + // If we're piping raw text and not a file if( rawText ) { // Only show the last X lines var startIndex = max( inputAsArray.len() - arguments.lines + 1, 1 ); while( startIndex <= inputAsArray.len() ) { print.line( inputAsArray[ startIndex++ ] ); - } - + } + return; } variables.file = createObject( "java", "java.io.File" ).init( filePath ); - + var startPos = findStartPos(); var startingLength = 0; - + try { - + var lineCounter = 0; var buffer = []; var randomAccessFile = createObject( "java", "java.io.RandomAccessFile" ).init( variables.file, "r" ); - var startingLength = variables.file.length(); + var startingLength = variables.file.length(); variables.position = startingLength; - + // move to the end of the file randomAccessFile.seek( position ); - // Was the last character a line feed. + // Was the last character a line feed. // Remeber the CRLFs will be coming in reverse order var lastLF = false; - + while( true && startingLength ){ - + var char = randomAccessFile.read(); - + // Only increment CRs that were preceeded by a LF if ( char == 13 && !lastLF ) { lineCounter += 1; @@ -75,33 +75,33 @@ component { if ( char == 10 ) { lastLF=true; lineCounter += 1; - } else { + } else { lastLF=false; } if ( char != -1 ) buffer.append( chr( char ) ); - + position--; - + // stop looping if we have met our line limit or if end of file if ( position < startPos || lineCounter == arguments.lines ) { break; } - + // move to the preceding character randomAccessFile.seek( position ); - + } // End while - + if( buffer.len() ) { // Strip any CR or LF from the last (first really) line to eliminate leading line breaks in console output buffer[ buffer.len() ] = listChangeDelims( buffer[ buffer.len() ], '', chr(13) & chr( 10 ) ); } - - // print our file to console + + // print our file to console print .text( buffer.reverse().toList( "" ) ) .toConsole(); - + } finally { if( isDefined( 'randomAccessFile' ) ) { @@ -110,17 +110,17 @@ component { } // If we're not following the file, just bail here. - if( !follow ) { + if( !follow ) { if( buffer.len() ) { print.line(); } return; } - + position = startingLength; // This lets the thread know we're still running variables.tailRun = true; - + try { // This thread will keep redrawing the screen while the main thread waits for user input threadName = 'tail#createUUID()#'; @@ -128,24 +128,24 @@ component { try{ // Only keep drawing as long as the main thread is active while( variables.tailRun ) { - + var randomAccessFile = createObject( "java", "java.io.RandomAccessFile" ).init( file, "r" ); randomAccessFile.seek( position ); // As long as there is at least one more character in the file - while( ( var char = randomAccessFile.read() ) > -1 ){ + while( ( var char = randomAccessFile.read() ) > -1 ){ // output it print .text( chr( char ) ) .toConsole(); - - randomAccessFile.seek( ++position ); + + randomAccessFile.seek( ++position ); } // Close the file every time so we don't keep it open and locked randomAccessFile.close(); - + // Decrease this to speed up the Tail sleep( 300 ); - } + } } catch( any e ) { logger.error( e.message & ' ' & e.detail, e.stacktrace ); } finally { @@ -154,13 +154,13 @@ component { randomAccessFile.close(); } } - + } // End thread - + while( true ) { // Wipe out prompt so it doesn't redraw if the user hits enter shell.getReader().setPrompt( '' ); - + // Detect user pressing Ctrl-C // Any other characters captured will be ignored var line = shell.getReader().readLine(); @@ -171,8 +171,8 @@ component { } } - - // user wants to exit, they've pressed Ctrl-C + + // user wants to exit, they've pressed Ctrl-C } catch ( jline.console.UserInterruptException e ) { // make sure the thread exits variables.tailRun = false; @@ -188,15 +188,15 @@ component { shell.setPrompt(); rethrow; } - + // We're done with the Tail, clean up. variables.tailRun = false; // Wait until the thread finishes its last draw thread action="join" name=threadName; shell.setPrompt(); - + } - + // Deal with BOM (Byte order mark) // TODO: Actually pay attention to the BOM! function findStartPos() { @@ -207,7 +207,7 @@ component { ; // Will contain the first few bytes of the file represented by an integer var peek = ''; - + // If the file has a least 2 bytes if( length > 1 ) { // read them @@ -218,9 +218,9 @@ component { if( listFindNoCase( '254255,255254', peek ) ) { // Start after it startPos=2; - } + } } - + // If the file has a least 3 bytes if( length > 2 && ! startPos ) { // read them @@ -230,7 +230,7 @@ component { if( listFindNoCase( '239187191', peek ) ) { // Start after it startPos=3; - } + } } // If the file has at least 4 bytes and we didn't find a 3 byte BOM if( length > 3 && ! startPos) { @@ -241,11 +241,11 @@ component { if( listFindNoCase( '00254255,25525400', peek ) ) { // Start after it startPos=4; - } + } } - + randomAccessFile.close(); return startPos; } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc b/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc index aa2d14cd4..2eb9ab216 100644 --- a/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/tokenReplace.cfc @@ -12,7 +12,7 @@ * tokenReplace path=file.txt token="foo" replacement="bar" * {code} * - **/ + **/ component { /** @@ -26,9 +26,9 @@ component { required String token, required String replacement, boolean verbose=false ) { - + path.apply( function( thisPath ) { - + // It's a file if( fileExists( thisPath ) ){ if( verbose ) { @@ -36,11 +36,11 @@ component { } var fileContents = fileRead( thisPath ); if( fileContents.findNoCase( token ) ) { - fileWrite( thisPath, fileContents.replaceNoCase( token, replacement, 'all' ) ); + fileWrite( thisPath, fileContents.replaceNoCase( token, replacement, 'all' ) ); } } - } ); + } ); } - + } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/touch.cfc b/src/cfml/system/modules_app/system-commands/commands/touch.cfc index 4a1ba4364..bf8c7cb32 100644 --- a/src/cfml/system/modules_app/system-commands/commands/touch.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/touch.cfc @@ -17,7 +17,7 @@ * {code:bash} * touch file.txt --force * {code} - * + * **/ component aliases="new" { @@ -30,25 +30,25 @@ component aliases="new" { required Globber file, boolean force=false, boolean open=false ) { - + // Get matching paths var matches = file.matches(); - - // If no paths were found and the pattern isn't a glob, just use the pattern (it's a new file). + + // If no paths were found and the pattern isn't a glob, just use the pattern (it's a new file). if( !file.count() && !( file.getPattern() contains '*' ) && !( file.getPattern() contains '?' ) ) { matches.append( file.getPattern() ); } - + for( var theFile in matches ) { - + var oFile = createObject( "java", "java.io.File" ).init( theFile ); var fileName = listLast( theFile, "/" ); - + // if we have a force, recreate the file if( arguments.force and oFile.exists() ){ oFile.delete(); } - + // check for update or creation if( !oFile.exists() ){ oFile.createNewFile(); @@ -57,7 +57,7 @@ component aliases="new" { oFile.setLastModified( now().getTime() ); print.line( "#fileName# last modified bit updated!" ); } - + // Open file for the user if( arguments.open ){ // Defer to the "edit" command. @@ -65,9 +65,9 @@ component aliases="new" { .params( theFile ) .run(); } - + } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc b/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc index 00f6b7954..cc2eb44ca 100644 --- a/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc @@ -28,7 +28,7 @@ component { property name="progressBar" inject="ProgressBar"; property name="semanticVersion" inject="semanticVersion@semver"; property name="ConfigService" inject="ConfigService"; - + /** * @latest.hint Will download bleeding edge if true, last stable version if false * @force.hint Force the update even if the version on the server is the same as locally @@ -43,8 +43,8 @@ component { print.greenLine( "Getting #arguments.latest ? 'latest' : 'stable'# versioning information from #thisArtifactsURL#" ).toConsole(); var boxRepoURL = '#thisArtifactsURL#ortussolutions/commandbox/box-repo.json'; var loaderRepoURL = '#thisArtifactsURL#ortussolutions/commandbox/box-loader.json'; - - http + + http url="#boxRepoURL#" file="#temp#/box-repo.json" throwOnError=false @@ -53,7 +53,7 @@ component { proxyUser="#ConfigService.getSetting( 'proxy.user', '' )#" proxyPassword="#ConfigService.getSetting( 'proxy.password', '' )#" result="local.boxRepoResult"; - + http url="#loaderRepoURL#" file="#temp#/box-loader.json" @@ -63,19 +63,19 @@ component { proxyUser="#ConfigService.getSetting( 'proxy.user', '' )#" proxyPassword="#ConfigService.getSetting( 'proxy.password', '' )#" result="local.loaderRepoResult"; - + // Do some error checking if( !local.boxRepoResult.statusCode contains "200" || !fileExists( '#temp#/box-repo.json' ) || !local.loaderRepoResult.statusCode contains "200" || !fileExists( '#temp#/box-loader.json' ) ) { error( "Sorry, we're having troubles accessing the interwebs now or the update site is down. Please try again later", "Box Repo: [#local.boxRepoResult.statusCode#] Loader Repo: [#local.loaderRepoResult.statusCode#]" - ); + ); } - + var boxRepoJSON = fileRead( '#temp#/box-repo.json' ); var loaderRepoJSON = fileRead( '#temp#/box-loader.json' ); - + if( !isJSON( boxRepoJSON ) ) { return error( "Oops, we expected [#boxRepoURL#] to be JSON, but it wasn't. #cr#I'm afraid we can't upgrade right now." ); } @@ -96,9 +96,9 @@ component { // We don't store build numbers for stable versions in box-repo.json var repoVersionShort= repoData.versioning.stableVersion; var repoVersion = repoVersionShort; - var loaderVersion = loaderData.versioning.stableVersion; + var loaderVersion = loaderData.versioning.stableVersion; } - + // Is there a new version of CommandBox. New builds consistute new BE verions. var isNewVersion = semanticVersion.isNew( current=shell.getVersion(), target=repoVersion, checkBuildID=arguments.latest ); // Is there a new version of the CLI Loader. Ignore build number since it's sort of fake (Just a copy of the CommandBox build number) @@ -109,7 +109,7 @@ component { // Inform User about update print.boldCyanLine( "Ohh Goody Goody, an update has been found (#repoVersion#) for your installation (#shell.getVersion()#)!" ) .toConsole(); - + if( isNewLoaderVersion ) { // We can't handle this kind of update from CFML // so instruct the user to do a manual update with a new binary @@ -155,14 +155,14 @@ component { // Notify the user print - .greenLine( "Update applied successfully, installed v#repoVersion#" ) + .greenLine( "Update applied successfully, installed v#repoVersion#" ) .redLine( "CommandBox needs to exit to complete the installation." ) .yellowLine( "This message will self-destruct in 10 seconds" ) .toConsole(); - + // Give them a chance to read it. sleep( 10000 ); - + // Stop executing. Since the unzipping possbily replaced .cfm files that were // also cached in memory, there's no good way we've found to be able to reload and keep going. abort; diff --git a/src/cfml/system/modules_app/system-commands/commands/version.cfc b/src/cfml/system/modules_app/system-commands/commands/version.cfc index 020ef90e9..fe039c38f 100644 --- a/src/cfml/system/modules_app/system-commands/commands/version.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/version.cfc @@ -19,9 +19,9 @@ component aliases="ver" { */ function run( boolean loader=false ) { if( arguments.loader ) { - print.line( 'CLI Loader #shell.getLoaderVersion()#' ); + print.line( 'CLI Loader #shell.getLoaderVersion()#' ); } else { - print.line( 'CommandBox #shell.getVersion()#' ); + print.line( 'CommandBox #shell.getVersion()#' ); } } diff --git a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc index 21ba49957..0d89251af 100644 --- a/src/cfml/system/modules_app/task-commands/commands/task/run.cfc +++ b/src/cfml/system/modules_app/task-commands/commands/task/run.cfc @@ -1,24 +1,24 @@ /** * Run a task. By default this will look for a file called "task.cfc" in the current directory and invoke it's run() method. - * + * * {code} * task run * {code} - * + * * Override the file name and/or method name with the taskFile and target parameters. The .cfc is optional. - * + * * {code} * task run build.cfc createZips * {code} * * To pass parameters to your task, include additional positional parameters or named parameters starting with a colon (:). * Theses parameters will appear directly in the arguments scope of the task. - * + * * {code} * task run build.cfc createZips value1 value2 * task run :param1=value1 :param2=value2 * {code} - * + * **/ component { property name='taskService' inject='taskService@task-commands'; @@ -31,15 +31,15 @@ component { string taskFile='task.cfc', string target='run' ) { - + arguments.taskFile = fileSystemUtil.resolvePath( arguments.taskFile ); var taskArgs = {}; - + // Named task args will come through in a struct called args // task run :param=value :param2=value2 if( arguments.keyExists( 'args' ) && isStruct( arguments.args ) ) { taskArgs = arguments.args; - + // Positional task args will come through direclty in the arguments scope // task run task.cfc run value value2 } else if( arguments.count() > 1 ) { @@ -49,10 +49,10 @@ component { taskArgs.delete( 'taskFile' ); taskArgs.delete( 'target' ); } - + // Run the task! // We're printing the output here so we can capture it and pipe or redirect the output from "task run" - print.text( + print.text( taskService.runTask( taskFile, target, taskArgs ) ); } diff --git a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc index 5c222870b..32d5f9c28 100644 --- a/src/cfml/system/modules_app/task-commands/models/TaskService.cfc +++ b/src/cfml/system/modules_app/task-commands/models/TaskService.cfc @@ -8,7 +8,7 @@ * I handle running tasks */ component singleton accessors=true { - + // DI Properties property name='FileSystemUtil' inject='FileSystem'; property name='logger' inject='logbox:logger:{this}'; @@ -25,61 +25,61 @@ component singleton accessors=true { .setAutowire( false ); } } - + /** * Runs a task - * + * * @taskFile Path to the Task CFC that you want to run * @target Method in Task CFC to run * @taskArgs Struct of arguments to pass on to the task - * + * * @returns The output of the task. It's up to the caller to output it. */ string function runTask( required string taskFile, required string target='run', taskArgs={} ) { - + // This is neccessary so changes to tasks get picked up right away. pagePoolClear(); - + // We need the .cfc extension for the file exists check to work. if( right( taskFile, 4 ) != '.cfc' ) { taskFile &= '.cfc'; } - + if( !fileExists( taskFile ) ) { throw( message="Task CFC doesn't exist.", detail=arguments.taskFile, type="commandException"); } - + // Create an instance of the taskCFC. To prevent caching of the actual code in the task, we're treating them as // transients. Since is since the code is likely to change while devs are building and testing them. var taskCFC = createTaskCFC( taskFile ); - + // If target doesn't exist or isn't a UDF - if( !structKeyExists( taskCFC, target ) || !IsCustomFunction( taskCFC[ target ] ) ) { + if( !structKeyExists( taskCFC, target ) || !IsCustomFunction( taskCFC[ target ] ) ) { throw( message="Target [#target#] doesn't exist in Task CFC.", detail=arguments.taskFile, type="commandException"); } - + // Run the task taskCFC[ target ]( argumentCollection = taskArgs ); - + // Return any output. It's up to the caller to output it. // This is so task output can be correctly captured and piped or redirected to a file. return taskCFC.getResult(); - + } - - + + function createTaskCFC( required string taskFile ) { // Convert to use a mapping var relTaskFile = FileSystemUtil.makePathRelative( taskFile ); - + // Strip .cfc back off relTaskFile = mid( relTaskFile, 1, len( relTaskFile ) - 4 ); relTaskFile = relTaskFile.listChangeDelims( '.', '/' ); relTaskFile = relTaskFile.listChangeDelims( '.', '\' ); - + // Create this Task CFC try { - + // Check if task mapped? if( NOT wirebox.getBinder().mappingExists( "task-" & relTaskFile ) ){ // feed this task to wirebox with virtual inheritance @@ -88,7 +88,7 @@ component singleton accessors=true { } // retrieve, build and wire from wirebox return wireBox.getInstance( "task-" & relTaskFile ); - + // This will catch nasty parse errors and tell us where they happened } catch( any e ){ // Log the full exception with stack trace @@ -98,4 +98,3 @@ component singleton accessors=true { } } - diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/bdd.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/bdd.cfc index 3e432f296..2d3d8b164 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/bdd.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/bdd.cfc @@ -8,7 +8,7 @@ * **/ component { - + /** * @name.hint Name of the BDD spec to create without the .cfc. For packages, specify name as 'myPackage/myBDDSpec' * @open.hint Open the file once it is created @@ -17,7 +17,7 @@ component { function run( required name, boolean open=false, directory=getCWD() ){ // Allow dot-delimited paths arguments.name = replace( arguments.name, '.', '/', 'all' ); - + // Check if the name is actually a path var nameArray = arguments.name.listToArray( '/' ); var nameArrayLength = nameArray.len(); @@ -27,28 +27,28 @@ component { var extendedPath = nameArray.slice(1, nameArrayLength - 1).toList('/'); arguments.directory &= '/#extendedPath#'; } - - // This will make each directory canonical and absolute + + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } - + // This help readability so the success messages aren't up against the previous command line print.line(); - + // Read in Templates var BDDContent = fileRead( '/testbox-commands/templates/testbox/bdd.txt' ); - + // Write out BDD Spec - var BDDPath = '#directory#/#name#.cfc'; + var BDDPath = '#directory#/#name#.cfc'; file action='write' file='#BDDPath#' mode ='777' output='#BDDContent#'; print.greenLine( 'Created #BDDPath#' ); // Open file? - if( arguments.open ){ openPath( bddPath ); } + if( arguments.open ){ openPath( bddPath ); } } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/help.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/help.cfc index c45cf6de3..02dd0d2d6 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/help.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/help.cfc @@ -1,15 +1,15 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellow( 'The ' ); print.boldYellow( 'testbox create' ); print.yellowLine( ' namespace allows you to quickly create specs for your TestBox test suites. ' ); print.yellowLine( 'Use these commands to stub out placeholder unit and integration tests as well as BDD specs.' ); print.yellowLine( 'Type help before any command name to get additional information on how to call that specific command.' ); - + print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/unit.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/unit.cfc index 69dbe9786..489eedc69 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/unit.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/create/unit.cfc @@ -5,10 +5,10 @@ * {code:bash} * testbox create unit myTest * {code} -* +* **/ component { - + /** * @name.hint Name of the xUnit bundle to create without the .cfc. For packages, specify name as 'myPackage/MyTest' * @open.hint Open the file once it is created @@ -17,7 +17,7 @@ component { function run( required name, boolean open=false, directory=getCWD() ){ // Allow dot-delimited paths arguments.name = replace( arguments.name, '.', '/', 'all' ); - + // Check if the name is actually a path var nameArray = arguments.name.listToArray( '/' ); var nameArrayLength = nameArray.len(); @@ -27,28 +27,28 @@ component { var extendedPath = nameArray.slice(1, nameArrayLength - 1).toList('/'); arguments.directory &= '/#extendedPath#'; } - - // This will make each directory canonical and absolute + + // This will make each directory canonical and absolute arguments.directory = fileSystemUtil.resolvePath( arguments.directory ); - + // Validate directory if( !directoryExists( arguments.directory ) ) { - directoryCreate( arguments.directory ); + directoryCreate( arguments.directory ); } - + // This help readability so the success messages aren't up against the previous command line print.line(); - + // Read in Templates var content = fileRead( '/testbox-commands/templates/testbox/unit.txt' ); - + // Write out BDD Spec - var thisPath = '#directory#/#name#.cfc'; + var thisPath = '#directory#/#name#.cfc'; file action='write' file='#thisPath#' mode ='777' output='#content#'; print.greenLine( 'Created #thisPath#' ); // Open file? - if( arguments.open ){ openPath( thisPath ); } + if( arguments.open ){ openPath( thisPath ); } } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/harness.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/harness.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/harness.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/harness.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/help.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/help.cfc index 967c96215..bbc865fb4 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/help.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/generate/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use testbox generate' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/help.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/help.cfc index f8ca61870..d5da325af 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/help.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/help.cfc @@ -1,16 +1,16 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellow( 'The ' ); print.boldYellow( 'testbox' ); print.yellowLine( ' namespace helps you do anything related to your TestBox installation. Use these commands' ); print.yellowLine( 'to create tests, generate runners, and even run your tests for you from the command line.' ); - + print.yellowLine( 'Type help before any command name to get additional information on how to call that specific command.' ); - + print.line(); print.line(); - + } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc index 50877c9c5..6c508581a 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/run.cfc @@ -1,9 +1,9 @@ /** - * Executes TestBox runners via HTTP/S. By default, the "testbox.runner" property will be read from your box.json. + * Executes TestBox runners via HTTP/S. By default, the "testbox.runner" property will be read from your box.json. * . * {code:bash} * testbox run -* {code} +* {code} * . * You can also specify the URL manually * {code:bash} @@ -12,7 +12,7 @@ * **/ component { - + // DI property name="packageService" inject="PackageService"; property name="testingService" inject="TestingService@testbox-commands"; @@ -31,7 +31,7 @@ component { * @testSuites A list of suite names that are the ones that will be executed ONLY! * @testSpecs A list of test names that are the ones that will be executed ONLY! * @outputFile We will store the results in this output file as well as presenting it to you. - * @verbose Display extra details inlcuding passing and skipped tests. + * @verbose Display extra details inlcuding passing and skipped tests. **/ function run( string runner="", @@ -71,7 +71,7 @@ component { if( !find( "?", testboxURL ) ){ testboxURL &= "?"; } - + // Runner options overridable by arguments and box options var RUNNER_OPTIONS = { "reporter" : "json", @@ -91,11 +91,11 @@ component { // Check argument overrides if( !isNull( arguments[ thisOption ] ) ){ testboxURL &= "&#thisOption#=#arguments[ thisOption ]#"; - } + } // Check runtime options now else if( boxOptions.keyExists( thisOption ) ){ testboxURL &= "&#thisOption#=#boxOptions[ thisOption ]#"; - } + } // Defaults else if( len( RUNNER_OPTIONS[ thisOption ] ) ) { testboxURL &= "&#thisOption#=#RUNNER_OPTIONS[ thisOption ]#"; @@ -109,8 +109,8 @@ component { // run it now baby! try{ // Throw on error means this command will fail if the actual test runner blows up-- possibly on a compilation issue. - Http url=testBoxURL throwonerror=true result='local.results' ; - } catch( any e ){ + Http url=testBoxURL throwonerror=true result='local.results' ; + } catch( any e ){ logger.error( "Error executing tests: #e.message# #e.detail#", e ); return error( 'Error executing tests: #CR# #e.message##CR##e.detail##CR##local.results.fileContent ?: ''#' ); } @@ -123,29 +123,29 @@ component { fileWrite( arguments.outputFile, results.fileContent ); print.boldGreenLine( "Report written to #arguments.outputFile#!" ); } - + results.fileContent = trim( results.fileContent ); - + // Default is to template our own output based on a JSON reponse if( RUNNER_OPTIONS.reporter == 'json' && isJSON( results.fileContent ) ) { - + var testData = deserializeJSON( results.fileContent ); - + // If any tests failed or errored. if( testData.totalFail || testData.totalError ) { // Send back failing exit code to shell setExitCode( 1 ); - } - + } + CLIRenderer.render( print, testData, arguments.verbose ?: boxOptions.verbose ?: true ); - + //systemOutput( getINstance( 'formatter' ).formatJSON( testData ) ); - + // For all other reporters, just dump out whatever we got from the server } else { - + results.fileContent = reReplace( results.fileContent, '[\r\n]+', CR, 'all' ); - + // Print accordingly to results if( ( results.responseheader[ "x-testbox-totalFail" ] ?: 0 ) eq 0 AND ( results.responseheader[ "x-testbox-totalError" ] ?: 0 ) eq 0 ){ @@ -160,9 +160,9 @@ component { setExitCode( 1 ); print.boldRed( " " & results.filecontent ); } - + } - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc index 130bd3301..3b85a0a24 100644 --- a/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc +++ b/src/cfml/system/modules_app/testbox-commands/commands/testbox/watch.cfc @@ -4,8 +4,8 @@ * {code} * testbox watch * {code} - * - * In order for this command to work, you need to have started your server and configured the + * + * In order for this command to work, you need to have started your server and configured the * URL to the test runner in your box.json. * * {code} @@ -13,7 +13,7 @@ * server start * testbox watch * {code} - * + * * If you need more control over what tests run and their output, you can set additional options in your box.json * which will be picked up automatically by "testbox run" whe it fires. * @@ -24,7 +24,7 @@ * package set testbox.watchDelay=1000 * package set testbox.watchPaths=/models/**.cfc * {code} - * + * * This command will run in the foreground until you stop it. When you are ready to shut down the watcher, press Ctrl+C. * **/ @@ -35,16 +35,16 @@ component { variables.WATCH_DELAY = 500; variables.PATHS = "**.cfc"; - + /** * @paths Command delimited list of file globbing paths to watch relative to the working directory, defaults to **.cfc * @delay How may milliseconds to wait before polling for changes, defaults to 500 ms **/ function run( - string paths, + string paths, number delay ) { - + // Get testbox options from package descriptor var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox; @@ -56,7 +56,7 @@ component { // should return null if not found return; } - + // Determine watching patterns, either from arguments or boxoptions or defaults var globbingPaths = arguments.paths ?: getOptionsWatchers() ?: variables.PATHS; // handle non numberic config and put a floor of 150ms @@ -64,23 +64,23 @@ component { // Tabula rasa command( 'cls' ).run(); - + // Start watcher watch() .paths( globbingPaths.listToArray() ) .inDirectory( getCWD() ) .withDelay( delayMs ) .onChange( function() { - + // Clear the screen command( 'cls' ) .run(); - + // Run the tests in the target directory command( 'testbox run' ) .inWorkingDirectory( getCWD() ) .run(); - + } ) .start(); } diff --git a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc index c9582b5c1..d8042954b 100644 --- a/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc +++ b/src/cfml/system/modules_app/testbox-commands/models/CLIRenderer.cfc @@ -23,7 +23,7 @@ component { * @verbose Display information about passing and skipped specs */ function render( print, testData, verbose ) { - + var thisColor = getAggregatedColor( testData.totalError, testData.totalFail, 0 ); print .line("TestBox " & ( !isNull( testData.version ) ? "v#testData.version#" : "" ) ) @@ -32,31 +32,31 @@ component { .line( "---------------------------------------------------------------------------------", thisColor ) .line( "| #headerCell(testData.totalPass)# | #headerCell(testData.totalFail)# | #headerCell(testData.totalError)# | #headerCell(testData.totalSkipped)# | #headerCell(testData.totalDuration & ' ms')# | #headerCell(testData.totalBundles)# | #headerCell(testData.totalSuites)# | #headerCell(testData.totalSpecs)# |", thisColor ) .line( "---------------------------------------------------------------------------------", thisColor); - + if ( arrayLen( testData.labels ) ) { print.line("->[Labels Applied: #arrayToList( testData.labels )#]"); } var didPrint = false; for ( thisBundle in testData.bundleStats ) { - - + + if ( ( thisBundle.totalFail + thisBundle.totalError ) == 0 && !verbose) { continue; } - + var thisColor = getAggregatedColor( thisBundle.totalError, thisBundle.totalFail, 0 ); print .line("=================================================================================", thisColor ) .line( "#thisBundle.path# (#thisBundle.totalDuration# ms) [Suites/Specs: #thisBundle.totalSuites#/#thisBundle.totalSpecs#]", thisColor ) .line( "[Passed: #thisBundle.totalPass#] [Failed: #thisBundle.totalFail#] [Errors: #thisBundle.totalError#] [Skipped: #thisBundle.totalSkipped#]", thisColor ) .line( "---------------------------------------------------------------------------------", thisColor ); - + if ( !isSimpleValue( thisBundle.globalException ) ) { - + print.line("GLOBAL BUNDLE EXCEPTION", COLOR.ERROR ) .line( "-> #thisBundle.globalException.type#:#thisBundle.globalException.message#:#thisBundle.globalException.detail#", COLOR.ERROR ) .line( "---------------------------------------------------------------------------------", COLOR.ERROR ); - + // ACF has an array for the stack trace if( isSimpleValue( thisBundle.globalException.stacktrace ) ) { print @@ -66,19 +66,19 @@ component { .line( "---------------------------------------------------------------------------------", COLOR.ERROR ) .line( "END STACKTRACE", COLOR.ERROR ); } - + print.line( "---------------------------------------------------------------------------------", COLOR.ERROR ); } for ( suiteStats in thisBundle.suiteStats ) { didPrint = genSuiteReport( suiteStats, thisBundle, 0, print, verbose ); } } - + // Skip this redundant line if no specs printed above in the previous suite if( didPrint ) { - print.line("---------------------------------------------------------------------------------", thisColor ); + print.line("---------------------------------------------------------------------------------", thisColor ); } - + if( verbose ) { print .text( "Passed", COLOR.PASS ).text( " || " ) @@ -89,20 +89,20 @@ component { } } - + // Recursive Output function genSuiteReport(suiteStats, bundleStats, level="0", print, verbose ) { - + if ( ( arguments.suiteStats.totalFail + arguments.suiteStats.totalError ) == 0 && !verbose) { return false; } var tabs = repeatString( " ", arguments.level ); - + print.line( "#tabs#+#arguments.suiteStats.name# #chr(13)#", getAggregatedColor( arguments.suiteStats.totalError, arguments.suiteStats.totalFail, ( arguments.suiteStats.status == 'skipped' ? 1 : 0 ) ) ); - + var printedAtLeastOneLine = false; for ( local.thisSpec in arguments.suiteStats.specStats ) { - + if ( ListFindNoCase("failed,exception,error", local.thisSpec.status) == 0 && !verbose ) { continue; } @@ -110,9 +110,9 @@ component { printedAtLeastOneLine = true; var thisColor = getAggregatedColor( ( local.thisSpec.status == "error" ? 1 : 0 ), ( local.thisSpec.status == "failed" ? 1 : 0 ), ( local.thisSpec.status == "skipped" ? 1 : 0 ) ); print.line("#repeatString( " ", arguments.level+1 )##local.thisSpec.name# (#local.thisSpec.totalDuration# ms) #chr(13)#", thisColor ); - + if ( local.thisSpec.status == "failed" ) { - print.line("#repeatString( " ", arguments.level+2 )#-> Failure: #local.thisSpec.failMessage##chr(13)#", COLOR.FAIL ); + print.line("#repeatString( " ", arguments.level+2 )#-> Failure: #local.thisSpec.failMessage##chr(13)#", COLOR.FAIL ); } if ( local.thisSpec.status == "error" ) { print.line("#repeatString( " ", arguments.level+2 )#-> Error: #local.thisSpec.error.message##chr(13)#", COLOR.ERROR ); @@ -130,11 +130,11 @@ component { } return printedAtLeastOneLine; } - + private function headerCell( text ) { return Left( arguments.text & RepeatString( " ", HEADER_CELL_CHARS), HEADER_CELL_CHARS); } - + private function getAggregatedColor( errors=0, failures=0, skips=0 ) { if( errors ) { return COLOR.ERROR; diff --git a/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc b/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc index 222f2e62a..fc87c99af 100644 --- a/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc +++ b/src/cfml/system/modules_app/testbox-commands/models/TestingService.cfc @@ -11,19 +11,19 @@ component accessors="true" singleton { // DI property name="packageService" inject="PackageService"; - + /** * Constructor */ function init(){ return this; } - + /** * Gets a TestBox runner URL from box.json with an optional slug to look up. If no slug is passed, the first runner will be used * @directory The directory that is the root of the package * @slug An optional runner slug to look for in the list of runners - */ + */ public function getTestBoxRunner( required string directory, string slug='' ) { // Get box.json, create empty if it doesn't exist var boxJSON = packageService.readPackageDescriptor( arguments.directory ); @@ -44,21 +44,21 @@ component accessors="true" singleton { } // Just get the first one we can find - + // simple runner? if( isSimpleValue( runners ) ){ return runners; } - + // Array of runners? if( isArray( runners ) ) { // get the first definition in the list to use var firstRunner = runners[ 1 ]; return firstRunner[ listFirst( structKeyList( firstRunner ) ) ]; } - + // We failed to find anything return ''; } - -} \ No newline at end of file + +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/runner.cfm b/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/runner.cfm index 0fa70d4d1..a1501ae9a 100644 --- a/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/runner.cfm +++ b/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/runner.cfm @@ -1,4 +1,4 @@ - + diff --git a/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc index 9ca442169..f63d54e5b 100644 --- a/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc +++ b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc @@ -8,4 +8,4 @@ */ component { function configure(){} -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc index cd1e8a65a..81ad8b11a 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc @@ -1,38 +1,38 @@ /** - * + * * Ensure files have a trailing newline to adhere to POSIX standard. Operates on a single file * or multiple files as defined by a file globbing pattern. - * + * * {code:bash} * eol **.cf* * {code} - * + * * To skip the confirmation, use the --force flag. - * + * * {code:bash} * eol models/**.cfc --force * {code} - * + * * Print the file path of each file affected with the --verbose flag. - * + * * {code:bash} * eol includes/*.cfm --verbose * {code} - * + * * Exclude a list a globber patterns - * + * * {code:bash} * eol ** *.png,node_modules/ * {code} - * + * * You can set global default parameters for this command to use like so: - * + * * {code:bash} * config set command.defaults.eol.force=true * config set command.defaults.eol.verbose=true * config set command.defaults.eol.exclude=.git/,*.png * {code} - * + * **/ component aliases="eol" { property name="pathPatternMatcher" inject="provider:pathPatternMatcher@globber"; @@ -101,4 +101,4 @@ component aliases="eol" { return chr( 10 ); } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc index 61399e80a..267fb7a1c 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -1,32 +1,32 @@ /** - * - * Remove those pesky trailing spaces from each line that some editors add. + * + * Remove those pesky trailing spaces from each line that some editors add. * Can be run on a single file or aginst a list of files defined by a file globbing pattern. - * + * * {code:bash} * rts **.cf* * {code} - * + * * Skip the user confirmation with the --force flag. - * + * * {code:bash} * rts models/**.cfc --force * {code} - * + * * Print the file path of each file affected with the --verbose flag. - * + * * {code:bash} * rts includes/*.cfm --verbose * {code} - * + * * Exclude a list a file globbing patterns - * + * * {code:bash} * rts ** *.png,node_modules/ * {code} - * + * * You can set global default parameters for this command to use like so: - * + * * {code:bash} * config set command.defaults.rts.force=true * config set command.defaults.rts.verbose=true @@ -114,4 +114,4 @@ component aliases="rts" { return chr( 10 ); } -} +} \ No newline at end of file diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc index 12e198f7f..9094360cd 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use wirebox create' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc index dce2a8c4e..0f46de0ac 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc @@ -2,9 +2,9 @@ * Description of command **/ component { - + /** - * + * **/ function run( ) { print.line( "Command not implemented!" ); diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc index 43da506ef..675d29a95 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc @@ -1,12 +1,12 @@ component excludeFromHelp=true { - + function run() { - + print.line(); print.yellowLine( 'General help and description of how to use wirebox' ); print.line(); print.line(); - + } } \ No newline at end of file diff --git a/src/cfml/system/services/ArtifactService.cfc b/src/cfml/system/services/ArtifactService.cfc index 7d3457c18..a592fee94 100644 --- a/src/cfml/system/services/ArtifactService.cfc +++ b/src/cfml/system/services/ArtifactService.cfc @@ -6,7 +6,7 @@ * @author Brad Wood, Luis Majano, Denny Valliant * * I handle artifacts, which are basically just a cache of downloaded packages. -* +* * Artifacts are stored in this format: * /packageName/version/packageName.zip * @@ -14,7 +14,7 @@ * */ component accessors="true" singleton { - + // DI property name='artifactDir' inject='artifactDir@constants'; property name='tempDir' inject='tempDir@constants'; @@ -23,21 +23,21 @@ component accessors="true" singleton { property name="semanticVersion" inject="provider:semanticVersion@semver"; // COMMANDBOX-479 property name="configService" inject="ConfigService"; - - + + /** * DI complete */ function onDIComplete() { - + // Create the artifacts directory if it doesn't exist // COMMANDBOX-479 if( !directoryExists( getArtifactsDirectory() ) ) { directoryCreate( getArtifactsDirectory() ); } - + } - + /** * List the packages in the artifacts cache. * @package.hint Supply a package to see only versions of this package @@ -47,7 +47,7 @@ component accessors="true" singleton { var result = {}; // COMMANDBOX-479 var dirList = directoryList( path=getArtifactsDirectory(), recurse=false, listInfo='query', sort='name asc' ); - + for( var dir in dirList ) { if( dir.type == 'dir' && ( !arguments.packageName.len() || arguments.packageName == dir.name ) ) { var verList = directoryList( path=dir.directory & '\' & dir.name, recurse=false, listInfo='query', sort='name asc' ); @@ -65,31 +65,31 @@ component accessors="true" singleton { return result; } - - + + /** * Removes all artifacts from the cache and returns the number of wiped out directories - */ + */ numeric function cleanArtifacts() { // COMMANDBOX-479 var qryDir = directoryList( path=getArtifactsDirectory(), recurse=false, listInfo='query' ); var numRemoved = 0; - + for( var path in qryDir ) { if( path.type == 'Dir' ) { numRemoved++; - directoryDelete( path.directory & '/' & path.name, true ); + directoryDelete( path.directory & '/' & path.name, true ); } } - + return numRemoved; } - + /** * Removes an artifact or an artifact package, true if removed * @packageName.hint The package name to look for * @version.hint The version to look for - */ + */ boolean function removeArtifact( required packageName, version="" ) { if( packageExists( arguments.packageName, arguments.version ) ){ directoryDelete( getPackagePath( arguments.packageName, arguments.version ), true ); @@ -103,16 +103,16 @@ component accessors="true" singleton { * Returns true if a package exists in the artifact cache, false if not. * @packageName.hint The package name to look for * @version.hint The version to look for - */ + */ boolean function packageExists( required packageName, version="" ){ - return directoryExists( getPackagePath( arguments.packageName, arguments.version ) ); + return directoryExists( getPackagePath( arguments.packageName, arguments.version ) ); } /** * Returns the filesystem path of the package path * @packageName.hint The package name to look for * @version.hint The version to look for - */ + */ function getPackagePath( required packageName, version="" ){ // This will likely change, so I'm only going to put the code here. // COMMANDBOX-479 @@ -122,13 +122,13 @@ component accessors="true" singleton { path &= "/" & arguments.version; } return path; - } - + } + /** * Returns true if a package exists in the artifact cache, false if not. * @packageName.hint The package name to look for * @version.hint The version of the package to look for - */ + */ boolean function artifactExists( required packageName, required version ){ return fileExists( getArtifactPath( argumentCollection = arguments ) ); } @@ -137,13 +137,13 @@ component accessors="true" singleton { * Returns the filesystem path of the artifact zip file * @packageName.hint The package name to look for * @version.hint The version of the package to look for - */ + */ function getArtifactPath( required packageName, required version ) { // I'm using the package name as the zip file for lack of anything better even though it's redundant with the first folder return getPackagePath( arguments.packageName, arguments.version ) & '/' & arguments.packageName & '.zip'; - } - + } + /** * Store a package in the artifact cache. * This expects that the package is already downloaded and stored somewhere on the local filesystem. @@ -154,34 +154,34 @@ component accessors="true" singleton { * @packagePath.hint A file path to a local zip file that contains the package */ ArtifactService function createArtifact( required packageName, required version, required packagePath ) { - + // If we were given a folder, defer to another method if( directoryExists( arguments.packagePath ) ) { return createArtifactFromFolder( arguments.packageName, arguments.version, arguments.packagePath ); } - + // Validate the package path if( !fileExists( arguments.packagePath ) ) { throw( 'Cannot create artifact [#arguments.packageName#], the file doesn''t exist', arguments.packagePath ); } - + // Validate the package is a zip if( right( arguments.packagePath, 4 ) != '.zip' ) { throw( 'Cannot create artifact [#arguments.packageName#], the file isn''t a zip', arguments.packagePath ); } - + // Where will this artifact live? var thisArtifactPath = getArtifactPath( arguments.packageName, arguments.version ); - + // Create dir if it doesn't exist directorycreate( getDirectoryFromPath( thisArtifactPath ), true, true ); - + // Here's your new home fileCopy( arguments.packagePath, thisArtifactPath ); return this; - } - + } + /** * Store a package in the artifact cache. * This expects that the package is already downloaded and stored somewhere on the local filesystem. @@ -191,48 +191,48 @@ component accessors="true" singleton { * @packageFolder.hint A file path to a local folder that contains the package */ private function createArtifactFromFolder( required packageName, required version, required packageFolder ) { - + // Where will this artifact live? var thisArtifactPath = getArtifactPath( arguments.packageName, arguments.version ); - + // Create dir if it doesn't exist directorycreate( getDirectoryFromPath( thisArtifactPath ), true, true ); - - zip action='zip' source=arguments.packageFolder file=thisArtifactPath; + + zip action='zip' source=arguments.packageFolder file=thisArtifactPath; return this; - } - + } + /** - * Returns the descriptor file (box.json) for a packge parsed as a struct. - * This data will be merged with a default document to guaruntee existence of standard variables and - * reduce the need for "exist" checks in our code + * Returns the descriptor file (box.json) for a packge parsed as a struct. + * This data will be merged with a default document to guaruntee existence of standard variables and + * reduce the need for "exist" checks in our code * @packageName.hint The package name to look for * @version.hint The version of the package to look for */ public struct function getArtifactDescriptor( required packageName, required version ) { var thisArtifactPath = getArtifactPath( arguments.packageName, arguments.version ); var boxJSONPath = 'zip://' & thisArtifactPath & '!box.json'; - + // If the packge has a box.json in the root... if( fileExists( boxJSONPath ) ) { - + // ...Read it. var boxJSON = fileRead( boxJSONPath ); - + // Validate the file is valid JSOn if( isJSON( boxJSON ) ) { // Merge this JSON with defaults return packageService.newPackageDescriptor( deserializeJSON( boxJSON ) ); } - + } - + // Just return defaults return packageService.newPackageDescriptor(); - - } - + + } + /** * Figures out the closest satisfying version that's available for a package in the local artifacts cache. @@ -241,32 +241,32 @@ component accessors="true" singleton { */ function findSatisfyingVersion( required string slug, required string version ) { var artifacts = listArtifacts( slug ); - + // Check to see if we even have any versions for this artifact if( !artifacts.keyExists( slug ) ) { return ''; } - + // Get the locally-stored versions var arrVersions = artifacts[ slug ]; // Sort them arrVersions.sort( function( a, b ) { return semanticVersion.compare( b, a ) } ); - + var found = false; for( var thisVersion in arrVersions ) { if( semanticVersion.satisfies( thisVersion, arguments.version ) ) { return thisVersion; } } - + // If we requested stable and all releases are pre-release, just grab the latest if( arguments.version == 'stable' && arrayLen( arrVersions ) ) { - return arrVersions[ 1 ]; + return arrVersions[ 1 ]; } else { return ''; } } - + // COMMANDBOX-479 string function getArtifactsDirectory() { return configService.getSetting( 'artifactsDirectory', variables.artifactDir ); diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 8f9663866..daa58d23f 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -25,7 +25,7 @@ component accessors="true" singleton { property name='stringDistance' inject='provider:StringSimilarity@string-similarity'; property name='SystemSettings' inject='SystemSettings'; property name='ConfigService' inject='ConfigService'; - + property name='configured' default="false" type="boolean"; // TODO: Convert these to properties @@ -169,12 +169,12 @@ component accessors="true" singleton { // default behavior is to keep trucking var previousCommandSeparator = ';'; var lastCommandErrored = false; - + if( structKeyExists( arguments, 'piped' ) ) { var result = arguments.piped; previousCommandSeparator = '|'; } - + // If piping commands, each one will be an item in the chain. // i.e. forgebox show | grep | more // Would result in three separate, chained commands. @@ -267,7 +267,7 @@ component accessors="true" singleton { mergeFlagParameters( parameterInfo ); // Add in defaults - addDefaultParameters( commandInfo.commandString, parameterInfo ); + addDefaultParameters( commandInfo.commandString, parameterInfo ); // Make sure we have all required params. parameterInfo.namedParameters = ensureRequiredParams( parameterInfo.namedParameters, commandParams ); @@ -304,7 +304,7 @@ component accessors="true" singleton { // Successful command execution resets exit code to 0. Set this prior to running the command since the command // may explicitly set the exit code to 1 but not call the error() method. shell.setExitCode( 0 ); - + // Run the command try { var result = commandInfo.commandReference.CFC.run( argumentCollection = parameterInfo.namedParameters ); @@ -449,7 +449,7 @@ component accessors="true" singleton { var defaultValue = ''; if( settingName.listLen( ':' ) ) { defaultValue = settingName.listRest( ':' ); - settingName = settingName.listFirst( ':' ); + settingName = settingName.listFirst( ':' ); } var result = systemSettings.getSystemSetting( settingName, defaultValue ); @@ -461,7 +461,7 @@ component accessors="true" singleton { } } } - + /** * Look through named parameters and combine any ones with a colon based on matching prefixes. */ @@ -640,13 +640,13 @@ component accessors="true" singleton { return commandChain; } - + /** * Takes a single array of tokens and breaks it into a chain of commands (array of arrays) - * i.e. foo bar | baz turns into [ [ 'foo', 'bar' ], [ '|' ], [ 'baz' ] ] + * i.e. foo bar | baz turns into [ [ 'foo', 'bar' ], [ '|' ], [ 'baz' ] ] */ private function breakTokensIntoChain( required array tokens ) { - + var commandsToResolve = [[]]; var expandedCommandsToResolve = []; @@ -668,7 +668,7 @@ component accessors="true" singleton { commandsToResolve.append( [ '&&' ] ); commandsToResolve.append( [] ); } else if( token == '||' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ - // Add a new command + // Add a new command commandsToResolve.append( [ '||' ] ); commandsToResolve.append( [] ); } else if( token == '>' && commandsToResolve[ commandsToResolve.len() ].len() && i < tokens.len() ){ @@ -684,27 +684,27 @@ component accessors="true" singleton { commandsToResolve[ commandsToResolve.len() ].append( token ); } } - + // Expand aliases for( commandTokens in commandsToResolve ) { var originalLine = commandTokens.toList( ' ' ); var aliases = configService.getSetting( 'command.aliases', {} ); var matchingAlias = ''; - + for( alias in aliases ) { if( lcase( originalLine ).startsWith( lcase( alias ) ) ) { matchingAlias = alias; break; } } - + // If the exact tokens in this command match an alias, swap it out. if( matchingAlias.len() ) { expandedCommandsToResolve.append( // Recursivley dig down. This allows aliases to alias other alises breakTokensIntoChain( - // Re-tokenize the new strin - parser.tokenizeInput( + // Re-tokenize the new strin + parser.tokenizeInput( // Expand the alias with the string it aliases replaceNoCase( originalLine, matchingAlias, aliases[ matchingAlias ], 'once' ) ) @@ -712,11 +712,11 @@ component accessors="true" singleton { true ); // Otherwise just use them as is. } else { - expandedCommandsToResolve.append( commandTokens ); + expandedCommandsToResolve.append( commandTokens ); } - + } - + return expandedCommandsToResolve; } @@ -955,17 +955,17 @@ component accessors="true" singleton { private function createGlobs( parameterInfo, commandParams ) { // Loop over user-supplied params for( var paramName in parameterInfo.namedParameters ) { - + // If this is an expected param functionIndex = commandParams.find( function( i ) { return i.name == paramName; } ); - + if( functionIndex ) { var paramData = commandParams[ functionIndex ]; // And it's of type Globber if( ( paramData.type ?: 'any' ) == 'Globber' ) { - + // Overwrite it with an actual Globber instance seeded with the original canonical path as the pattern. var originalPath = parameterInfo.namedParameters[ paramName ].replace( '\', '/', 'all' ); var newPath = fileSystemUtil.resolvePath( originalPath ).replace( '\', '/', 'all' ); @@ -1021,7 +1021,7 @@ component accessors="true" singleton { return results; } - + /** * Merge flags into named parameters **/ @@ -1029,7 +1029,7 @@ component accessors="true" singleton { // Add flags into named params arguments.parameterInfo.namedParameters.append( arguments.parameterInfo.flags ); } - + /** * Merge in parameter defaults **/ @@ -1037,7 +1037,7 @@ component accessors="true" singleton { // Get defaults for this command, an empty struct if nothing. var defaults = configService.getSetting( 'command.defaults["#commandString#"]', {} ); var params = parameterInfo.namedParameters; - + // For each default defaults.each( function( k,v ) { // If it's not already set @@ -1046,7 +1046,7 @@ component accessors="true" singleton { params[ k ] = v; } } ); - + } } \ No newline at end of file diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index 45dd0af31..b22bdb3e9 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -21,7 +21,7 @@ component accessors="true" singleton { property name='ModuleService' inject='ModuleService'; property name='JSONService' inject='JSONService'; property name='ServerService' inject='ServerService'; - + /** * Constructor */ @@ -58,42 +58,42 @@ component accessors="true" singleton { 'command.defaults', 'command.aliases' ]); - + setConfigFilePath( '/commandbox-home/CommandBox.json' ); - + // Create the config file if neccessary if( !fileExists( getConfigFilePath() ) ) { fileWrite( getConfigFilePath(), '{}' ); } - + loadConfig(); - + return this; } - + function onDIComplete() { var serverProps = serverService.completeProperty( 'fake', true ); for( var prop in serverProps ) { variables.possibleConfigSettings.append( 'server.defaults.#prop#' ); } } - + function setConfigSettings( required struct configSettings ) { variables.configSettings = arguments.configSettings; saveConfig(); } - + /** * Get a setting from a configuration structure * @name.hint The name of the setting. Allows for "deep" struct/array names. * @defaultValue.hint The default value to use if setting does not exist */ function getSetting( required name, defaultValue ){ - + arguments.JSON = getConfigSettings(); arguments.property = arguments.name; - - return JSONService.show( argumentCollection = arguments ); + + return JSONService.show( argumentCollection = arguments ); } /** @@ -103,7 +103,7 @@ component accessors="true" singleton { boolean function settingExists( required name ){ arguments.JSON = getConfigSettings(); arguments.property = arguments.name; - + return JSONService.check( argumentCollection = arguments ); } @@ -114,12 +114,12 @@ component accessors="true" singleton { * @thisAppend.hint Append an array or struct to existing */ function setSetting( required name, required value, boolean thisAppend=false ){ - + arguments.JSON = getConfigSettings(); arguments.properties[ name ] = arguments.value; - + JSONService.set( argumentCollection = arguments ); - + saveConfig(); return this; } @@ -129,12 +129,12 @@ component accessors="true" singleton { * @name.hint The name of the setting. Allows for "deep" struct/array names. */ function removeSetting( required name ){ - + arguments.JSON = getConfigSettings(); arguments.property = arguments.name; - + JSONService.clear( argumentCollection = arguments ); - + saveConfig(); return this; } @@ -144,7 +144,7 @@ component accessors="true" singleton { */ function loadConfig(){ // Don't call the setter here since we don't need to trigger a save. - variables.configSettings = deserializeJSON( fileRead( getConfigFilePath() ) ); + variables.configSettings = deserializeJSON( fileRead( getConfigFilePath() ) ); } /** @@ -152,21 +152,21 @@ component accessors="true" singleton { */ function saveConfig(){ fileWrite( getConfigFilePath(), formatterUtil.formatJSON( serializeJSON( getConfigSettings() ) ) ); - + // Update ModuleService ModuleService.overrideAllConfigSettings(); } - + /** * Dynamic completion for property name based on contents of commandbox.json * @all Pass false to ONLY suggest existing setting names. True will suggest all possible settings. * @asSet Pass true to add = to the end of the options - */ + */ function completeProperty( all=false, asSet=false ) { // Get all config settings currently set var props = JSONService.addProp( [], '', '', getConfigSettings() ); - + // If we want all possible options... if( arguments.all ) { // ... Then add them in @@ -175,6 +175,6 @@ component accessors="true" singleton { if( asSet ) { props = props.map( function( i ){ return i &= '='; } ); } - return props; - } + return props; + } } \ No newline at end of file diff --git a/src/cfml/system/services/InterceptorService.cfc b/src/cfml/system/services/InterceptorService.cfc index a1a51cdd3..9f88a8211 100644 --- a/src/cfml/system/services/InterceptorService.cfc +++ b/src/cfml/system/services/InterceptorService.cfc @@ -12,17 +12,17 @@ component accessors=true singleton { property name='EventPoolManager'; property name='InterceptionPoints'; property name='configured' type="boolean" default="false"; - + // DI property name='log' inject='logbox:logger:{this}'; /** * @shell.inject shell - + */ InterceptorService function init( required shell ) { setConfigured( false ); - + setShell( arguments.shell ); setInterceptionPoints( [ @@ -37,9 +37,9 @@ component accessors=true singleton { // Error handling 'onException', // Package lifecycle - 'preInstall','onInstall','postInstall','preUninstall','postUninstall','preVersion','postVersion','prePublish','postPublish','preUnpublish','postUnpublish','onRelease' + 'preInstall','onInstall','postInstall','preUninstall','postUninstall','preVersion','postVersion','prePublish','postPublish','preUnpublish','postUnpublish','onRelease' ] ); - + return this; } @@ -48,13 +48,13 @@ component accessors=true singleton { setEventPoolManager( getShell().getWireBox().getEventManager() ); appendInterceptionPoints( getInterceptionPoints().toList() ); setConfigured( true ); - return this; + return this; } - + function announceInterception( required string state, struct interceptData={} ) { getEventPoolManager().processState( state, interceptData ); } - + /** * @interceptor.hint The qualified class of the interceptor to register or an already instantiated object as an interceptor. * @interceptorProperties.hint The structure of properties to register this interceptor with. @@ -68,7 +68,7 @@ component accessors=true singleton { string customPoints='', string interceptorName='' ) { - + // determine registration names if( !len( arguments.interceptorName ) ) { if( isSimpleValue( arguments.interceptor ) ){ @@ -133,7 +133,7 @@ component accessors=true singleton { return oInterceptor; } - + /** * Verifies the setup for interceptor classes is online */ @@ -149,9 +149,9 @@ component accessors=true singleton { .setAutowire( false ); } } - + /** - * Get an interceptor according to its name from a state. + * Get an interceptor according to its name from a state. */ function getInterceptor( required string interceptorName ) { return getEventPoolManager().getObject( arguments.interceptorName ); diff --git a/src/cfml/system/services/JSONService.cfc b/src/cfml/system/services/JSONService.cfc index a1a4f4c82..f36ff27f2 100644 --- a/src/cfml/system/services/JSONService.cfc +++ b/src/cfml/system/services/JSONService.cfc @@ -11,31 +11,31 @@ component accessors="true" singleton { // DI property name="logger" inject="logbox:logger:{this}"; - + /** * Constructor */ function init(){ return this; } - + /** * I check for the existance of a property */ boolean function check( required any JSON, required string property ){ - + var fullPropertyName = 'arguments.JSON' & toBracketNotation( arguments.property ); - + return isDefined( fullPropertyName ); } - + /** * I get a property from a deserialized JSON object and return it */ function show( required any JSON, required string property, defaultValue ){ - + var fullPropertyName = 'arguments.JSON' & toBracketNotation( arguments.property ); - + if( !isDefined( fullPropertyName ) ) { if( structKeyExists( arguments, 'defaultValue' ) ) { return arguments.defaultValue; @@ -43,7 +43,7 @@ component accessors="true" singleton { throw( message='Property [#arguments.property#] doesn''t exist.', type="JSONException"); } } - + return evaluate( fullPropertyName ); } @@ -53,11 +53,11 @@ component accessors="true" singleton { */ function set( required any JSON, required struct properties, required boolean thisAppend ){ var results = []; - + for( var prop in arguments.properties ) { - + var fullPropertyName = 'arguments.JSON' & toBracketNotation( prop ); - + var propertyValue = arguments.properties[ prop ]; if( isJSON( propertyValue ) ) { // We're trying to append and the target property exists @@ -79,24 +79,24 @@ component accessors="true" singleton { } } // structs - } else { - targetProperty.append( complexValue, true ); + } else { + targetProperty.append( complexValue, true ); } results.append( '#propertyValue# appended to #prop#' ); continue; } - + } // If any of the ifs above fail, we'll fall back through to this - + // Double check if value is really JSON due to Lucee bug if( listFind( '",{,[', left( propertyValue, 1 ) ) ) { evaluate( '#fullPropertyName# = deserializeJSON( propertyValue )' ); } else { evaluate( '#fullPropertyName# = propertyValue' ); - } + } } else { - evaluate( '#fullPropertyName# = propertyValue' ); + evaluate( '#fullPropertyName# = propertyValue' ); } results.append( 'Set #prop# = #propertyValue#' ); } @@ -108,19 +108,19 @@ component accessors="true" singleton { * I clear a property from a deserialized JSON object. */ function clear( required any JSON, required string property ){ - + // See if this string ends with array brackets containing a number greater than 1. Ex: test[3] var search = reFind( "\[\s*([1-9][0-9]*)\s*\]$", property, 1, true ); - + // Deal with array index if( search.pos[1] ) { // Index to remove var arrayIndex = mid( property, search.pos[2], search.len[2] ); // Path to the array var theArray = left( property, search.pos[1]-1 ); - + // Verify the full path exists (including the array index) - + var fullPropertyName = 'arguments.JSON' & toBracketNotation( arguments.property ); if( !isDefined( fullPropertyName ) ) { throw( message='#arguments.property# does not exist.', type="JSONException"); @@ -130,23 +130,23 @@ component accessors="true" singleton { var propertyValue = evaluate( fullPropertyName ); // Remove the index propertyValue.deleteAt( arrayIndex ); - + // Else see if it's a dot-delimted struct path. Ex foo.bar } else if( listLen( property, '.' ) >= 2 ) { // Name of last key to remove var last = listLast( property, '.' ); // path to containing struct var everythingBut = listDeleteAt( property, listLen( property, '.' ), '.' ); - + // Confirm it exists var fullPropertyName = 'arguments.JSON' & toBracketNotation( everythingBut ); - + if( !isDefined( fullPropertyName ) ) { throw( message='#arguments.property# does not exist.', type="JSONException"); } // Get a refernce to the containing struct var propertyValue = evaluate( fullPropertyName ); - // Remove the key + // Remove the key structDelete( propertyValue, last ); // Else just a simple propery name } else { @@ -157,7 +157,7 @@ component accessors="true" singleton { // Remove it structDelete( JSON, arguments.property ); } - + } @@ -170,7 +170,7 @@ component accessors="true" singleton { if( item.startsWith( '[' ) ) { fullPropertyName &= item; } else { - fullPropertyName &= '[ "#item#" ]'; + fullPropertyName &= '[ "#item#" ]'; } } return fullPropertyName; @@ -179,7 +179,7 @@ component accessors="true" singleton { // Recursive function to crawl struct and create a string that represents each property. function addProp( props, prop, safeProp, targetStruct ) { var propValue = ( len( prop ) ? evaluate( 'targetStruct#safeProp#' ) : targetStruct ); - + if( isStruct( propValue ) ) { // Add all of this struct's keys for( var thisProp in propValue ) { @@ -187,9 +187,9 @@ component accessors="true" singleton { var newSafeProp = "#safeProp#['#thisProp#']"; props.append( newProp ); props = addProp( props, newProp, newSafeProp, targetStruct ); - } + } } - + if( isArray( propValue ) ) { // Add all of this array's indexes var i = 0; @@ -200,8 +200,8 @@ component accessors="true" singleton { props = addProp( props, newProp, newSafeProp, targetStruct ); } } - + return props; } - + } \ No newline at end of file diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index 8d7e49f57..af1be7ad4 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -828,4 +828,4 @@
- + \ No newline at end of file diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index fb5a8da9a..1e581bf2d 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -23,38 +23,38 @@ component accessors="true" singleton { property name='interceptorService' inject='interceptorService'; property name='JSONService' inject='JSONService'; property name='systemSettings' inject='SystemSettings'; - + /** * Constructor */ function init(){ return this; } - + /** * Checks to see if a box.json exists in a given directory * @directory The directory to examine - */ + */ public function isPackage( required string directory ) { // If the packge has a box.json in the root... return fileExists( getDescriptorPath( arguments.directory ) ); } - + /** * Returns the path to the package descriptor * @directory The directory that is the root of the package - */ + */ public function getDescriptorPath( required string directory ) { return directory & '/box.json'; } - + /** * Installs a package and its dependencies, obeying ignors in the box.json file. Returns a struct containing a "copied" array * and an "ignored" array containing the relative paths inside the package that were copied and ignored. - * + * * @slug.ID Identifier of the packge to install. If no ID is passed, all dependencies in the CDW will be installed. * @slug.optionsUDF slugComplete - * @directory The directory to install in. This will override the packages's box.json install dir if provided. + * @directory The directory to install in. This will override the packages's box.json install dir if provided. * @save Save the installed package as a dependancy in box.json (if it exists) * @saveDev Save the installed package as a dev dependancy in box.json (if it exists) * @production When calling this command with no slug to install all dependencies, set this to true to ignore devDependencies. @@ -62,7 +62,7 @@ component accessors="true" singleton { * @verbose If set, it will produce much more verbose information about the package installation * @force When set to true, it will force dependencies to be installed whether they already exist or not * @packagePathRequestingInstallation If installing smart dependencies packages (like ColdBox modules) that are capable of being nested, this is our current level - * + * * @returns True if no errors encountered, false if things went boom. **/ boolean function installPackage( @@ -76,43 +76,43 @@ component accessors="true" singleton { boolean force=false, string packagePathRequestingInstallation = arguments.currentWorkingDirectory ){ - + interceptorService.announceInterception( 'preInstall', { installArgs=arguments, packagePathRequestingInstallation=packagePathRequestingInstallation } ); - + // If there is a package to install, install it if( len( arguments.ID ) ) { - + // By default, a specific package install doesn't include dev dependencies arguments.production = arguments.production ?: true; - + // Verbose info if( arguments.verbose ){ consoleLogger.debug( "Save:#arguments.save# SaveDev:#arguments.saveDev# Production:#arguments.production# Directory:#arguments.directory#" ); } - + try { var endpointData = endpointService.resolveEndpoint( arguments.ID, arguments.currentWorkingDirectory ); } catch( EndpointNotFound var e ) { consoleLogger.error( e.message ); return false; } - + consoleLogger.info( '.'); consoleLogger.info( 'Installing package [#endpointData.ID#]' ); - + try { - var tmpPath = endpointData.endpoint.resolvePackage( endpointData.package, arguments.verbose ); - - // endpointException exception type is used when the endpoint has an issue that needs displayed, - // but I don't want to "blow up" the console with a full error. + var tmpPath = endpointData.endpoint.resolvePackage( endpointData.package, arguments.verbose ); + + // endpointException exception type is used when the endpoint has an issue that needs displayed, + // but I don't want to "blow up" the console with a full error. } catch( endpointException var e ) { consoleLogger.error( e.message & ' ' & e.detail ); - return false; + return false; } - + // Support box.json in the root OR in a subfolder (NPM-style!) tmpPath = findPackageRoot( tmpPath ); - + // The code below expects these variables if( isPackage( tmpPath ) ) { var boxJSON = readPackageDescriptor( tmpPath ); @@ -126,8 +126,8 @@ component accessors="true" singleton { var packageName = endpointData.endpoint.getDefaultName( endpointData.package ); var version = '1.0.0'; } - - + + /******************************************************************************************************************/ // Old Modules Build Check: If the zip file has a directory named after the package, that's our actual package root. // Remove once build process in ForgeBox and ContentBox are updated @@ -139,12 +139,12 @@ component accessors="true" singleton { if( len( packageDirectory ) ) { tmpName = packageDirectory; } - } + } var innerTmpPath = '#tmpPath#/#tmpName#'; if( directoryExists( innerTmpPath ) ) { // Move the box.json if it exists into the inner folder var fromBoxJSONPath = '#tmpPath#/box.json'; - var toBoxJSONPath = '#innerTmpPath#/box.json'; + var toBoxJSONPath = '#innerTmpPath#/box.json'; if( fileExists( fromBoxJSONPath ) ) { fileMove( fromBoxJSONPath, toBoxJSONPath ); } @@ -152,39 +152,39 @@ component accessors="true" singleton { tmpPath = innerTmpPath; } /******************************************************************************************************************/ - + // Now that we have resolved the directory where our package lives, read the box.json out of it. var artifactDescriptor = readPackageDescriptor( tmpPath ); var ignorePatterns = ( isArray( artifactDescriptor.ignore ) ? artifactDescriptor.ignore : [] ); - - + + // Assert: At this point we know what we're installing and we've acquired it, but we don't know where it will install to yet. - + // Determine if a satisfying version of this package is already installed here or at a higher level. if so, skip it. - // Modules are the only kind of packages that can be nested in a hierarchy, so the check only applies here. + // Modules are the only kind of packages that can be nested in a hierarchy, so the check only applies here. // We're also going to assume that they are in a "modules" folder. // This check also only applies if we're at least one level deep into modules. if( isPackageModule( packageType ) && currentWorkingDirectory != packagePathRequestingInstallation) { - + // We'll update this variable as we climb back up the directory structure var movingTarget = packagePathRequestingInstallation; // match "/modules/{myPackage}" at the end of a path var regex = '[/\\]modules[/\\][^/\\]*$'; - + // Can we keep backing up? while( reFindNoCase( regex, movingTarget ) ) { - + // Back out of this folder - movingTarget = reReplaceNoCase( movingTarget, regex, '' ); - + movingTarget = reReplaceNoCase( movingTarget, regex, '' ); + // If we didn't reach a package, I'm not sure what happened, but we can't really continue if( !isPackage( movingTarget ) ) { break; } - + // What does this package need installed? targetBoxJSON = readPackageDescriptor( movingTarget ); - + // This ancestor package has a candidate installed that might satisfy our dependency if( structKeyExists( targetBoxJSON.installPaths, packageName ) ) { var candidateInstallPath = fileSystemUtil.resolvePath( targetBoxJSON.installPaths[ packageName ], movingTarget ); @@ -197,60 +197,60 @@ component accessors="true" singleton { } } } - + // If we've reached the root dir, just quit if( movingTarget == currentWorkingDirectory) { break; } - + } - + } - + var installDirectory = ''; - + // If the user gave us a directory, use it above all else if( structKeyExists( arguments, 'directory' ) ) { installDirectory = arguments.directory; - + // If this is an initial install (not a dependency) into a folder somehwere inside the CommandBox home, // make sure we save correctly to CommandBox's user module box.json. var commandBoxCFMLHome = expandPath( '/commandbox' ).replace( '\', '/', 'all' ); installDirectory = installDirectory.replace( '\', '/', 'all' ); - + // If we're already in the CommandBox (a submodule of a commandbox module, most likely) if( installDirectory contains commandBoxCFMLHome ) { // Override the install directories to the CommandBox CFML root arguments.currentWorkingDirectory = installDirectory.listDeleteAt( installDirectory.listLen( '/\' ), '/\' ); - arguments.packagePathRequestingInstallation = arguments.currentWorkingDirectory; + arguments.packagePathRequestingInstallation = arguments.currentWorkingDirectory; } - + } - + // Next, see if the containing project has an install path configured for this dependency already. var containerBoxJSON = readPackageDescriptor( arguments.packagePathRequestingInstallation ); if( !len( installDirectory ) && structKeyExists( containerBoxJSON.installPaths, packageName ) ) { // Get the resolved installation path for this package installDirectory = fileSystemUtil.resolvePath( containerBoxJSON.installPaths[ packageName ], arguments.packagePathRequestingInstallation ); - + // Back up to the "container" folder. The packge directory will be added back below - installDirectory = listDeleteAt( installDirectory, listLen( installDirectory, '/\' ), '/\' ); + installDirectory = listDeleteAt( installDirectory, listLen( installDirectory, '/\' ), '/\' ); } - + // Else, use directory in the target package's box.json if it exists if( !len( installDirectory ) && len( artifactDescriptor.directory ) ) { // Strip any leading slashes off of the install directory if( artifactDescriptor.directory.startsWith( '/' ) || artifactDescriptor.directory.startsWith( '\' ) ) { // Make sure it's not just a single slash if( artifactDescriptor.directory.len() > 2 ) { - artifactDescriptor.directory = right( artifactDescriptor.directory, len( artifactDescriptor.directory ) - 1 ); + artifactDescriptor.directory = right( artifactDescriptor.directory, len( artifactDescriptor.directory ) - 1 ); } else { artifactDescriptor.directory = ''; } } - installDirectory = arguments.currentWorkingDirectory & '/' & artifactDescriptor.directory; + installDirectory = arguments.currentWorkingDirectory & '/' & artifactDescriptor.directory; } - + // Gather all the interesting things this interceptor might need to know. var interceptData = { installArgs = arguments, @@ -267,7 +267,7 @@ component accessors="true" singleton { installDirectory = interceptData.installDirectory; ignorePatterns = interceptData.ignorePatterns; tmpPath = interceptData.artifactPath; - + // Else, use package type convention if( !len( installDirectory ) && len( packageType ) ) { // If this is a CommandBox command @@ -298,23 +298,23 @@ component accessors="true" singleton { installDirectory = arguments.packagePathRequestingInstallation & '/modules/contentbox/themes'; // ContentBox Modules } else if( packageType == 'contentbox-modules' ) { - installDirectory = arguments.packagePathRequestingInstallation & '/modules/contentbox/modules_user'; + installDirectory = arguments.packagePathRequestingInstallation & '/modules/contentbox/modules_user'; // CommandBox Modules } else if( packageType == 'commandbox-modules' ) { var commandBoxCFMLHome = expandPath( '/commandbox' ).replace( '\', '/', 'all' ); arguments.packagePathRequestingInstallation = arguments.packagePathRequestingInstallation.replace( '\', '/', 'all' ); - + // If we're already in the CommandBox (a submodule of a commandbox module, most likely) if( arguments.packagePathRequestingInstallation contains commandBoxCFMLHome ) { // Then just nest as normal. - installDirectory = arguments.packagePathRequestingInstallation & '/modules'; + installDirectory = arguments.packagePathRequestingInstallation & '/modules'; } else { // Override the install directories to the CommandBox CFML root arguments.currentWorkingDirectory = commandBoxCFMLHome; arguments.packagePathRequestingInstallation = commandBoxCFMLHome; - installDirectory = expandPath( '/commandbox/modules' ); + installDirectory = expandPath( '/commandbox/modules' ); } - + // Flag the shell to reload after this command is finished. consoleLogger.warn( "Shell will be reloaded after installation." ); shell.reload( false ); @@ -337,19 +337,19 @@ component accessors="true" singleton { installDirectory = arguments.packagePathRequestingInstallation & '/lib'; } } - + // I give up, just stick it in the CWD if( !len( installDirectory ) ) { installDirectory = arguments.currentWorkingDirectory; } - + // Default directory to package name var packageDirectory = packageName; // Override package directory in descriptor? if( len( artifactDescriptor.packageDirectory ) ) { packageDirectory = artifactDescriptor.packageDirectory; } - + // Some packages may just want to be dumped in their destination without being contained in a subfolder if( artifactDescriptor.createPackageDirectory ) { installDirectory &= '/#packageDirectory#'; @@ -357,37 +357,37 @@ component accessors="true" singleton { // If the directory wasn't already a package, still save so our box.json gets install paths added } else if( isPackage( installDirectory ) ) { ignorePatterns.append( '/box.json' ); - } - + } + // Assert: At this point, all paths are finalized and we are ready to install. - + // Should we save this as a dependency. Save the install even though the package may already be there if( ( arguments.save || arguments.saveDev ) ) { // Add it! addDependency( packagePathRequestingInstallation, packageName, version, installDirectory, artifactDescriptor.createPackageDirectory, arguments.saveDev, endpointData ); // Tell the user... consoleLogger.info( "#packagePathRequestingInstallation#/box.json updated with #( arguments.saveDev ? 'dev ': '' )#dependency." ); - } - + } + // Check to see if package has already been installed. Skip unless forced. // This check can only be performed for packages that get installed in their own directory. if ( artifactDescriptor.createPackageDirectory && directoryExists( installDirectory ) && !arguments.force ){ - + // Do an additional check and make sure the currently installed version is older than what's being requested. // If there's a new version, install it anyway. var alreadyInstalledBoxJSON = readPackageDescriptor( installDirectory ); if( isPackage( installDirectory ) && semanticVersion.isNew( alreadyInstalledBoxJSON.version, version ) ) { consoleLogger.info( "Package already installed but its version [#alreadyInstalledBoxJSON.version#] is older than the new version being installed [#version#]. Forcing a reinstall." ); - } else { + } else { // cleanup tmp if( endpointData.endpointName != 'folder' ) { - directoryDelete( tmpPath, true ); + directoryDelete( tmpPath, true ); } consoleLogger.warn( "The package #packageName# is already installed at #installDirectory#. Skipping installation. Use --force option to force install." ); return true; - } + } } - + // Create installation directory if neccesary if( !directoryExists( installDirectory ) ) { directoryCreate( installDirectory ); @@ -400,7 +400,7 @@ component accessors="true" singleton { // This will normalize the slashes to match tmpPath = fileSystemUtil.resolvePath( tmpPath ); - + // Copy Assets now to destination directoryCopy( tmpPath, installDirectory, true, function( path ){ // This will normalize the slashes to match @@ -422,55 +422,55 @@ component accessors="true" singleton { return true; } }); - - // Catch this to gracefully handle where the OS or another program + + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { // cleanup unzip if( endpointData.endpointName != 'folder' ) { - directoryDelete( tmpPath, true ); - } + directoryDelete( tmpPath, true ); + } } catch( any e ) { consoleLogger.error( '#e.message##CR#The folder is possibly locked by another program.' ); logger.error( '#e.message# #e.detail#' , e.stackTrace ); } - - + + // Summary output - consoleLogger.info( "Installing to: #installDirectory#" ); + consoleLogger.info( "Installing to: #installDirectory#" ); consoleLogger.debug( "-> #results.copied.len()# File(s) Installed" ); - + // Verbose info if( arguments.verbose ){ for( var file in results.copied ) { - consoleLogger.debug( ". #file#" ); - } - } - + consoleLogger.debug( ". #file#" ); + } + } + // Ignored Summary consoleLogger.debug( "-> #results.ignored.len()# File(s) ignored" ); if( arguments.verbose ){ for( var file in results.ignored ) { - consoleLogger.debug( ". #file#" ); + consoleLogger.debug( ". #file#" ); } } - + consoleLogger.info( "Eureka, '#arguments.ID#' has been installed!" ); - + // If no package ID was specified, just get the dependencies for the current directory } else { // read it... var artifactDescriptor = readPackageDescriptor( arguments.currentWorkingDirectory ); var installDirectory = arguments.currentWorkingDirectory; - + // By default, a general package install includes dev dependencies arguments.production = arguments.production ?: false; - + } // and grab all the dependencies var dependencies = artifactDescriptor.dependencies; - + // If we're not in production mode... if( !arguments.production ) { // Add in the devDependencies @@ -481,7 +481,7 @@ component accessors="true" singleton { for( var dependency in dependencies ) { var isDev = structKeyExists( artifactDescriptor.devDependencies, dependency ); var isSaving = ( arguments.save || arguments.saveDev ); - + var detail = dependencies[ dependency ]; // full ID with endpoint and package like file:/opt/files/foo.zip if( detail contains ':' ) { @@ -490,7 +490,7 @@ component accessors="true" singleton { } else { var ID = dependency & '@' & detail; } - + var params = { ID = ID, force = arguments.force, @@ -503,26 +503,26 @@ component accessors="true" singleton { currentWorkingDirectory = arguments.currentWorkingDirectory, // Original dir packagePathRequestingInstallation = installDirectory // directory for smart dependencies to use }; - + // Recursivley install them - installPackage( argumentCollection = params ); + installPackage( argumentCollection = params ); } - + if( !len( arguments.ID ) && dependencies.isEmpty() ) { consoleLogger.info( "No dependencies found to install, but it's the thought that counts, right?" ); } - + interceptorService.announceInterception( 'postInstall', { installArgs=arguments, installDirectory=installDirectory } ); return true; } - + // DRY function isPackageModule( required string packageType ) { // Is the package type that of a module? return ( listFindNoCase( 'modules,contentbox-modules,commandbox-modules', arguments.packageType ) > 0) ; } - - + + /******************************************************************************************************************/ // If the root of the current package doesn't have a box.json, check if there is a subdirectory that contains // a box.json. This would be the NPM-style standard where a zip contains a package in a sub folder. @@ -544,18 +544,18 @@ component accessors="true" singleton { // Repoint ourselves to the inner folder packagePath = subPath; break; - } + } } } } return packagePath; } - + /** * Uninstalls a package and its dependencies * @slug.ID Identifier of the packge to uninstall. * @slug.optionsUDF slugComplete - * @directory The directory to install in. This will override the packages's box.json install dir if provided. + * @directory The directory to install in. This will override the packages's box.json install dir if provided. * @save Remove package as a dependancy in box.json (if it exists) * @saveDev Remove package as a dev dependancy in box.json (if it exists) * @currentWorkingDirectory Root of the application (used for finding box.json) @@ -567,15 +567,15 @@ component accessors="true" singleton { required string currentWorkingDirectory, string packagePathRequestingUninstallation = arguments.currentWorkingDirectory ){ - + // In case someone types "uninstall coldbox@4.0.0" var packageName = listFirst( arguments.ID, '@' ); - + consoleLogger.info( '.'); consoleLogger.info( 'Uninstalling package: #packageName#'); - + var uninstallDirectory = ''; - + // If a directory is passed in, use it if( structKeyExists( arguments, 'directory' ) ) { var uninstallDirectory = arguments.directory @@ -584,19 +584,19 @@ component accessors="true" singleton { // Read the box.json var boxjson = readPackageDescriptor( arguments.currentWorkingDirectory ); var installPaths = boxJSON.installPaths; - + // Is there an install path for this? if( structKeyExists( installPaths, packageName ) ) { uninstallDirectory = fileSystemUtil.resolvePath( installPaths[ packageName ], arguments.currentWorkingDirectory ); - } + } } - - // Wait to run this until we've decided where the package lives that's being uninstalled. + + // Wait to run this until we've decided where the package lives that's being uninstalled. interceptorService.announceInterception( 'preUninstall', { uninstallArgs=arguments, uninstallDirectory=uninstallDirectory } ); - + // See if the package exists here if( len( uninstallDirectory ) && directoryExists( uninstallDirectory ) ) { - + // Get the dependencies of the package we're about to uninstalled var boxJSON = readPackageDescriptor( uninstallDirectory ); // and grab all the dependencies @@ -604,7 +604,7 @@ component accessors="true" singleton { var type = boxJSON.type; // Add in the devDependencies dependencies.append( boxJSON.devDependencies ); - + } else { // If the package isn't on disk, no dependencies var dependencies = {}; @@ -614,14 +614,14 @@ component accessors="true" singleton { // ColdBox modules are stored in a hierachy so just removing the top one removes then all // For all other packages, the depenencies are probably just in the root if( !isPackageModule( type ) ) { - + if( dependencies.count() ) { consoleLogger.debug( "Uninstalling dependencies first..." ); } - + // Loop over this packages dependencies for( var dependency in dependencies ) { - + var params = { ID = dependency, // Only save the first level @@ -629,40 +629,40 @@ component accessors="true" singleton { currentWorkingDirectory = uninstallDirectory, packagePathRequestingUninstallation=arguments.packagePathRequestingUninstallation }; - + // If the user didn't specify this, don't pass it since it overrides the package's desired install location if( structKeyExists( arguments, 'directory' ) ) { params.directory = arguments.directory; } - + // Recursivley install them - uninstallPackage( argumentCollection = params ); + uninstallPackage( argumentCollection = params ); } - + } // end is not module - + // uninstall the package if( len( uninstallDirectory ) && directoryExists( uninstallDirectory ) ) { - - // Catch this to gracefully handle where the OS or another program + + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { - directoryDelete( uninstallDirectory, true ); + directoryDelete( uninstallDirectory, true ); } catch( any e ) { consoleLogger.error( '#e.message##CR#The folder is possibly locked by another program.' ); logger.error( '#e.message# #e.detail#' , e.stackTrace ); } - + consoleLogger.info( "'#packageName#' has been uninstalled" ); - + } else if( !len( uninstallDirectory ) ) { - consoleLogger.debug( "Package [#packageName#] skipped, it doesn't appear to be installed." ); - + consoleLogger.debug( "Package [#packageName#] skipped, it doesn't appear to be installed." ); + } else { - consoleLogger.warn( 'Package [#uninstallDirectory#] not found.' ); + consoleLogger.warn( 'Package [#uninstallDirectory#] not found.' ); } - + // Should we save this as a dependancy // and is the current working directory a package? if( arguments.save && isPackage( arguments.currentWorkingDirectory ) ) { @@ -671,10 +671,10 @@ component accessors="true" singleton { // Tell the user... consoleLogger.info( "Dependency removed from box.json." ); } - + interceptorService.announceInterception( 'postUninstall', { uninstallArgs=arguments } ); } - + /** * Adds a dependency to a packge * @currentWorkingDirectory The directory that is the root of the package @@ -683,7 +683,7 @@ component accessors="true" singleton { * @installDirectory The location that the package is installed to including the container folder. * @installDirectoryIsDedicated True if the package was placed in a dedicated folder * @dev True if this is a development depenency, false if it is a production dependency - */ + */ public function addDependency( required string currentWorkingDirectory, required string packageName, @@ -695,20 +695,20 @@ component accessors="true" singleton { ) { // Get box.json, create empty if it doesn't exist var boxJSON = readPackageDescriptorRaw( arguments.currentWorkingDirectory ); - + // Get reference to appropriate dependency struct if( arguments.dev ) { param name='boxJSON.devDependencies' default='#{}#'; var dependencies = boxJSON.devDependencies; } else { param name='boxJSON.dependencies' default='#{}#'; - var dependencies = boxJSON.dependencies; + var dependencies = boxJSON.dependencies; } - + // Add/overwrite this dependency - + if( endpointData.endpointName == 'forgebox' ) { - + if( listLen( endpointData.package, '@' ) > 1 ) { dependencies[ arguments.packageName ] = listLast( endpointData.package, '@' ); } else { @@ -718,18 +718,18 @@ component accessors="true" singleton { } else { dependencies[ arguments.packageName ] = endpointData.ID; } - + // Only packages installed in a dedicated directory of their own can be uninstalled // so don't save this if they were just dumped somewhere like the package root amongst // other unrelated files and folders. if( arguments.installDirectoryIsDedicated ) { param name='boxJSON.installPaths' default='#{}#'; var installPaths = boxJSON.installPaths; - + // normalize slashes arguments.currentWorkingDirectory = fileSystemUtil.resolvePath( arguments.currentWorkingDirectory ); arguments.installDirectory = fileSystemUtil.resolvePath( arguments.installDirectory ); - + // If the install location is contained within the package root... if( arguments.installDirectory contains arguments.currentWorkingDirectory ) { // Make it relative @@ -739,94 +739,94 @@ component accessors="true" singleton { arguments.installDirectory = right( arguments.installDirectory, len( arguments.installDirectory ) - 1 ); } } - + // Just in case-- an empty install dir would be useless. if( len( arguments.installDirectory ) ) { - installPaths[ arguments.packageName ] = arguments.installDirectory; + installPaths[ arguments.packageName ] = arguments.installDirectory; } - + } // end installDirectoryIsDedicated - + // Write the box.json back out writePackageDescriptor( boxJSON, arguments.currentWorkingDirectory ); } - + /** * Removes a dependency from a packge if it exists * @directory The directory that is the root of the package * @packageName Package to add a a dependency * @dev True if this is a development depenency, false if it is a production dependency - */ + */ public function removeDependency( required string directory, required string packageName ) { // Get box.json, create empty if it doesn't exist var boxJSON = readPackageDescriptorRaw( arguments.directory ); - + var saveMe = false; - + if( structKeyExists( boxJSON, 'dependencies' ) && structKeyExists( boxJSON.dependencies, arguments.packageName ) ) { saveMe = true; structDelete( boxJSON.dependencies, arguments.packageName ); } - + if( structKeyExists( boxJSON, 'devdependencies' ) && structKeyExists( boxJSON.devdependencies, arguments.packageName ) ) { saveMe = true; structDelete( boxJSON.devdependencies, arguments.packageName ); } - + if( structKeyExists( boxJSON, 'installPaths' ) && structKeyExists( boxJSON.installPaths, arguments.packageName ) ) { saveMe = true; structDelete( boxJSON.installPaths, arguments.packageName ); } - + // Only save if we modified the JSON if( saveMe ) { // Write the box.json back out - writePackageDescriptor( boxJSON, arguments.directory ); + writePackageDescriptor( boxJSON, arguments.directory ); } } - + /** * Get the default package description, AKA box.json * @defaults A struct of default values to be merged into the empty, default document - */ + */ public function newPackageDescriptor( struct defaults={}, boolean omitDeprecated=false ) { - + // TODO: Get author info from default CommandBox config - - // Read the default JSON file and deserialize it. + + // Read the default JSON file and deserialize it. var boxJSON = DeserializeJSON( fileRead( '/commandBox/system/config/box.json.txt' ) ); - + // Remove deprecated (or just edge case) properties // from the box.json template as to not confuse people. if( arguments.omitDeprecated ) { - + // most packages shouldn't need to set these boxJSON.delete( 'directory' ) boxJSON.delete( 'createPackageDirectory' ) boxJSON.delete( 'packageDirectory' ) - + // These aren't even used boxJSON.delete( 'engines' ) boxJSON.delete( 'defaultEngine' ) - + // This went out of style with server.json boxJSON.delete( 'defaultPort' ); } - + // Replace things passed via parameters boxJSON = boxJSON.append( arguments.defaults ); - - return boxJSON; - + + return boxJSON; + } /** * Get the box.json as data from the passed directory location. * Any missing properties will be defaulted with our box.json template. * If you plan on writing the box.json back out to disk, use readPackageDescriptorRaw() instead. - * - * If you ask for system settings to be swapped out, do not write this box.json back to disk. + * + * If you ask for system settings to be swapped out, do not write this box.json back to disk. * It's has possibly been modified to expand the props like ${foo} and will overwrite the actual place holders * * @directory The directory to search for the box.json @@ -839,8 +839,8 @@ component accessors="true" singleton { systemSettings.expandDeepSystemSettings( results ); } return results - - } + + } /** * Does everything readPackageDescriptor() does, but won't default deprecated box.json proprties. @@ -854,28 +854,28 @@ component accessors="true" singleton { /** * Get the box.json as data from the passed directory location, if not found * then we return an empty struct. This method will NOT default box.json properties - * and will return JUST what was defined. Make sure you use existence checks when + * and will return JUST what was defined. Make sure you use existence checks when * using the returned data structure * @directory The directory to search for the box.json */ struct function readPackageDescriptorRaw( required directory ){ - + // If the packge has a box.json in the root... if( isPackage( arguments.directory ) ) { - + // ...Read it. boxJSON = fileRead( getDescriptorPath( arguments.directory ) ); - + // Validate the file is valid JSON if( isJSON( boxJSON ) ) { return deserializeJSON( boxJSON ); } else { consoleLogger.warn( 'Warning: package has an invalid box.json file. [#arguments.directory#]' ); } - + } // Just return defaults - return {}; + return {}; } /** @@ -884,12 +884,12 @@ component accessors="true" singleton { * @directory The directory to write the box.json */ function writePackageDescriptor( required any JSONData, required directory ){ - + if( !isSimpleValue( JSONData ) ) { JSONData = serializeJSON( JSONData ); } - fileWrite( getDescriptorPath( arguments.directory ), formatterUtil.formatJSON( JSONData ) ); + fileWrite( getDescriptorPath( arguments.directory ), formatterUtil.formatJSON( JSONData ) ); } /** @@ -898,7 +898,7 @@ component accessors="true" singleton { * @print The print buffer used for command operation * @verbose Outputs additional information about each package as it is checked * @includeSlugs A commit-delimited list of slugs to include. Empty means include everything. - * + * * @return An array of structs of outdated dependencies */ array function getOutdatedDependencies( required directory, required print, boolean verbose=false, includeSlugs='' ){ @@ -911,44 +911,44 @@ component accessors="true" singleton { var aOutdatedDependencies = []; // Outdated check closure var fOutdatedCheck = function( slug, value ){ - + // Only check slugs we're supposed to if( !len( includeSlugs ) || listFindNoCase( includeSlugs, arguments.slug ) ) { - + // If a package is not installed (possibly a dev dependency in production mode), then we skip it if( !value.isInstalled ) { if( verbose ){ print.yellowLine( " * #arguments.slug# is not installed, skipping.." ) .toConsole(); } - return; + return; } - + // Contains an enpoint if( value.version contains ':' ) { var ID = value.version; } else { var ID = arguments.slug & '@' & value.version; } - + try { var endpointData = endpointService.resolveEndpoint( ID, fakeDir ); } catch( EndpointNotFound var e ) { consoleLogger.error( e.message ); - return; + return; } - + try { var updateData = endpointData.endpoint.getUpdate( endpointData.package, value.packageVersion, verbose ); - // endpointException exception type is used when the endpoint has an issue that needs displayed, - // but I don't want to "blow up" the console with a full error. + // endpointException exception type is used when the endpoint has an issue that needs displayed, + // but I don't want to "blow up" the console with a full error. } catch( endpointException var e ) { consoleLogger.error( e.message & ' ' & e.detail ); - return; + return; } - + if( updateData.isOutdated ){ - aOutdatedDependencies.append({ + aOutdatedDependencies.append({ slug : arguments.slug, directory : value.directory, version : value.version, @@ -965,9 +965,9 @@ component accessors="true" singleton { .boldRedText( updateData.isOutdated ? " * #arguments.slug# is Outdated#chr( 10 )#" : "" ) .toConsole(); } - + } - + // Do we have more dependencies, go down the tree in parallel if( structCount( value.dependencies ) ){ structEach( value.dependencies, fOutdatedCheck ); @@ -1004,10 +1004,10 @@ component accessors="true" singleton { parent[ 'dependencies' ] = processDependencies( boxJSON.dependencies, boxJSON.installPaths, false, arguments.basePath ); parent[ 'dependencies' ].append( processDependencies( boxJSON.devDependencies, boxJSON.installPaths, true, arguments.basePath ) ); } - + private function processDependencies( dependencies, installPaths, dev=false, basePath ) { var thisDeps = {}; - + for( var dependency in arguments.dependencies ) { thisDeps[ dependency ] = { 'version' : arguments.dependencies[ dependency ], @@ -1018,51 +1018,51 @@ component accessors="true" singleton { 'isInstalled': false, 'directory': '' }; - + if( structKeyExists( arguments.installPaths, dependency ) ) { - + var fullPackageInstallPath = fileSystemUtil.resolvePath( arguments.installPaths[ dependency ], arguments.basePath ); - + if( directoryExists( fullPackageInstallPath ) ) { var boxJSON = readPackageDescriptor( fullPackageInstallPath ); thisDeps[ dependency ][ 'name' ] = boxJSON.name; thisDeps[ dependency ][ 'shortDescription' ] = boxJSON.shortDescription; thisDeps[ dependency ][ 'packageVersion' ] = boxJSON.version; thisDeps[ dependency ][ 'isInstalled' ] = true; - + if( boxJSON.createPackageDirectory ) { // Back up to the "container" folder. The package directory will be added back on installation thisDeps[ dependency ][ 'directory' ] = listDeleteAt( fullPackageInstallPath, listLen( fullPackageInstallPath, '/\' ), '/\' ); } else { - thisDeps[ dependency ][ 'directory' ] = fullPackageInstallPath; + thisDeps[ dependency ][ 'directory' ] = fullPackageInstallPath; } - + // Down the rabbit hole - buildChildren( boxJSON, thisDeps[ dependency ], fullPackageInstallPath ); - + buildChildren( boxJSON, thisDeps[ dependency ], fullPackageInstallPath ); + } else { - thisDeps[ dependency ][ 'isInstalled' ] = false; + thisDeps[ dependency ][ 'isInstalled' ] = false; } - + } - + // If we don't have an install path for this package, we don't know about its dependencies thisDeps[ dependency ][ 'dependencies' ] = thisDeps[ dependency ][ 'dependencies' ] ?: {}; - + } - + return thisDeps; } - + /** * Dynamic completion for property name based on contents of box.json * @directory The package root * @all Pass false to ONLY suggest existing property names. True will suggest all possible box.json properties. * @asSet Pass true to add = to the end of the options - */ + */ function completeProperty( required directory, all=false, asSet=false ) { var props = []; - + // Check and see if box.json exists if( isPackage( arguments.directory ) ) { if( arguments.all ) { @@ -1070,45 +1070,45 @@ component accessors="true" singleton { } else { var boxJSON = readPackageDescriptorRaw( arguments.directory ); } - props = JSONService.addProp( props, '', '', boxJSON ); + props = JSONService.addProp( props, '', '', boxJSON ); } if( asSet ) { props = props.map( function( i ){ return i &= '='; } ); } - return props; + return props; } - + /** * Nice wrapper to run a package script * @scriptName Name of the package script to run * @directory The package root - */ + */ function runScript( required string scriptName, string directory=shell.pwd(), boolean ignoreMissing=true ) { - + // Read the box.json from this package (if it exists) var boxJSON = readPackageDescriptor( arguments.directory ); // If there is a scripts object with a matching key for this interceptor.... if( boxJSON.keyExists( 'scripts' ) && isStruct( boxJSON.scripts ) && boxJSON.scripts.keyExists( arguments.scriptName ) ) { - + // Run preXXX package script runScript( 'pre#arguments.scriptName#', arguments.directory, true ); - + var thisScript = boxJSON.scripts[ arguments.scriptName ]; consoleLogger.debug( '.' ); consoleLogger.warn( 'Running package script [#arguments.scriptName#].' ); consoleLogger.debug( '> ' & thisScript ); - + // ... then run the script! (in the context of the package's working directory) var previousCWD = shell.pwd(); shell.cd( arguments.directory ); shell.callCommand( thisScript ); shell.cd( previousCWD ); - + // Run postXXX package script runScript( 'post#arguments.scriptName#', arguments.directory, true ); - + } else if( !arguments.ignoreMissing ) { consoleLogger.error( 'The script [#arguments.scriptName#] does not exist in this package.' ); } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index 234a651cf..975ec3df6 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -20,10 +20,10 @@ component accessors="true" singleton="true" { property name="semanticVersion" inject="provider:semanticVersion@semver"; property name="artifactService" inject="artifactService"; - + /** * install the server if not already installed to the target directory - * + * * @cfengine CFML Engine name (lucee, adobe, railo) * @baseDirectory base directory for server install * @serverInfo The struct of server settings @@ -33,7 +33,7 @@ component accessors="true" singleton="true" { var version = listLen( cfengine, "@" )>1 ? listLast( cfengine, "@" ) : ""; var engineName = listFirst( cfengine, "@" ); arguments.baseDirectory = !arguments.baseDirectory.endsWith( "/" ) ? arguments.baseDirectory & "/" : arguments.baseDirectory; - + if( engineName == "adobe" ) { return installAdobe( destination=arguments.baseDirectory, version=version, serverInfo=serverInfo, serverHomeDirectory=serverHomeDirectory ); } else if (engineName == "railo") { @@ -47,7 +47,7 @@ component accessors="true" singleton="true" { /** * install adobe - * + * * @destination target directory * @version Version number or empty to use default * @serverInfo Struct of server settings @@ -63,11 +63,11 @@ component accessors="true" singleton="true" { if( installDetails.initialInstall ) { flexConfig = replace(flexConfig, "/WEB-INF/", installDetails.installDir & "/WEB-INF/","all"); fileWrite(installDetails.installDir & "/WEB-INF/cfform/flex-config.xml", flexConfig); - } else { - // TODO: Remove this ELSE block in a future revision. - // This will fix the flex-config.xml files that have been corrupted because we weren't checking initialInstall, above. + } else { + // TODO: Remove this ELSE block in a future revision. + // This will fix the flex-config.xml files that have been corrupted because we weren't checking initialInstall, above. var escapedInstDir=reReplace(installDetails.installDir,"(\\|\/|\.|\:)","\\1","all"); - //reReplace supports 5 backreferences in the replacement substring for case conversions. It doesn't allow escaping of these backreferences though in case you want them literally! + //reReplace supports 5 backreferences in the replacement substring for case conversions. It doesn't allow escaping of these backreferences though in case you want them literally! var replaceString=reReplace(installDetails.installDir,"\\(u|U|l|L|E)","##chr(92)##\1","all"); var regex="(?:" & escapedInstDir & ")*" & "\/WEB-INF\/" ; flexConfig = reReplace(flexConfig, regex, replaceString & "/WEB-INF/","all"); @@ -79,7 +79,7 @@ component accessors="true" singleton="true" { /** * install lucee - * + * * @destination target directory * @version Version number or empty to use default * @serverInfo struct of server settings @@ -87,16 +87,16 @@ component accessors="true" singleton="true" { **/ public function installLucee( required destination, required version, required struct serverInfo, required string serverHomeDirectory ) { var installDetails = installEngineArchive( 'lucee@#version#', destination, serverInfo, serverHomeDirectory ); - + if( installDetails.initialInstall ) { configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXML, destination=serverInfo.webXML, serverInfo=serverInfo ); - } + } return installDetails; } /** * install railo - * + * * @destination target directory * @version Version number or empty to use default * @serverInfo struct of server settings @@ -104,17 +104,17 @@ component accessors="true" singleton="true" { **/ public function installRailo( required destination, required version, required struct serverInfo, required string serverHomeDirectory ) { var installDetails = installEngineArchive( 'railo@#version#', destination, serverInfo, serverHomeDirectory ); - + if( installDetails.initialInstall ) { - configureWebXML( cfengine="railo", version=installDetails.version, source=serverInfo.webXML, destination=serverInfo.webXML, serverInfo=serverInfo ); - } + configureWebXML( cfengine="railo", version=installDetails.version, source=serverInfo.webXML, destination=serverInfo.webXML, serverInfo=serverInfo ); + } return installDetails; } /* * Downloads a CF engine endpoint and unzips the "Engine.[WAR|zip] archive into the destination * The WAR will be placed in a folder named {cfengine}-{version}/ unless an installDir is supplied. - * + * * @ID The endpoint ID to use for the CF Engine. * @destination The folder where this site's servers are stored. */ @@ -124,28 +124,28 @@ component accessors="true" singleton="true" { required struct serverInfo, required string serverHomeDirectory ) { - + var installDetails = { engineName : '', version : '', installDir : '', initialInstall : false }; - + var thisTempDir = tempDir & '/' & createUUID(); - + // Find out what endpoint will service them and ask the endpoint what their name is. var endpointData = endpointService.resolveEndpoint( ID, shell.pwd() ); var endpoint = endpointData.endpoint; var engineName = endpoint.getDefaultName( arguments.ID ); installDetails.engineName = engineName; - - // In order to prevent uneccessary work, we're going to try REALLY hard to figure out exactly what engine will be installed + + // In order to prevent uneccessary work, we're going to try REALLY hard to figure out exactly what engine will be installed // before it actually happens so we can skip this whole mess if it's already in place. // if our endpoint is ForgeBox, figure out what version it is going to install. if( endpointData.endpointName == 'forgebox' ) { var version = endpoint.parseVersion( arguments.ID ); - + // If the user gave us an exact version, just use it! // Require buildID like 5.1.0+34 if( semanticVersion.isExactVersion( version=version, includeBuildID=true ) ) { @@ -157,12 +157,12 @@ component accessors="true" singleton="true" { var satisfyingVersion = endpoint.findSatisfyingVersion( endpoint.parseSlug( arguments.ID ), version ).version; consoleLogger.info( "OK, [#engineName# #satisfyingVersion#] it is!"); } catch( any var e ) { - + consoleLogger.error( "."); consoleLogger.error( "Aww man, ForgeBox isn't feeling well."); consoleLogger.debug( "#e.message# #e.detail#"); consoleLogger.error( "We're going to look in your local artifacts cache and see if one of those versions will work."); - + // See if there's something usable in the artifacts cache. If so, we'll use that version. var satisfyingVersion = artifactService.findSatisfyingVersion( endpoint.parseSlug( arguments.ID ), version ); if( len( satisfyingVersion ) ) { @@ -173,36 +173,36 @@ component accessors="true" singleton="true" { } else { throw( 'No satisfying version found for [#version#].', 'endpointException', 'Well, we tried as hard as we can. ForgeBox is unreachable and you don''t have a usable version in your local artifacts cache. Please try another version.' ); } - } + } } // Overriding server home which is where the exploded war lives if( len( arguments.serverHomeDirectory ) ) { - installDetails.installDir = arguments.serverHomeDirectory; - // Default is engine-version folder in base dir + installDetails.installDir = arguments.serverHomeDirectory; + // Default is engine-version folder in base dir } else { installDetails.installDir = destination & engineName & "-" & replace( satisfyingVersion, '+', '.', 'all' ); } installDetails.version = satisfyingVersion; - + var thisEngineTag = installDetails.engineName & '@' & installDetails.version; - + } else { - + // For all other endpoints, create a predictable folder based on the endpoint ID. // If the file that the endpoint points to changes, you'll have to forget the server to pick up changes. // The alternative is re-downloading the engine EVERY. SINGLE. TIME. // Overriding server home which is where the exploded war lives if( len( arguments.serverHomeDirectory ) ) { - installDetails.installDir = arguments.serverHomeDirectory; - // Default is engine-version folder in base dir + installDetails.installDir = arguments.serverHomeDirectory; + // Default is engine-version folder in base dir } else { installDetails.installDir = destination & engineName; } - + var thisEngineTag = arguments.ID; - + } - + // Set default web.xml path now that we have an install dir if( !len( serverInfo.webXML ) ) { serverInfo.webXML = "#installDetails.installDir#/WEB-INF/web.xml"; @@ -221,16 +221,16 @@ component accessors="true" singleton="true" { serverInfo.webConfigDir = replace( serverInfo.webConfigDir, '\', '/', 'all' ); serverInfo.serverConfigDir = replace( serverInfo.serverConfigDir, '\', '/', 'all' ); installDetails.installDir = replace( installDetails.installDir, '\', '/', 'all' ); - + serverInfo.webConfigDir = replace( serverInfo.webConfigDir, installDetails.installDir, '' ); - serverInfo.serverConfigDir = replace( serverInfo.serverConfigDir, installDetails.installDir, '' ); + serverInfo.serverConfigDir = replace( serverInfo.serverConfigDir, installDetails.installDir, '' ); } - + var engineTagFile = installDetails.installDir & '/.engineInstall'; - + // Check to see if this WAR has already been exploded if( fileExists( engineTagFile ) ) { - + // Check and see if another version of this engine has already been started in the server home. var previousEngineTag = fileRead( engineTagFile ); if( previousEngineTag != thisEngineTag ) { @@ -238,40 +238,40 @@ component accessors="true" singleton="true" { consoleLogger.warn( "but this server home already has [#previousEngineTag#] deployed to it!" ); consoleLogger.warn( "In order to get the new version, you need to run 'server forget' on this server and start it again." ); } - + consoleLogger.info( "WAR/zip archive already installed."); - + return installDetails; } - + // Install the engine via our standard package service installDetails.initialInstall = true; - + // If we're starting a Lucee server whose version matches the CLI engine, then don't download anything, we're using internal jars. if( listFirst( arguments.ID, '@' ) == 'lucee' && server.lucee.version == replace( installDetails.version, '+', '.', 'all' ) ) { - + consoleLogger.info( "Building a WAR from local jars."); - + // Spoof a WAR file. var thisWebinf = installDetails.installDir & '/WEB-INF'; var thislib = thisWebinf & '/lib'; var thiServerContext = thisWebinf & '/server-context'; var thiWebContext = thisWebinf & '/web-context'; - + directoryCreate( installDetails.installDir & '/WEB-INF', true, true ); directoryCopy( '/commandbox-home/lib', thislib, false, '*.jar' ); fileCopy( '/commandbox/system/config/web.xml', thisWebinf & '/web.xml'); - + // Mark this WAR as being exploded already fileWrite( engineTagFile, thisEngineTag ); - + return installDetails; } - + if( !packageService.installPackage( ID=arguments.ID, directory=thisTempDir, save=false ) ) { throw( message='Server not installed.', type="commandException"); } - + // Look for a war or zip archive inside the package var theArchive = ''; for( var thisFile in directoryList( thisTempDir ) ) { @@ -280,20 +280,20 @@ component accessors="true" singleton="true" { break; } } - + // If there's no archive, we don't know what to do! if( theArchive == '' ) { throw( "Package didn't contain a war or zip archive." ); } - + consoleLogger.info( "Exploding WAR/zip archive..."); directoryCreate( installDetails.installDir, true, true ); zip action="unzip" file="#theArchive#" destination="#installDetails.installDir#" overwrite="false"; - + // Mark this WAR as being exploded already fileWrite( engineTagFile, thisEngineTag ); - - // Catch this to gracefully handle where the OS or another program + + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { directoryDelete( thisTempDir, true ); @@ -303,10 +303,10 @@ component accessors="true" singleton="true" { } return installDetails; } - + /** * configure web.xml file for Lucee and Railo - * + * * @cfengine lucee or railo * @source source web.xml * @destination target web.xml @@ -320,7 +320,7 @@ component accessors="true" singleton="true" { initParam.XmlChildren[2] = xmlElemnew(webXML,"param-value"); initParam.XmlChildren[2].XmlText = serverInfo.webConfigDir; arrayInsertAt(servlets[1].XmlParent.XmlChildren,4,initParam); - + var servlets = xmlSearch(webXML,"//:servlet-class[text()='#lcase( cfengine )#.loader.servlet.CFMLServlet']"); var initParam = xmlElemnew(webXML,"http://java.sun.com/xml/ns/javaee","init-param"); initParam.XmlChildren[1] = xmlElemnew(webXML,"param-name"); @@ -328,9 +328,9 @@ component accessors="true" singleton="true" { initParam.XmlChildren[2] = xmlElemnew(webXML,"param-value"); initParam.XmlChildren[2].XmlText = serverInfo.serverConfigDir; arrayInsertAt(servlets[1].XmlParent.XmlChildren,4,initParam); - + // Lucee 5+ has a LuceeServlet as well as will create the WEB-INF by default in your web root - if( arguments.cfengine == 'lucee' && val( listFirst( arguments.version, '.' )) >= 5 ) { + if( arguments.cfengine == 'lucee' && val( listFirst( arguments.version, '.' )) >= 5 ) { var servlets = xmlSearch(webXML,"//:servlet-class[text()='#lcase( cfengine )#.loader.servlet.LuceeServlet']"); var initParam = xmlElemnew(webXML,"http://java.sun.com/xml/ns/javaee","init-param"); initParam.XmlChildren[1] = xmlElemnew(webXML,"param-name"); @@ -338,7 +338,7 @@ component accessors="true" singleton="true" { initParam.XmlChildren[2] = xmlElemnew(webXML,"param-value"); initParam.XmlChildren[2].XmlText = serverInfo.webConfigDir; arrayInsertAt(servlets[1].XmlParent.XmlChildren,4,initParam); - + var servlets = xmlSearch(webXML,"//:servlet-class[text()='#lcase( cfengine )#.loader.servlet.LuceeServlet']"); var initParam = xmlElemnew(webXML,"http://java.sun.com/xml/ns/javaee","init-param"); initParam.XmlChildren[1] = xmlElemnew(webXML,"param-name"); @@ -346,8 +346,8 @@ component accessors="true" singleton="true" { initParam.XmlChildren[2] = xmlElemnew(webXML,"param-value"); initParam.XmlChildren[2].XmlText = serverInfo.serverConfigDir; arrayInsertAt(servlets[1].XmlParent.XmlChildren,4,initParam); - } - + } + var xlt = ' diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 207eca359..7163e01a9 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -30,9 +30,9 @@ component accessors="true" singleton { * Where the Run War jar path is */ property name="jarPath"; - - property name='rewritesDefaultConfig' inject='rewritesDefaultConfig@constants'; - property name='interceptorService' inject='interceptorService'; + + property name='rewritesDefaultConfig' inject='rewritesDefaultConfig@constants'; + property name='interceptorService' inject='interceptorService'; property name='configService' inject='ConfigService'; property name='JSONService' inject='JSONService'; property name='packageService' inject='packageService'; @@ -42,7 +42,7 @@ component accessors="true" singleton { property name='CR' inject='CR@constants'; property name='parser' inject='parser'; property name='systemSettings' inject='SystemSettings'; - + /** * Constructor * @shell.inject shell @@ -98,7 +98,7 @@ component accessors="true" singleton { if( !directoryExists( variables.customServerDirectory ) ){ directoryCreate( variables.customServerDirectory ); } - + return this; } @@ -109,7 +109,7 @@ component accessors="true" singleton { // pull default settings from config to mix in below. // The structure of server.defaults in Config settings matches the default server.json layout here. var d = ConfigService.getSetting( 'server.defaults', {} ); - + return { 'name' : d.name ?: '', 'openBrowser' : d.openBrowser ?: true, @@ -123,13 +123,13 @@ component accessors="true" singleton { 'trayOptions' : duplicate( d.trayOptions ?: [] ), 'trayEnable' : d.trayEnable ?: true, 'jvm' : { - 'heapSize' : d.jvm.heapSize ?: 512, + 'heapSize' : d.jvm.heapSize ?: 512, 'minHeapSize' : d.jvm.minHeapSize ?: 0, 'args' : d.jvm.args ?: '', 'javaHome' : ( isDefined( 'd.jvm.javaHome' ) ? fileSystemUtil.getJREExecutable( d.jvm.javaHome ) : variables.javaCommand ) }, 'web' : { - 'host' : d.web.host ?: '127.0.0.1', + 'host' : d.web.host ?: '127.0.0.1', 'directoryBrowsing' : d.web.directoryBrowsing ?: true, 'webroot' : d.web.webroot ?: '', // Duplicate so onServerStart interceptors don't actually change config settings via refernce. @@ -185,11 +185,11 @@ component accessors="true" singleton { function start( Struct serverProps ){ - + // Resolve path as used locally if( !isNull( serverProps.directory ) ) { serverProps.directory = fileSystemUtil.resolvePath( serverProps.directory ); - } + } if( !isNull( serverProps.serverConfigFile ) ) { serverProps.serverConfigFile = fileSystemUtil.resolvePath( serverProps.serverConfigFile ); } @@ -217,7 +217,7 @@ component accessors="true" singleton { if( !isNull( serverProps.libDirs ) ) { // Comma-delimited list needs each item resolved serverProps.libDirs = serverProps.libDirs - .map( function( thisLibDir ){ + .map( function( thisLibDir ){ return fileSystemUtil.resolvePath( thisLibDir ); } ); } @@ -234,9 +234,9 @@ component accessors="true" singleton { // Look up the server that we're starting var serverDetails = resolveServerDetails( arguments.serverProps ); - + interceptorService.announceInterception( 'preServerStart', { serverDetails=serverDetails, serverProps=serverProps } ); - + var defaultName = serverDetails.defaultName; var defaultwebroot = serverDetails.defaultwebroot; var defaultServerConfigFile = serverDetails.defaultServerConfigFile; @@ -258,7 +258,7 @@ component accessors="true" singleton { if( len( newName ) ) { serverProps.name = newName; //copy the orig server's server.json file to the new file so it starts with the same properties as the original. lots of alternative ways to do this but the file copy works and is simple - file action='copy' source="#defaultServerConfigFile#" destination=fileSystemUtil.resolvePath( serverProps.directory ?: '' ) & "/server-#serverProps.name#.json" mode ='777'; + file action='copy' source="#defaultServerConfigFile#" destination=fileSystemUtil.resolvePath( serverProps.directory ?: '' ) & "/server-#serverProps.name#.json" mode ='777'; return start( serverProps ); } } @@ -286,7 +286,7 @@ component accessors="true" singleton { // * // End backwards compat for default port in box.json. // * // ************************************************************************************* - + // Save hand-entered properties in our server.json for next time for( var prop in serverProps ) { // Ignore null props or ones that shouldn't be saved @@ -359,10 +359,10 @@ component accessors="true" singleton { if( thisLibDir contains configPath ) { return replaceNoCase( thisLibDir, configPath, '' ); } else { - return thisLibDir; + return thisLibDir; } } ); - + break; case "cfengine": serverJSON[ 'app' ][ 'cfengine' ] = serverProps[ prop ]; @@ -423,31 +423,31 @@ component accessors="true" singleton { break; case "heapSize": serverJSON[ 'JVM' ][ 'heapSize' ] = serverProps[ prop ]; - break; + break; case "minHeapSize": serverJSON[ 'JVM' ][ 'minHeapSize' ] = serverProps[ prop ]; - break; + break; case "JVMArgs": serverJSON[ 'JVM' ][ 'args' ] = serverProps[ prop ]; - break; + break; case "javaHomeDirectory": serverJSON[ 'JVM' ][ 'javaHome' ] = serverProps[ prop ]; break; case "runwarArgs": serverJSON[ 'runwar' ][ 'args' ] = serverProps[ prop ]; break; - default: + default: serverJSON[ prop ] = serverProps[ prop ]; } // end switch } // for loop - + if( !serverJSON.isEmpty() && serverProps.saveSettings ) { saveServerJSON( defaultServerConfigFile, serverJSON ); } - + systemSettings.expandDeepSystemSettings( serverJSON ); systemSettings.expandDeepSystemSettings( defaults ); - + // Setup serverinfo according to params // Hand-entered values take precendence, then settings saved in server.json, and finally defaults. // The big servers.json is only used to keep a record of the last values the server was started with @@ -455,8 +455,8 @@ component accessors="true" singleton { serverInfo.debug = serverProps.debug ?: serverJSON.debug ?: defaults.debug; serverInfo.openbrowser = serverProps.openbrowser ?: serverJSON.openbrowser ?: defaults.openbrowser; serverInfo.openbrowserURL = serverProps.openbrowserURL ?: serverJSON.openbrowserURL ?: defaults.openbrowserURL; - - + + serverInfo.host = serverProps.host ?: serverJSON.web.host ?: defaults.web.host; // If the last port we used is taken, remove it from consideration. if( serverInfo.port == 0 || !isPortAvailable( serverInfo.host, serverInfo.port ) ) { serverInfo.delete( 'port' ); } @@ -466,7 +466,7 @@ component accessors="true" singleton { if( serverInfo.port == 0 ) { serverInfo.port = getRandomPort( serverInfo.host ); } - + // Double check that the port in the user params or server.json isn't in use if( !isPortAvailable( serverInfo.host, serverInfo.port ) ) { consoleLogger.error( "." ); @@ -476,13 +476,13 @@ component accessors="true" singleton { } else if ( len( defaults.web.http.port ?: '' ) ) { badPortlocation = 'server.json'; } else { - badPortlocation = 'config server defaults'; + badPortlocation = 'config server defaults'; } consoleLogger.error( "You asked for port [#( serverProps.port ?: serverJSON.web.http.port ?: defaults.web.http.port ?: '?' )#] in your #badPortlocation# but it's already in use so I'm ignoring it and choosing a random one for you." ); consoleLogger.error( "." ); serverInfo.port = getRandomPort( serverInfo.host ); } - + // If there's no open URL, let's create a complete one if( !serverInfo.openbrowserURL.len() ) { serverInfo.openbrowserURL = serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#'; @@ -493,8 +493,8 @@ component accessors="true" singleton { } serverInfo.openbrowserURL = ( serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#' ) & serverInfo.openbrowserURL; } - - serverInfo.stopsocket = serverProps.stopsocket ?: serverJSON.stopsocket ?: getRandomPort( serverInfo.host ); + + serverInfo.stopsocket = serverProps.stopsocket ?: serverJSON.stopsocket ?: getRandomPort( serverInfo.host ); // relative trayIcon in server.json is resolved relative to the server.json if( serverJSON.keyExists( 'app' ) && serverJSON.app.keyExists( 'webConfigDir' ) ) { serverJSON.app.webConfigDir = fileSystemUtil.resolvePath( serverJSON.app.webConfigDir, defaultServerConfigFileDirectory ); } @@ -512,14 +512,14 @@ component accessors="true" singleton { if( serverJSON.keyExists( 'app' ) && serverJSON.app.keyExists( 'webXML' ) ) { serverJSON.app.webXML = fileSystemUtil.resolvePath( serverJSON.app.webXML, defaultServerConfigFileDirectory ); } // relative trayIcon in config setting server defaults is resolved relative to the web root if( len( defaults.app.webXML ?: '' ) ) { defaults.app.webXML = fileSystemUtil.resolvePath( defaults.app.webXML, defaultwebroot ); } - serverInfo.webXML = serverProps.webXML ?: serverJSON.app.webXML ?: defaults.app.webXML; - + serverInfo.webXML = serverProps.webXML ?: serverJSON.app.webXML ?: defaults.app.webXML; + // relative trayIcon in server.json is resolved relative to the server.json if( serverJSON.keyExists( 'trayIcon' ) ) { serverJSON.trayIcon = fileSystemUtil.resolvePath( serverJSON.trayIcon, defaultServerConfigFileDirectory ); } // relative trayIcon in config setting server defaults is resolved relative to the web root if( defaults.keyExists( 'trayIcon' ) && len( defaults.trayIcon ) ) { defaults.trayIcon = fileSystemUtil.resolvePath( defaults.trayIcon, defaultwebroot ); } serverInfo.trayIcon = serverProps.trayIcon ?: serverJSON.trayIcon ?: defaults.trayIcon; - + serverInfo.SSLEnable = serverProps.SSLEnable ?: serverJSON.web.SSL.enable ?: defaults.web.SSL.enable; serverInfo.HTTPEnable = serverProps.HTTPEnable ?: serverJSON.web.HTTP.enable ?: defaults.web.HTTP.enable; serverInfo.SSLPort = serverProps.SSLPort ?: serverJSON.web.SSL.port ?: defaults.web.SSL.port; @@ -532,58 +532,58 @@ component accessors="true" singleton { serverInfo.basicAuthEnable = serverJSON.web.basicAuth.enable ?: defaults.web.basicAuth.enable; serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; - + serverInfo.trayEnable = serverJSON.trayEnable ?: defaults.trayEnable; - - + + // Clean up spaces in welcome file list serverInfo.welcomeFiles = serverInfo.welcomeFiles.listMap( function( i ){ return trim( i ); } ); - - + + // relative rewrite config path in server.json is resolved relative to the server.json if( isDefined( 'serverJSON.web.rewrites.config' ) ) { serverJSON.web.rewrites.config = fileSystemUtil.resolvePath( serverJSON.web.rewrites.config, defaultServerConfigFileDirectory ); } // relative rewrite config path in config setting server defaults is resolved relative to the web root if( isDefined( 'defaults.web.rewrites.config' ) ) { defaults.web.rewrites.config = fileSystemUtil.resolvePath( defaults.web.rewrites.config, defaultwebroot ); } serverInfo.rewritesConfig = serverProps.rewritesConfig ?: serverJSON.web.rewrites.config ?: defaults.web.rewrites.config; - + serverInfo.heapSize = serverProps.heapSize ?: serverJSON.JVM.heapSize ?: defaults.JVM.heapSize; serverInfo.minHeapSize = serverProps.minHeapSize ?: serverJSON.JVM.minHeapSize ?: defaults.JVM.minHeapSize; - + if( isDefined( 'serverProps.javaHomeDirectory' ) ) { serverInfo.javaHome = fileSystemUtil.getJREExecutable( serverProps.javaHomeDirectory ); } else if( isDefined( 'serverJSON.JVM.javaHome' ) ) { serverInfo.javaHome = fileSystemUtil.getJREExecutable( serverJSON.JVM.javaHome ); } else { serverInfo.javaHome = defaults.JVM.javaHome; - } - + } + serverInfo.directoryBrowsing = serverProps.directoryBrowsing ?: serverJSON.web.directoryBrowsing ?: defaults.web.directoryBrowsing; - + // Global aliases are always added on top of server.json (but don't overwrite) // Aliases aren't accepted via command params due to no clean way to provide them serverInfo.aliases = defaults.web.aliases; serverInfo.aliases.append( serverJSON.web.aliases ?: {} ); - + // Global errorPages are always added on top of server.json (but don't overwrite the full struct) // Aliases aren't accepted via command params serverInfo.errorPages = defaults.web.errorPages; serverInfo.errorPages.append( serverJSON.web.errorPages ?: {} ); - - + + // Global trayOptions are always added on top of server.json (but don't overwrite) // trayOptions aren't accepted via command params due to no clean way to provide them serverInfo.trayOptions = defaults.trayOptions; serverInfo.trayOptions.append( serverJSON.trayOptions ?: [], true ); - + // Global defauls are always added on top of whatever is specified by the user or server.json serverInfo.JVMargs = ( serverProps.JVMargs ?: serverJSON.JVM.args ?: '' ) & ' ' & defaults.JVM.args; - + // Global defauls are always added on top of whatever is specified by the user or server.json serverInfo.runwarArgs = ( serverProps.runwarArgs ?: serverJSON.runwar.args ?: '' ) & ' ' & defaults.runwar.args; // Server startup timeout serverInfo.startTimeout = serverProps.startTimeout ?: serverJSON.startTimeout ?: defaults.startTimeout; - + // relative lib dirs in server.json are resolved relative to the server.json if( serverJSON.keyExists( 'app' ) && serverJSON.app.keyExists( 'libDirs' ) ) { serverJSON.app.libDirs = serverJSON.app.libDirs.listMap( function( thisLibDir ){ @@ -592,7 +592,7 @@ component accessors="true" singleton { } // relative lib dirs in config setting server defaults are resolved relative to the web root if( defaults.keyExists( 'app' ) && defaults.app.keyExists( 'libDirs' ) && len( defaults.app.libDirs ) ) { - // For each lib dir in the list, resolve the path, but only keep it if the folder actually exists. + // For each lib dir in the list, resolve the path, but only keep it if the folder actually exists. // This allows for "optional" global lib dirs. // listReduce starts with an initial value of "" and aggregates the new list, onluy appending the items it wants to keep defaults.app.libDirs = defaults.app.libDirs.listReduce( function( thisLibDirs, thisLibDir ){ @@ -607,61 +607,61 @@ component accessors="true" singleton { } // Global defauls are always added on top of whatever is specified by the user or server.json serverInfo.libDirs = ( serverProps.libDirs ?: serverJSON.app.libDirs ?: '' ).listAppend( defaults.app.libDirs ); - + serverInfo.cfengine = serverProps.cfengine ?: serverJSON.app.cfengine ?: defaults.app.cfengine; - + serverInfo.restMappings = serverProps.restMappings ?: serverJSON.app.restMappings ?: defaults.app.restMappings; // relative rewrite config path in server.json is resolved relative to the server.json if( isDefined( 'serverJSON.app.WARPath' ) && len( serverJSON.app.WARPath ) ) { serverJSON.app.WARPath = fileSystemUtil.resolvePath( serverJSON.app.WARPath, defaultServerConfigFileDirectory ); } - if( isDefined( 'defaults.app.WARPath' ) && len( defaults.app.WARPath ) ) { defaults.app.WARPath = fileSystemUtil.resolvePath( defaults.app.WARPath, defaultwebroot ); } + if( isDefined( 'defaults.app.WARPath' ) && len( defaults.app.WARPath ) ) { defaults.app.WARPath = fileSystemUtil.resolvePath( defaults.app.WARPath, defaultwebroot ); } serverInfo.WARPath = serverProps.WARPath ?: serverJSON.app.WARPath ?: defaults.app.WARPath; - + // relative rewrite config path in server.json is resolved relative to the server.json if( isDefined( 'serverJSON.app.serverHomeDirectory' ) && len( serverJSON.app.serverHomeDirectory ) ) { serverJSON.app.serverHomeDirectory = fileSystemUtil.resolvePath( serverJSON.app.serverHomeDirectory, defaultServerConfigFileDirectory ); } - if( isDefined( 'defaults.app.serverHomeDirectory' ) && len( defaults.app.serverHomeDirectory ) ) { defaults.app.serverHomeDirectory = fileSystemUtil.resolvePath( defaults.app.serverHomeDirectory, defaultwebroot ); } + if( isDefined( 'defaults.app.serverHomeDirectory' ) && len( defaults.app.serverHomeDirectory ) ) { defaults.app.serverHomeDirectory = fileSystemUtil.resolvePath( defaults.app.serverHomeDirectory, defaultwebroot ); } serverInfo.serverHomeDirectory = serverProps.serverHomeDirectory ?: serverJSON.app.serverHomeDirectory ?: defaults.app.serverHomeDirectory; - + // These are already hammered out above, so no need to go through all the defaults. serverInfo.serverConfigFile = defaultServerConfigFile; serverInfo.name = defaultName; serverInfo.webroot = defaultwebroot; - + if( serverInfo.debug ) { consoleLogger.info( "start server in - " & serverInfo.webroot ); consoleLogger.info( "server name - " & serverInfo.name ); - consoleLogger.info( "server config file - " & defaultServerConfigFile ); - } - + consoleLogger.info( "server config file - " & defaultServerConfigFile ); + } + if( !len( serverInfo.WARPath ) && !len( serverInfo.cfengine ) ) { // Turn 1.2.3.4 into 1.2.3+4 serverInfo.cfengine = 'lucee@' & reReplace( server.lucee.version, '([0-9]*.[0-9]*.[0-9]*)(.)([0-9]*)', '\1+\3' ); } - + if( serverInfo.cfengine.endsWith( '@' ) ) { serverInfo.cfengine = left( serverInfo.cfengine, len( serverInfo.cfengine ) - 1 ); } - + var launchUtil = java.LaunchUtil; - + // Default java agent for embedded Lucee engine var javaagent = serverinfo.cfengine contains 'lucee' ? '-javaagent:#libdir#/lucee-inst.jar' : ''; - + // Regardless of a custom server home, this is still used for various temp files and logs serverinfo.customServerFolder = getCustomServerFolder( serverInfo ); directoryCreate( serverinfo.customServerFolder, true, true ); - + // Not sure what Runwar does with this, but it wants to know what CFEngine we're starting (if we know) var CFEngineName = ''; CFEngineName = serverinfo.cfengine contains 'lucee' ? 'lucee' : CFEngineName; CFEngineName = serverinfo.cfengine contains 'railo' ? 'railo' : CFEngineName; CFEngineName = serverinfo.cfengine contains 'adobe' ? 'adobe' : CFEngineName; CFEngineName = serverinfo.warPath contains 'adobe' ? 'adobe' : CFEngineName; - + var processName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ); - + // As long as there's no WAR Path, let's install the engine to use. if( serverInfo.WARPath == '' ){ - + // This will install the engine war to start, possibly downloading it first var installDetails = serverEngineService.install( cfengine=serverInfo.cfengine, basedirectory=serverinfo.customServerFolder, serverInfo=serverInfo, serverHomeDirectory=serverInfo.serverHomeDirectory ); serverInfo.serverHomeDirectory = installDetails.installDir; @@ -671,21 +671,21 @@ component accessors="true" singleton { serverInfo.consolelogPath = serverInfo.logdir & '/server.out.txt'; serverInfo.engineName = installDetails.engineName; serverInfo.engineVersion = installDetails.version; - + // This is for one-time setup tasks on first install - if( installDetails.initialInstall ) { + if( installDetails.initialInstall ) { // Make current settings available to package scripts setServerInfo( serverInfo ); - + // This interception point can be used for additional configuration of the engine before it actually starts. interceptorService.announceInterception( 'onServerInstall', { serverInfo=serverInfo, installDetails=installDetails } ); } - + // If Lucee server, set the java agent if( serverInfo.cfengine contains "lucee" ) { // Detect Lucee 4.x if( installDetails.version.listFirst( '.' ) < 5 ) { - javaagent = '-javaagent:#serverInfo.serverHomeDirectory#/WEB-INF/lib/lucee-inst.jar'; + javaagent = '-javaagent:#serverInfo.serverHomeDirectory#/WEB-INF/lib/lucee-inst.jar'; } else { // Lucee 5+ doesn't need the Java agent javaagent = ''; @@ -695,32 +695,32 @@ component accessors="true" singleton { if( serverInfo.cfengine contains "railo" ) { javaagent = '-javaagent:#serverInfo.serverHomeDirectory#/WEB-INF/lib/railo-inst.jar'; } - - // Add in "/cf_scripts" alias for 2016+ servers if the /cf_scripts folder exists in the war we're starting and there isn't already an alias + + // Add in "/cf_scripts" alias for 2016+ servers if the /cf_scripts folder exists in the war we're starting and there isn't already an alias // for this. I'm specifically not checking the engine name and version so this will work on regular Adobe wars and be future proof. if( directoryExists( serverInfo.serverHomeDirectory & '/cf_scripts' ) && !serverInfo.aliases.keyExists( '/cf_scripts' ) ) { serverInfo.aliases[ '/cf_scripts' ] = serverInfo.serverHomeDirectory & '/cf_scripts'; } - + // The process native name var processName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ) & ' [' & listFirst( serverinfo.cfengine, '@' ) & ' ' & installDetails.version & ']'; var displayServerName = ( serverInfo.name is "" ? "CommandBox" : serverInfo.name ); var displayEngineName = listFirst( serverinfo.cfengine, '@' ) & ' ' & installDetails.version; - + // This is a WAR } else { // If WAR is a file if( fileExists( serverInfo.WARPath ) ){ // It will be extracted into a folder named after the file serverInfo.serverHomeDirectory = reReplaceNoCase( serverInfo.WARPath, '(.*)(\.zip|\.war)', '\1' ); - + // Expand the war if it doesn't exist or we're forcing if( !directoryExists( serverInfo.serverHomeDirectory ) || ( serverProps.force ?: false ) ) { consoleLogger.info( "Exploding WAR archive..."); directoryCreate( serverInfo.serverHomeDirectory, true, true ); zip action="unzip" file="#serverInfo.WARPath#" destination="#serverInfo.serverHomeDirectory#" overwrite="true"; } - + // If WAR is a folder } else { // Just use it @@ -730,16 +730,16 @@ component accessors="true" singleton { serverInfo.logdir = serverinfo.customServerFolder & "/logs"; serverInfo.consolelogPath = serverInfo.logdir & '/server.out.txt'; } - + // Find the correct tray icon for this server if( !len( serverInfo.trayIcon ) ) { var iconSize = fileSystemUtil.isWindows() ? '-32px' : ''; - if( CFEngineName contains "lucee" ) { + if( CFEngineName contains "lucee" ) { serverInfo.trayIcon = '/commandbox/system/config/server-icons/trayicon-lucee#iconSize#.png'; } else if( CFEngineName contains "railo" ) { serverInfo.trayIcon = '/commandbox/system/config/server-icons/trayicon-railo#iconSize#.png'; } else if( CFEngineName contains "adobe" ) { - + if( listFirst( serverInfo.engineVersion, '.' ) == 9 ) { serverInfo.trayIcon = '/commandbox/system/config/server-icons/trayicon-cf09#iconSize#.png'; } else if( listFirst( serverInfo.engineVersion, '.' ) == 10 ) { @@ -751,17 +751,17 @@ component accessors="true" singleton { } else { serverInfo.trayIcon = '/commandbox/system/config/server-icons/trayicon-cf2016#iconSize#.png'; } - + } - } - + } + // Default tray icon - serverInfo.trayIcon = ( len( serverInfo.trayIcon ) ? serverInfo.trayIcon : '/commandbox/system/config/server-icons/trayicon.png' ); + serverInfo.trayIcon = ( len( serverInfo.trayIcon ) ? serverInfo.trayIcon : '/commandbox/system/config/server-icons/trayicon.png' ); serverInfo.trayIcon = expandPath( serverInfo.trayIcon ); - + // Set default options for all servers // TODO: Don't overwrite existing options with the same label. - + /* serverInfo.trayOptions.prepend( { "label":"Advanced", @@ -771,7 +771,7 @@ component accessors="true" singleton { { "label" : "PID: ${runwar.PID}", "disabled" : true, 'checkbox': true, "image" : expandPath('/commandbox/system/config/server-icons/info.png' ) } ] } );*/ - + if( CFEngineName contains "lucee" ) { serverInfo.trayOptions.prepend( { 'label':'Open Web Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/lucee/admin/web.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/web_settings.png' ) } ); serverInfo.trayOptions.prepend( { 'label':'Open Server Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/lucee/admin/server.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/server_settings.png' ) } ); @@ -781,27 +781,27 @@ component accessors="true" singleton { } else if( CFEngineName contains "adobe" ) { serverInfo.trayOptions.prepend( { 'label':'Open Server Admin', 'action':'openbrowser', 'url':'http://${runwar.host}:${runwar.port}/CFIDE/administrator/enter.cfm', 'image' : expandPath('/commandbox/system/config/server-icons/server_settings.png' ) } ); } - + serverInfo.trayOptions.prepend( { 'label':'Open Browser', 'action':'openbrowser', 'url': serverInfo.openbrowserURL, 'image' : expandPath('/commandbox/system/config/server-icons/home.png' ) } ); /* serverInfo.trayOptions.prepend( { 'label' : 'Restart Server', 'hotkey':'R', 'action' : 'restartserver', 'image': expandPath('/commandbox/system/config/server-icons/home.png' ) } ); - */ + */ serverInfo.trayOptions.prepend( { 'label':'Stop Server', 'action':'stopserver', 'image' : expandPath('/commandbox/system/config/server-icons/stop.png' ) } ); //serverInfo.trayOptions.prepend( { 'label': displayServerName, 'disabled':true, 'image' : expandPath('/commandbox/system/config/server-icons/info.png' ) } ); - + // This is due to a bug in RunWar not creating the right directory for the logs directoryCreate( serverInfo.logDir, true, true ); - + // Make current settings available to package scripts setServerInfo( serverInfo ); interceptorService.announceInterception( 'onServerStart', { serverInfo=serverInfo } ); - + // Turn struct of aliases into a comma-delimited list, plus resolve relative paths. // "/foo=C:\path,/bar=C:\another/path" var CLIAliases = ''; for( var thisAlias in serverInfo.aliases ) { CLIAliases = CLIAliases.listAppend( thisAlias & '=' & fileSystemUtil.resolvePath( serverInfo.aliases[ thisAlias ], serverInfo.webroot ) ); } - + // Turn struct of errorPages into a comma-delimited list. // --error-pages="404=/path/to/404.html,500=/path/to/500.html,1=/path/to/default.html" var errorPages = ''; @@ -815,7 +815,7 @@ component accessors="true" singleton { tmp &= thisPath.startsWith( '/' ) ? thisPath : '/' & thisPath; errorPages = errorPages.listAppend( tmp ); } - + // Serialize tray options and write to temp file var trayOptionsPath = serverinfo.customServerFolder & '/trayOptions.json'; var trayJSON = { @@ -827,10 +827,10 @@ component accessors="true" singleton { fileWrite( trayOptionsPath, serializeJSON( trayJSON ) ); var background = !(serverProps.console ?: false); // The java arguments to execute: Shared server, custom web configs - + // This is an array of tokens to send to the process builder var args = []; - + // "borrow" the CommandBox commandline parser to tokenize the JVM args. Not perfect, but close. Handles quoted values with spaces. var argTokens = parser.tokenizeInput( serverInfo.JVMargs ) .map( function( i ){ @@ -839,16 +839,16 @@ component accessors="true" singleton { }); // Add in heap size and java agent argTokens.append( '-Xmx#serverInfo.heapSize#m' ); - + if( val( serverInfo.minHeapSize ) ) { if( serverInfo.minHeapSize > serverInfo.heapSize ) { consoleLogger.warn( 'Your JVM min heap size [#serverInfo.minHeapSize#] is set larger than your max size [#serverInfo.heapSize#]! Reducing the Min to prevent errors.' ); } argTokens.append( '-Xms#min( serverInfo.minHeapSize, serverInfo.heapSize )#m' ); } - + if( len( trim( javaAgent ) ) ) { argTokens.append( javaagent ); } - + args .append( '-jar' ).append( variables.jarPath ) .append( '--background=#background#' ) @@ -862,29 +862,29 @@ component accessors="true" singleton { .append( '--server-name' ).append( serverInfo.name ) .append( '--tray-icon' ).append( serverInfo.trayIcon ) .append( '--tray-config' ).append( trayOptionsPath ) - .append( '--tray-enable' ).append( serverInfo.trayEnable ) + .append( '--tray-enable' ).append( serverInfo.trayEnable ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) .append( '--proxy-peeraddress' ).append( 'true' ) .append( serverInfo.runwarArgs.listToArray( ' ' ), true ); - + if( serverInfo.debug ) { // Debug is getting turned on any time I include the --debug flag regardless of whether it's true or false. args.append( '--debug' ).append( serverInfo.debug ); } - - // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. + + // Runwar will blow up if there isn't a parameter supplied, so I can't pass an empty string. if( len( serverInfo.restMappings ) ) { args.append( '--servlet-rest-mappings' ).append( serverInfo.restMappings ); } else { // This effectively disables it (assuming there's not a real directory or route called "___disabled___") but it's janky args.append( '--servlet-rest-mappings' ).append( '___DISABLED___' ); } - + if( serverInfo.trace ) { args.append( '--log-level' ).append( 'TRACE' ); } - + if( len( errorPages ) ) { args.append( '--error-pages' ).append( errorPages ); } @@ -897,8 +897,8 @@ component accessors="true" singleton { if( len( CLIAliases ) ) { args.append( '--dirs' ).append( CLIAliases ); } - - + + // If background, wrap up JVM args to pass through to background servers. "Real" JVM args must come before Runwar args if( background ) { var argString = argTokens.toList( ';' ); @@ -909,9 +909,9 @@ component accessors="true" singleton { } else { argTokens.each( function(i) { args.prepend( i ); } ); } - + args.append( '-war' ); - + // Starting a WAR if (serverInfo.WARPath != "" ) { args.append( serverInfo.WARPath ); @@ -919,7 +919,7 @@ component accessors="true" singleton { } else { args.append( serverInfo.webroot ); } - + // Custom web.xml (doesn't work right now) if ( Len( Trim( serverInfo.webXml ) ) && false ) { args.append( '--web-xml-path' ).append( serverInfo.webXml ); @@ -927,12 +927,12 @@ component accessors="true" singleton { } else { args.append( '--web-xml-path' ).append( '#serverInfo.serverHomeDirectory#/WEB-INF/web.xml' ); } - + if( len( serverInfo.libDirs ) ) { // Have to get rid of empty list elements args.append( '--lib-dirs' ).append( serverInfo.libDirs.listChangeDelims( ',', ',' ) ); } - + // Incorporate SSL to command if( serverInfo.SSLEnable ){ args @@ -946,20 +946,20 @@ component accessors="true" singleton { .append( '--ssl-key' ).append( serverInfo.SSLKeyFile ); // Not all certs require a password if( serverInfo.SSLKeyPass.len() ) { - args.append( '--ssl-keypass' ).append( serverInfo.SSLKeyPass ); + args.append( '--ssl-keypass' ).append( serverInfo.SSLKeyPass ); } } - + // Incorporate rewrites to command args.append( '--urlrewrite-enable' ).append( serverInfo.rewritesEnable ); if( len( serverInfo.rewritesStatusPath ) ) { - args.append( '--urlrewrite-statuspath' ).append( serverInfo.rewritesStatusPath ); + args.append( '--urlrewrite-statuspath' ).append( serverInfo.rewritesStatusPath ); } // A setting of 0 reloads on every request if( len( serverInfo.rewritesConfigReloadSeconds ) ) { - args.append( '--urlrewrite-check' ).append( serverInfo.rewritesConfigReloadSeconds ); + args.append( '--urlrewrite-check' ).append( serverInfo.rewritesConfigReloadSeconds ); } - + // Basic auth if( serverInfo.basicAuthEnable && serverInfo.basicAuthUsers.count() ) { // Escape commas and equals with backslash @@ -969,9 +969,9 @@ component accessors="true" singleton { thisBasicAuthUsers = thisBasicAuthUsers.listAppend( '#sanitizeBA( i )#=#sanitizeBA( serverInfo.basicAuthUsers[ i ] )#' ); } ); // user=pass,user2=pass2 - args.append( '--basicauth-users' ).append( thisBasicAuthUsers ); + args.append( '--basicauth-users' ).append( thisBasicAuthUsers ); } - + if( serverInfo.rewritesEnable ){ if( !fileExists(serverInfo.rewritesConfig) ){ consoleLogger.error( '.' ); @@ -985,12 +985,12 @@ component accessors="true" singleton { serverInfo.dateLastStarted = now(); serverInfo.status = "starting"; setServerInfo( serverInfo ); - + if( serverInfo.debug ) { var cleanedArgs = cr & ' ' & trim( reReplaceNoCase( args.toList( ' ' ), ' (-|"-)', cr & ' \1', 'all' ) ); consoleLogger.debug("Server start command: #serverInfo.javaHome# #cleanedargs#"); } - + // needs to be unique in each run to avoid errors var threadName = 'server#hash( serverInfo.webroot )##createUUID()#'; // Construct a new process object @@ -1002,38 +1002,38 @@ component accessors="true" singleton { processBuilder.redirectErrorStream( true ); // Kick off actual process variables.process = processBuilder.start(); - + // She'll be coming 'round the mountain when she comes... consoleLogger.warn( "The server for #serverInfo.webroot# is starting on #serverInfo.host#:#serverInfo.port#..." ); - + // If the user is running a one-off command to start a server or specified the debug flag, stream the output and wait until it's finished starting. var interactiveStart = ( shell.getShellType() == 'command' || serverInfo.debug || !background ); - + // Spin up a thread to capture the standard out and error from the server thread name="#threadName#" interactiveStart=interactiveStart serverInfo=serverInfo args=args startTimeout=serverInfo.startTimeout { try{ - + // save server info and persist serverInfo.statusInfo = { command:serverInfo.javaHome, arguments:attributes.args.toList( ' ' ), result:'' }; serverInfo.status="starting"; setServerInfo( serverInfo ); - + var startOutput = createObject( 'java', 'java.lang.StringBuilder' ).init(); var inputStream = process.getInputStream(); var inputStreamReader = createObject( 'java', 'java.io.InputStreamReader' ).init( inputStream ); var bufferedReader = createObject( 'java', 'java.io.BufferedReader' ).init( inputStreamReader ); var print = wirebox.getInstance( "PrintBuffer" ); - + var line = bufferedReader.readLine(); while( !isNull( line ) ){ // Clean log4j cruft from line line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger - processoutput: ', '' ); line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger lib: ', 'Runwar: ' ); line = reReplaceNoCase( line, '^.* (INFO|DEBUG|ERROR|WARN) RunwarLogger - ', 'Runwar: ' ); - + // Build up our output startOutput.append( line & chr( 13 ) & chr( 10 ) ); - + // output it if we're being interactive if( attributes.interactiveStart ) { print @@ -1042,16 +1042,16 @@ component accessors="true" singleton { } line = bufferedReader.readLine(); } // End of inputStream - + // When we require Java 8 for CommandBox, we can pass a timeout to waitFor(). var exitCode = process.waitFor(); - + if( exitCode == 0 ) { - serverInfo.status="running"; + serverInfo.status="running"; } else { serverInfo.status="unknown"; } - + } catch( any e ) { logger.error( e.message & ' ' & e.detail, e.stacktrace ); serverInfo.status="unknown"; @@ -1064,17 +1064,17 @@ component accessors="true" singleton { setServerInfo( serverInfo ); } } - + // Block until the process ends and the streaming output thread above is done. if( interactiveStart ) { - + if( !background ) { try { - + while( true ) { // Wipe out prompt so it doesn't redraw if the user hits enter shell.getReader().setPrompt( '' ); - + // Detect user pressing Ctrl-C // Any other characters captured will be ignored var line = shell.getReader().readLine(); @@ -1084,10 +1084,10 @@ component accessors="true" singleton { consoleLogger.error( 'To exit press Ctrl-C or "q" followed the enter key.' ); } } - + // user wants to exit, they've pressed Ctrl-C } catch ( jline.console.UserInterruptException e ) { - // Something bad happened + // Something bad happened } catch ( Any e ) { logger.error( '#e.message# #e.detail#' , e.stackTrace ); consoleLogger.error( '#e.message##chr(10)##e.detail#' ); @@ -1095,24 +1095,24 @@ component accessors="true" singleton { } finally { consoleLogger.error( 'Stopping server...' ); shell.setPrompt(); - process.destroy(); + process.destroy(); } } - + thread action="join" name="#threadName#"; } - + } /** * Unified logic to resolve a server given an optional name, directory, and server.json path. * Returns resolved name, webroot, serverConfigFile, serverInfo from the last start and serverJSON * Use this for all 'server' commands that let a user specify the server they want by convention (CWD), - * name, directory, or server.json path. - * + * name, directory, or server.json path. + * * @serverProps A struct that can contains name, directory, and/or serverConfigFile * - * @returns a struct containing + * @returns a struct containing * - defaultName * - defaultwebroot * - defaultServerConfigFile @@ -1124,7 +1124,7 @@ component accessors="true" singleton { required struct serverProps ) { var locDebug = serverProps.debug ?: false; - + // As a convenient shorcut, allow the serverConfigFile to be passed via the name parameter. var tmpName = serverProps.name ?: ''; var tmpNameResolved = fileSystemUtil.resolvePath( tmpName ); @@ -1134,7 +1134,7 @@ component accessors="true" singleton { serverProps.serverConfigFile = tmpNameResolved; structDelete( serverProps, 'name' ); } - + // If a specific server.json file path was passed, use it. if( len( serverProps.serverConfigFile ?: '' ) ) { var defaultServerConfigFile = serverProps.serverConfigFile; @@ -1150,7 +1150,7 @@ component accessors="true" singleton { // If starting by name and we guessed the server.json file name, this serverJSON maybe replaced later by another saved file. if( locDebug ) { consoleLogger.debug("Looking for server JSON file by convention: #defaultServerConfigFile#"); } var serverJSON = readServerJSON( defaultServerConfigFile ); - + // Get the web root out of the server.json, if specified and make it relative to the actual server.json file. // If user gave us a webroot, we use it first. if( len( arguments.serverProps.directory ?: '' ) ) { @@ -1175,54 +1175,54 @@ component accessors="true" singleton { } else { // Don't do a final guess at the name yet so we don't affect the server discovery below. var defaultName = ''; - } - + } + // Discover by shortname or server and get server info var serverInfo = getServerInfoByDiscovery( directory = defaultwebroot, name = defaultName, serverConfigFile = serverProps.serverConfigFile ?: '' // Since this takes precendence, I only want to use it if it was actually specified ); - + // If we found a server, set our name. if( len( serverInfo.name ?: '' ) ) { defaultName = serverInfo.name; - } + } var serverIsNew = false; // If it wasn't found, create new server info using defaults if( structIsEmpty( serverInfo ) ){ - + if( !len( defaultName ) ) { // If there is still no name, default to the current directory // TODO: I don't care for this because it creates conflicts since many servers could have the name "webroot" on one machine. defaultName = replace( listLast( defaultwebroot, "\/" ), ':', ''); - + // Don't overlap an existing server name var originalName = defaultName; var nameCounter = 1; while( structCount( getServerInfoByName( defaultName ) ) ) { - defaultName = originalName & ++nameCounter; + defaultName = originalName & ++nameCounter; } - + } - + // We need a new entry serverIsNew = true; serverInfo = getServerInfo( defaultwebroot, defaultName ); } - + // If the user didn't provide an explicit config file and it turns out last time we started a server by this name, we used a different // config, let's re-read out that config JSON file to use instead of the default above. - if( !len( serverProps.serverConfigFile ?: '' ) - && len( serverInfo.serverConfigFile ?: '' ) + if( !len( serverProps.serverConfigFile ?: '' ) + && len( serverInfo.serverConfigFile ?: '' ) && serverInfo.serverConfigFile != defaultServerConfigFile ) { - + // Get server descriptor again if( locDebug ) { consoleLogger.debug("Switching to the last-used server JSON file for this server: #serverInfo.serverConfigFile#"); } serverJSON = readServerJSON( serverInfo.serverConfigFile ); defaultServerConfigFile = serverInfo.serverConfigFile; - + // Now that we changed server JSONs, we need to recalculate the webroot. if( locDebug ) { consoleLogger.debug("Recalculating web root based on new server JSON file."); } // If user gave us a webroot, we use it first. @@ -1238,9 +1238,9 @@ component accessors="true" singleton { var defaultwebroot = fileSystemUtil.resolvePath( getDirectoryFromPath( serverInfo.serverConfigFile ) ); if( locDebug ) { consoleLogger.debug("webroot defaulted to location of server's JSON file: #defaultwebroot#"); } } - + } - + // By now we've figured out the name, webroot, and serverConfigFile for this server. // Also return the serverInfo of the last values the server was started with (if ever) // and the serverJSON setting for the server, if they exist. @@ -1261,9 +1261,9 @@ component accessors="true" singleton { * @returns struct of [ error, messages ] **/ struct function stop( required struct serverInfo ){ - + interceptorService.announceInterception( 'onServerStop', { serverInfo=serverInfo } ); - + var launchUtil = java.LaunchUtil; var stopsocket = arguments.serverInfo.stopsocket; var args = "-jar ""#variables.jarPath#"" -stop --stop-port #val( stopsocket )# -host #arguments.serverInfo.host# --background false"; @@ -1292,36 +1292,36 @@ component accessors="true" singleton { function forget( required struct serverInfo ){ var servers = getServers(); var serverdir = getCustomServerFolder( arguments.serverInfo ); - + interceptorService.announceInterception( 'preServerForget', { serverInfo=serverInfo } ); - + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { - + // try to delete interal server dir server if( directoryExists( serverDir ) ){ directoryDelete( serverdir, true ); } - + // Server home may be custom, so delete it as well if( len( serverInfo.serverHomeDirectory ) && directoryExists( serverInfo.serverHomeDirectory ) ){ directoryDelete( serverInfo.serverHomeDirectory, true ); } - - + + } catch( any e ) { consoleLogger.error( '#e.message##chr(10)#Did you leave the server running? ' ); logger.error( '#e.message# #e.detail#' , e.stackTrace ); return serverInfo.name & ' not deleted.'; } - + // Remove from config structDelete( servers, arguments.serverInfo.id ); setServers( servers ); - + interceptorService.announceInterception( 'postServerForget', { serverInfo=serverInfo } ); - + // return message return "Poof! Wiped out server " & serverInfo.name; } @@ -1387,22 +1387,22 @@ component accessors="true" singleton { * @serverInfo.hint struct of server info (ports, etc.) **/ function setServerInfo( required struct serverInfo ){ - + var servers = getServers(); var normalizedWebroot = normalizeWebroot( arguments.serverInfo.webroot ); var webrootHash = hash( normalizedWebroot & ucase( arguments.serverInfo.name ) ); arguments.serverInfo.id = webrootHash; - + if( arguments.serverInfo.webroot == "" ){ throw( "The webroot cannot be empty!" ); } servers[ webrootHash ] = serverInfo; // persist back safely - + setServers( servers ); - + } - + function normalizeWebroot( required string webroot ) { if( webroot contains '/' && !webroot.endsWith( '/' ) ) { return webroot & '/'; @@ -1442,7 +1442,7 @@ component accessors="true" singleton { var results = deserializeJSON( fileRead( variables.serverConfig ) ); var updateRequired = false; var serverKeys = results.keyArray(); - + // Loop over each server for some housekeeping for( var thisKey in serverKeys ){ // This server may have gotten deleted already based on the cleanup below. @@ -1456,14 +1456,14 @@ component accessors="true" singleton { thisServer.id = hash( normalizedWebroot & ucase( thisServer.name ) ); updateRequired = true; } - - // Try and clean up orphaned server names that were missing the slash on the path and + + // Try and clean up orphaned server names that were missing the slash on the path and // ended up with a different hash. // I really have no idea how this happens. I can't repro it on-demand. for( var orphanKey in results ){ var orphan = results[ orphanKey ]; // If this is another server with the same name and the same webroot but without a trailing slash... - if( orphan.id != thisServer.id + if( orphan.id != thisServer.id && orphan.name == thisServer.name && ( thisServer.webroot.endsWith( '\' ) || thisServer.webroot.endsWith( '/' ) ) && ( !orphan.webroot.endsWith( '\' ) || !orphan.webroot.endsWith( '/' ) ) @@ -1471,10 +1471,10 @@ component accessors="true" singleton { // ...kill it dead. results.delete( orphanKey ); updateRequired = true; - } + } } - - // Future-proof server info by guaranteeing that all properties will exist in the + + // Future-proof server info by guaranteeing that all properties will exist in the // server object as long as they are defined in the newServerInfoStruct() method. thisServer.append( newServerInfoStruct(), false ); } @@ -1488,13 +1488,13 @@ component accessors="true" singleton { } /** - * Get a server information struct by name or directory. + * Get a server information struct by name or directory. * Returns empty struct if not found. * @directory.hint the directory to find * @name.hint The name to find */ struct function getServerInfoByDiscovery( required directory="", required name="", serverConfigFile="" ){ - + if( len( arguments.serverConfigFile ) ){ var foundServer = getServerInfoByServerConfigFile( arguments.serverConfigFile ); if( structCount( foundServer ) ) { @@ -1502,7 +1502,7 @@ component accessors="true" singleton { } return {}; } - + if( len( arguments.name ) ){ var foundServer = getServerInfoByName( arguments.name ); if( structCount( foundServer ) ) { @@ -1595,14 +1595,14 @@ component accessors="true" singleton { serverInfo.id = webrootHash; serverInfo.webroot = arguments.webroot; serverInfo.name = listLast( arguments.webroot, "\/" ); - + // Don't overlap an existing server name var originalName = serverInfo.name; var nameCounter = 1; while( structCount( getServerInfoByName( serverInfo.name ) ) ) { - serverInfo.name = originalName & ++nameCounter; + serverInfo.name = originalName & ++nameCounter; } - + // Store it in server struct servers[ webrootHash ] = serverInfo; } @@ -1625,7 +1625,7 @@ component accessors="true" singleton { 'statusInfo' : { 'result' : "", 'arguments' : "", - 'command' : "" + 'command' : "" }, 'name' : "", 'logDir' : "", @@ -1647,8 +1647,8 @@ component accessors="true" singleton { 'rewritesConfig' : "", 'basicAuthEnable' : true, 'basicAuthUsers' : {}, - 'heapSize' : 512, - 'minHeapSize' : 0, + 'heapSize' : 512, + 'minHeapSize' : 0, 'javaHome' : '', 'directoryBrowsing' : true, 'JVMargs' : "", @@ -1677,7 +1677,7 @@ component accessors="true" singleton { if( fileExists( path ) ) { var fileContents = fileRead( path ); if( isJSON( fileContents ) ) { - return deserializeJSON( fileContents ); + return deserializeJSON( fileContents ); } else { consoleLogger.warn( 'Warning: File is not valid JSON. [#path#]' ); return {}; @@ -1693,26 +1693,26 @@ component accessors="true" singleton { function saveServerJSON( required string configFilePath, required struct data ) { var oldJSON = ''; if( fileExists( arguments.configFilePath ) ) { - oldJSON = fileRead( arguments.configFilePath ); + oldJSON = fileRead( arguments.configFilePath ); } var newJSON = formatterUtil.formatJSON( serializeJSON( arguments.data ) ); // Try to prevent bunping the date modified for no reason if( oldJSON != newJSON ) { directoryCreate( getDirectoryFromPath( arguments.configFilePath ), true, true ); - fileWrite( arguments.configFilePath, newJSON ); + fileWrite( arguments.configFilePath, newJSON ); } } - + /** * Dynamic completion for property name based on contents of server.json * @directory web root * @all Pass false to ONLY suggest existing setting names. True will suggest all possible settings. * @asSet Pass true to add = to the end of the options - */ + */ function completeProperty( required directory, all=false, asSet=false ) { // Get all config settings currently set var props = JSONService.addProp( [], '', '', readServerJSON( arguments.directory & '/server.json' ) ); - + // If we want all possible options... if( arguments.all ) { // ... Then add them in @@ -1731,7 +1731,7 @@ component accessors="true" singleton { if( asSet ) { props = props.map( function( i ){ return i &= '='; } ); } - - return props; - } -} + + return props; + } +} \ No newline at end of file diff --git a/src/cfml/system/util/ANSIConsoleAppender.cfc b/src/cfml/system/util/ANSIConsoleAppender.cfc index 41259fab4..c5ac5e880 100644 --- a/src/cfml/system/util/ANSIConsoleAppender.cfc +++ b/src/cfml/system/util/ANSIConsoleAppender.cfc @@ -1,4 +1,4 @@ -/** +/** ******************************************************************************** Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp www.coldbox.org | www.luismajano.com | www.ortussolutions.com @@ -8,13 +8,13 @@ Author : Brad Wood, Luis Majano Date : 07/22/2014 Description : A logger for outputting ANSI-formmatted text to the console - for use with CommandBox. - + for use with CommandBox. + Properties: - none */ component extends="wirebox.system.logging.AbstractAppender" { - + /** * @name.hint The unique name for this appender. * @properties.hint A map of configuration properties for the appender @@ -29,12 +29,12 @@ component extends="wirebox.system.logging.AbstractAppender" { variables.logLevels = createObject("component","wirebox.system.logging.LogLevels"); return this; } - + function logMessage( required logEvent ) { var loge = arguments.logEvent; var entry = ""; - + if( hasCustomLayout() ){ entry = getCustomLayout().format( loge ); } else { @@ -43,7 +43,7 @@ component extends="wirebox.system.logging.AbstractAppender" { entry = ''; } } - + // Log message switch( loge.getseverity() ) { case logLevels.FATAL: case logLevels.ERROR: @@ -55,23 +55,23 @@ component extends="wirebox.system.logging.AbstractAppender" { case logLevels.INFO: print().greenLine( entry ).toConsole(); break; - default: + default: print().line( entry ).toConsole(); } // Log Extra Info as a string var extraInfo = loge.getExtraInfoAsString(); if( len( extraInfo ) ){ - print().line( loge.getExtraInfo().toString() ).toConsole(); + print().line( loge.getExtraInfo().toString() ).toConsole(); } } - + function print() { if( !structKeyExists( variables, 'printBuffer' ) ){ // Appenders are created by WireBox, so we can't DI. variables.printBuffer = application.wireBox.getInstance( 'PrintBuffer' ); - } + } return variables.printBuffer; } - + } \ No newline at end of file diff --git a/src/cfml/system/util/CommandDSL.cfc b/src/cfml/system/util/CommandDSL.cfc index 23f8689a9..899d5983a 100644 --- a/src/cfml/system/util/CommandDSL.cfc +++ b/src/cfml/system/util/CommandDSL.cfc @@ -5,14 +5,14 @@ ******************************************************************************** * @author Brad Wood, Luis Majano * -* I am a helper object for executing commands via a DSL. Create me and call my +* I am a helper object for executing commands via a DSL. Create me and call my * methods to build up a command chain, then .run() will execute me. * * I am a transient and hold state. Do not share me with your friends. * */ component accessors=true { - + property name='command'; property name='params'; property name='piped'; @@ -20,23 +20,23 @@ component accessors=true { property name='append'; property name='overwrite'; property name='workingDirectory'; - - + + // DI property name='parser' inject='parser'; property name='shell' inject='shell'; - + /** * Create a new, executable command * * @name.hint I am the command to execute **/ function init( name ) { - + if( !structKeyExists( arguments, 'name' ) ) { throw( 'Command name not provided' ); } - + setCommand( arguments.name ); setPiped( [] ); setParams( [] ); @@ -46,16 +46,16 @@ component accessors=true { setWorkingDirectory( '' ); return this; } - + /** * Add params to the command **/ function params() { - + setParams( arguments ); return this; } - + /** * Convert params to named or positional arguments **/ @@ -64,7 +64,7 @@ component accessors=true { if( !arraylen( getParams() ) ) { return processedParams; } - + // Positional params if( isNumeric( listFirst( structKeyList( getParams() ) ) ) ) { for( var param in getParams() ) { @@ -76,64 +76,64 @@ component accessors=true { processedParams.append( '#param#="#parser.escapeArg( getParams()[ param ] )#"' ); } } - + return processedParams; } - + /** - * Add flags to the command + * Add flags to the command **/ function flags() { - + for( var param in arguments ) { var thisParam = arguments[ param ]; getFlags().append( ( thisParam.startsWith( '--' ) ? '' : '--' ) & thisParam ); } - + return this; } - + /** - * Append results to file + * Append results to file **/ function append( required path ) { setAppend( '"#parser.escapeArg( arguments.path )#"' ); return this; } - + /** - * overwrite file with results + * overwrite file with results **/ function overwrite( required path ) { setOverwrite( '"#parser.escapeArg( arguments.path )#"' ); return this; } - + /** - * Sets the directory to run the command in + * Sets the directory to run the command in **/ function inWorkingDirectory( required workingDirectory ) { setWorkingDirectory( arguments.workingDirectory ); return this; } - + /** * Pipe additional commands **/ function pipe( commandDSL ) { - + if( !structKeyExists( arguments, 'commandDSL' ) ) { throw( 'Please pass a commandDSL to pipe' ); } - + if( !isObject( arguments.commandDSL ) ) { throw( 'What you passed to pipe isn''t a commandDSL instance.' ); } - + getPiped().append( arguments.commandDSL ); return this; } - + /** * Turn this CFC into an array of command tokens **/ @@ -141,65 +141,65 @@ component accessors=true { var tokens = []; // Break the command name on the spaces tokens.append( listToArray( getCommand(), ' ' ), true ); - tokens.append( processParams(), true ); + tokens.append( processParams(), true ); tokens.append( getFlags(), true ); - + if( len( getOverwrite() ) ) { tokens.append( '>' ); tokens.append( getOverwrite() ); } - + if( len( getAppend() ) ) { tokens.append( '>>' ); tokens.append( getAppend() ); } - + for( var piperton in getPiped() ) { tokens.append( '|' ); tokens.append( piperton.getTokens(), true ); } - + return tokens; } - + /** * Turn this CFC into a string representation **/ string function getCommandString() { return getTokens().toList( ' ' ); } - + /** * Run this command **/ string function run( returnOutput=false, string piped, boolean echo=false ) { - + if( arguments.echo ) { shell.callCommand( 'echo "#parser.escapeArg( getCommandString() )#"' ); } - + var originalCWD = shell.getPWD(); if( getWorkingDirectory().len() ) { shell.cd( getWorkingDirectory() ); } - + if( structkeyExists( arguments, 'piped' ) ) { var result = shell.callCommand( getTokens(), arguments.returnOutput, arguments.piped ); } else { var result = shell.callCommand( getTokens(), arguments.returnOutput ); } - + var postCommandCWD = shell.getPWD(); - + // Only change back if the executed command didn't change the CWD if( getWorkingDirectory().len() && postCommandCWD == getWorkingDirectory() ) { shell.cd( originalCWD ); } - + if( !isNull( local.result ) ) { return local.result; - } - + } + } } \ No newline at end of file diff --git a/src/cfml/system/util/Completor.cfc b/src/cfml/system/util/Completor.cfc index b9247cf2b..c3589f7bc 100644 --- a/src/cfml/system/util/Completor.cfc +++ b/src/cfml/system/util/Completor.cfc @@ -90,30 +90,30 @@ component singleton { var definedParameters = commandInfo.commandReference.parameters; // This is the params the user has entered so far. var passedParameters = commandService.parseParameters( commandInfo.parameters, definedParameters ); - + // For sure we are using named- suggest name or value as necceessary if( structCount( passedParameters.namedParameters ) ) { var leftOver = ''; - + // Still typing if( !buffer.endsWith( ' ' ) ) { - + // grab the last chunk of text from the buffer var leftOver = listLast( buffer, ' ' ); - - // value completion only + + // value completion only if( leftOver contains '=' ) { - + // Param name is bit before the = var paramName = listFirst( leftOver, '=' ); // Everything else, is the value so far var paramSoFar = ''; // There's only a value if somethign was typed after the = if( !leftOver.endsWith( '=' ) ) { - paramSoFar = listLast( leftOver, '=' ); + paramSoFar = listLast( leftOver, '=' ); } - + var paramType = ''; // Now that we have the name, see if we can look up the type for( var param in definedParameters ) { @@ -128,7 +128,7 @@ component singleton { return len( buffer ) - len( paramSoFar ); } - + } // End still typing? @@ -157,13 +157,13 @@ component singleton { // or a single one with flags present } else if( passedParameters.positionalParameters.len() > 1 - || ( passedParameters.positionalParameters.len() == 1 + || ( passedParameters.positionalParameters.len() == 1 && ( buffer.endsWith( ' ' ) || structCount( passedParameters.flags ) ) ) ) { // If the buffer ends with a space, they were done typing the last param if( buffer.endsWith( ' ' ) ) { - + // Loop over remaining possible params and suggest the boolean ones as flags var i = 0; for( var param in definedParameters ) { @@ -181,15 +181,15 @@ component singleton { if( i > passedParameters.positionalParameters.len() && !structKeyExists( passedParameters.flags, param.name )) { // Add the name of the next one in the list. The user will have to backspace and // replace this with their actual param so this may not be that useful. - + candidates.add( param.name & ' ' ); paramValueCompletion( commandInfo, param.name, param.type, '', candidates ); // Bail once we find one break; } } - - arraySort( candidates, 'text' ); + + arraySort( candidates, 'text' ); return len( buffer ); @@ -198,16 +198,16 @@ component singleton { // Make sure defined params actually exist for this if( definedParameters.len() >= passedParameters.positionalParameters.len() ) { - + // If there is a passed positional param or flags if( passedParameters.positionalParameters.len() || structCount( passedParameters.flags ) ) { // grab the last chunk of text from the buffer var partialMatch = listLast( buffer, ' ' ); } - + var thisParam = definedParameters[ passedParameters.positionalParameters.len() ]; paramValueCompletion( commandInfo, thisParam.name, thisParam.type, partialMatch, candidates ); - + // Loop over remaining possible params and suggest the boolean ones as flags var i = 0; for( var param in definedParameters ) { @@ -216,11 +216,11 @@ component singleton { if( i >= passedParameters.positionalParameters.len() && param.type == 'boolean' && !structKeyExists( passedParameters.flags, param.name ) ) { var paramFlagname = '--' & param.name; if( lcase( paramFlagname ).startsWith( lcase( partialMatch ) ) ) { - candidates.add( paramFlagname & ' ' ); + candidates.add( paramFlagname & ' ' ); } } } - + arraySort( candidates, 'text' ); return len( buffer ) - len( partialMatch ); } @@ -250,11 +250,11 @@ component singleton { if( !structKeyExists( passedParameters.flags, param.name ) && ( !len( partialMatch ) || lcase( param.name ).startsWith( lcase( partialMatch ) ) ) ) { candidates.add( param.name & '=' ); } - + // If this param is a boolean that isn't a flag yet, sugguest the --flag version var paramFlagname = '--' & param.name; if( param.type == 'boolean' && !structKeyExists( passedParameters.flags, param.name ) && lcase( paramFlagname ).startsWith( lcase( partialMatch ) ) ) { - candidates.add( paramFlagname & ' ' ); + candidates.add( paramFlagname & ' ' ); } } @@ -263,7 +263,7 @@ component singleton { // Suggest its value paramValueCompletion( commandInfo, thisParam.name, thisParam.type, partialMatch, candidates ); - + arraySort( candidates, 'text' ); return len( buffer ) - len( partialMatch ); @@ -297,7 +297,7 @@ component singleton { private function paramValueCompletion( struct commandInfo, String paramName, String paramType, String paramSoFar, required candidates) { var completorData = commandInfo.commandReference.completor; - + if( structKeyExists( completorData, paramName ) ) { // Add static values if( structKeyExists( completorData[ paramName ], 'options' ) ) { @@ -321,24 +321,24 @@ component singleton { addCandidateIfMatch( "false", paramSoFar, candidates ); break; } - + paramName = lcase( paramName ); - if( paramName.startsWith( 'directory' ) || + if( paramName.startsWith( 'directory' ) || paramName.startsWith( 'destination' ) || paramName.endsWith( 'directory' ) || - paramName.endsWith( 'destination' ) + paramName.endsWith( 'destination' ) ){ - pathCompletion( paramSoFar, candidates, false ); - } else if( paramName.startsWith( 'file' ) || - paramName.endsWith( 'file' ) || + pathCompletion( paramSoFar, candidates, false ); + } else if( paramName.startsWith( 'file' ) || + paramName.endsWith( 'file' ) || paramName.startsWith( 'path' ) || - paramName.endsWith( 'path' ) + paramName.endsWith( 'path' ) ){ pathCompletion( paramSoFar, candidates, true ); } } - + /** * Convience method since calling addAll() directly errors if each value isn't a string * @candidates.hint Java TreeSet object @@ -357,18 +357,18 @@ component singleton { * @type.showFiles Whether to hit files as well as directories **/ private function pathCompletion(String startsWith, required candidates, showFiles=true ) { - + // keep track of the original here so we can put it back like the user had var originalStartsWith = replace( arguments.startsWith, "\", "/", "all" ); // Fully resolve the path. arguments.startsWith = fileSystemUtil.resolvePath( arguments.startsWith ); startsWith = replace( startsWith, "\", "/", "all" ); - + // make sure dirs are suffixed with a trailing slash or we'll strip it off, thinking it's a partial name if( ( originalStartsWith == '' || originalStartsWith.endsWith( '/' ) ) && !startsWith.endsWith( '/' ) ) { startsWith &= '/'; } - + // searchIn strips off partial directories, and has the last complete actual directory for searching. var searchIn = startsWith; // This is the bit at the end that is a partially typed directory or file name @@ -382,7 +382,7 @@ component singleton { partialMatch = replaceNoCase( startsWith, searchIn, '' ); } } - + // Don't even bother if search location doesn't exist if( directoryExists( searchIn ) ) { // Pull a list of paths in there @@ -407,7 +407,7 @@ component singleton { // ...strip it back down to what they typed thisCandidate = replaceNoCase( thisCandidate, startsWith, originalStartsWith ); - + // Finally add this candidate into the list candidates.add( thisCandidate & ( path.type == 'dir' ? '/' : '' ) ); } diff --git a/src/cfml/system/util/Executor.cfc b/src/cfml/system/util/Executor.cfc index 65397b9b1..6753ff951 100644 --- a/src/cfml/system/util/Executor.cfc +++ b/src/cfml/system/util/Executor.cfc @@ -41,11 +41,11 @@ component { * @vars.hint Struct of vars to set so the code can access them */ function runCode( required string code, boolean script=true, required string directory, struct vars = {} ){ - + // Temp file to evaluate var tmpFile = createUUID() & ".cfm"; var tmpFileAbsolute = arguments.directory & "/" & tmpFile; - + // generate cfml command to write to file var CFMLFileContents = ( arguments.script ? "" & arguments.code & "" : arguments.code ); @@ -71,9 +71,9 @@ component { function eval( required string statement, required string directory ){ variables.__statement = arguments.statement; var cfml = 'savecontent variable="variables.__out" { variables.__result = evaluate( variables.__statement ); }'; - + runCode( cfml, true, arguments.directory ); - + if( len( variables.__out ) ) { return variables.__out; } else { diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 43b6bd561..1540ac6f6 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -14,7 +14,7 @@ component accessors="true" singleton { * The os */ property name="os"; - + // DI property name="shell" inject="shell"; property name="logger" inject="logbox:logger:{this}"; @@ -31,48 +31,48 @@ component accessors="true" singleton { * @basePath.hint An expanded base path to resolve the path against. Defaults to CWD. */ function resolvePath( required string path, basePath=shell.pwd() ) { - + try { - + // Load our path into a Java file object so we can use some of its nice utility methods var oPath = createObject( 'java', 'java.io.File' ).init( path ); - + // This tells us if it's a relative path // Note, at this point we don't actually know if it actually even exists yet - + // If we're on windows and the path starts with / or \ if( isWindows() && reFind( '^[\\\/]', path ) ) { - + // Concat it with the drive root in the base path so "/foo" becomes "C:/foo" (if the basepath is C:/etc) oPath = createObject( 'java', 'java.io.File' ).init( listFirst( arguments.basePath, '/\' ) & '/' & path ); - + // If path is "~" // Note, we're supporting this on Windows as well as Linux because it seems useful } else if( path == '~' ) { - + var userHome = createObject( 'java', 'java.lang.System' ).getProperty( 'user.home' ); oPath = createObject( 'java', 'java.io.File' ).init( userHome ); - + // If path starts with "~/something" but not "~foo" (a valid folder name) } else if( reFind( '^~[\\\/]', path ) ) { - + oPath = createObject( 'java', 'java.io.File' ).init( userHome & right( path, len( path ) - 1 ) ); - + } else if( !oPath.isAbsolute() ) { - + // If it's relative, we assume it's relative to the current working directory and make it absolute oPath = createObject( 'java', 'java.io.File' ).init( arguments.basePath & '/' & path ); - + } - + // This will standardize the name and calculate stuff like ../../ return getCanonicalPath( oPath.toString() ); - + } catch ( any e ) { rethrow; return arguments.basePath & '/' & path; } - + } /** @@ -83,7 +83,7 @@ component accessors="true" singleton { // Load our path into a Java file object so we can use some of its nice utility methods var oPath = createObject( 'java', 'java.io.File' ).init( path ); // Drive roots don't have any name elements - return ( oPath.toPath().getNameCount()==0 ); + return ( oPath.toPath().getNameCount()==0 ); } /** @@ -101,7 +101,7 @@ component accessors="true" singleton { var javaPath = jreDirectory & "/" & "bin" & "/java#fileExtension#"; // build command var javaCommand = createObject( "java", "java.io.File").init( javaPath ).getCanonicalPath(); - + return javaCommand; } @@ -130,11 +130,11 @@ component accessors="true" singleton { if( desktop.isDesktopSupported() and target.isFile() ){ desktop.getDesktop().edit( target ); return true; - } + } } catch( any e ) { // Silently log this and we'll try a different method below if( e.message contains 'No application is associated with the specified file' ) { - logger.error( '#e.message# #e.detail#' ); + logger.error( '#e.message# #e.detail#' ); } else { logger.error( '#e.message# #e.detail#' , e.stackTrace ); } @@ -144,7 +144,7 @@ component accessors="true" singleton { var runtime = createObject( "java", "java.lang.Runtime" ).getRuntime(); if( isWindows() and target.isFile() ){ runtime.exec( [ "rundll32", "url.dll,FileProtocolHandler", target.getCanonicalPath() ] ); - } + } else if( isWindows() and target.isDirectory() ){ var processBuilder = createObject( "java", "java.lang.ProcessBuilder" ) .init( [ "explorer.exe", target.getCanonicalPath() ] ) @@ -199,10 +199,10 @@ component accessors="true" singleton { return true; } - - /** + + /** * Accepts an absolute path and returns a relative path - * Does NOT apply any canonicalization + * Does NOT apply any canonicalization */ string function makePathRelative( required string absolutePath ) { if( !isWindows() ) { @@ -215,15 +215,15 @@ component accessors="true" singleton { var mappingPath = getDirectoryFromPath( arguments.absolutePath ); mappingPath = mappingPath.replace( '\', '/', 'all' ); mappingPath = mappingPath.listChangeDelims( '/', '/' ); - + var mappingName = mappingPath.replace( ':', '_', 'all' ); mappingName = mappingName.replace( '.', '_', 'all' ); mappingName = mappingName.replace( '/', '_', 'all' ); mappingName = '/' & mappingName; - + createMapping( mappingName, mappingPath ); return mappingName & '/' & getFileFromPath( arguments.absolutePath ); - + // Otherwise, do the "normal" way that re-uses top level drive mappings // C:/users/brad/foo.cfc turns into /C_Drive/users/brad/foo.cfc } else { @@ -233,8 +233,8 @@ component accessors="true" singleton { return mapping & path; } } - - /** + + /** * Accepts a Windows drive letter and returns a CF Mapping * Creates the mapping if it doesn't exist */ @@ -244,7 +244,7 @@ component accessors="true" singleton { createMapping( mappingName, mappingPath ); return mappingName; } - + function createMapping( mappingName, mappingPath ) { var mappings = getApplicationSettings().mappings; if( !structKeyExists( mappings, mappingName ) ) { diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 4dc0bd56b..4e3e104c6 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -19,7 +19,7 @@ or just add DEBUG to the root logger -----------------------------------------------------------------------> - + @@ -33,9 +33,9 @@ or just add DEBUG to the root logger - + - this.ORDER = { + this.ORDER = { POPULAR = "popular", NEW = "new", RECENT = "recent", @@ -46,7 +46,7 @@ or just add DEBUG to the root logger - + // Setup Properties variables.endpointURL = "https://www.forgebox.io"; variables.APIURL = "#variables.endpointURL#/api/v1/"; @@ -58,13 +58,13 @@ or just add DEBUG to the root logger - + var results = ""; - + // Invoke call results = makeRequest( resource="types", @@ -72,13 +72,13 @@ or just add DEBUG to the root logger 'x-api-token' : arguments.APIToken } ); - // error + // error if( results.response.error ){ throw("Error making ForgeBox REST Call", 'forgebox', results.response.messages.toList() ); } - - return results.response.data; - + + return results.response.data; +
@@ -89,11 +89,11 @@ or just add DEBUG to the root logger if( isSimpleValue( variables.types ) OR arguments.force ){ variables.types = getTypes( APIToken ); } - + return variables.types; -
+
- + @@ -109,9 +109,9 @@ or just add DEBUG to the root logger max = arguments.maxrows, offset = arguments.startrow-1, typeSlug = arguments.typeSlug, - searchTerm = arguments.searchTerm + searchTerm = arguments.searchTerm }; - + // Invoke call results = makeRequest( resource="entries", @@ -119,36 +119,36 @@ or just add DEBUG to the root logger headers = { 'x-api-token' : arguments.APIToken }); - // error + // error if( results.response.error ){ throw( "Error making ForgeBox REST Call", 'forgebox', results.response.messages.toList() ); } - + return results.response.data; - + - + var results = ""; - + // Invoke call results = makeRequest( resource="entry/#arguments.slug#", headers = { 'x-api-token' : arguments.APIToken }); - - // error + + // error if( results.response.error ){ throw( "Error getting ForgeBox entry [#arguments.slug#]", 'forgebox', results.response.messages.toList() ); } - - return results.response.data; - + + return results.response.data; + @@ -157,25 +157,25 @@ or just add DEBUG to the root logger var results = ""; - + // Invoke call results = makeRequest( resource="slug-check/#arguments.slug#", headers = { 'x-api-token' : arguments.APIToken }); - - // error + + // error if( results.response.error ){ throw( "Error making ForgeBox REST Call", 'forgebox', results.response.messages.toList() ); } - - return results.response.data; - + + return results.response.data; + - + - + /** * Registers a new user in ForgeBox */ @@ -186,7 +186,7 @@ or just add DEBUG to the root logger required string fName, required string lName, string APIToken='' ) { - + var results = makeRequest( resource="register", parameters=arguments, @@ -194,52 +194,52 @@ or just add DEBUG to the root logger headers = { 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( "Sorry, the user could not be added.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - + /** * Look up user based on API Token */ function whoami( required string APIToken ) { - + var results = makeRequest( resource="users/whoami/#APIToken#", method='get', headers = { 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( arrayToList( results.response.messages ), 'forgebox' ); } - + return results.response.data; } - + /** * Authenticates a user in ForgeBox */ function login( required string username, required string password ) { - + var results = makeRequest( resource="authenticate", parameters=arguments, method='post' ); - - // error + + // error if( results.response.error ){ throw( "Sorry, the user could not be logged in.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - + /** * Publishes a package in ForgeBox */ @@ -255,7 +255,7 @@ or just add DEBUG to the root logger string changeLog='', string changeLogFormat='text', required string APIToken ) { - + var body = { slug : arguments.slug, version : arguments.version, @@ -268,8 +268,8 @@ or just add DEBUG to the root logger changeLog : arguments.changeLog, changeLogFormat : arguments.changeLogFormat }; - - var results = makeRequest( + + var results = makeRequest( resource = "publish", headers = { 'x-api-token' : arguments.APIToken, @@ -277,15 +277,15 @@ or just add DEBUG to the root logger }, body = serializeJSON( body ), method='post' ); - - // error + + // error if( results.response.error ){ throw( "Sorry, the package could not be published.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - + /** * Unpublishes a package */ @@ -293,23 +293,23 @@ or just add DEBUG to the root logger required string slug, string version='', required string APIToken ) { - + var thisResource = "unpublish/#arguments.slug#"; if( len( arguments.version ) ) { - thisResource &= "/#arguments.version#"; + thisResource &= "/#arguments.version#"; } - + var results = makeRequest( resource=thisResource, method='post', headers={ 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( "Something went wrong unplublishing.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - - + + /** * Tracks an install */ @@ -317,12 +317,12 @@ or just add DEBUG to the root logger required string slug, string version='', string APIToken='' ) { - + var thisResource = "install/#arguments.slug#"; if( len( arguments.version ) ) { - thisResource &= "/#arguments.version#"; + thisResource &= "/#arguments.version#"; } - + var results = makeRequest( resource=thisResource, method='post', @@ -330,15 +330,15 @@ or just add DEBUG to the root logger 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( "Something went wrong tracking this installation.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - + /** * Tracks a download */ @@ -346,28 +346,28 @@ or just add DEBUG to the root logger required string slug, string version, string APIToken='' ) { - + var thisResource = "install/#arguments.slug#"; if( len( arguments.version ) ) { - thisResource &= "/#arguments.version#"; + thisResource &= "/#arguments.version#"; } - + var results = makeRequest( resource=thisResource, method='post', headers = { 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( "Something went wrong tracking this download.", 'forgebox', arrayToList( results.response.messages ) ); } - + return results.response.data; } - - + + /** * Autocomplete for slugs */ @@ -375,9 +375,9 @@ or just add DEBUG to the root logger required string searchTerm, string typeSlug = '', string APIToken='' ) { - + var thisResource = "slugs/#arguments.searchTerm#"; - + var results = makeRequest( resource=thisResource, method='get', @@ -387,24 +387,24 @@ or just add DEBUG to the root logger headers = { 'x-api-token' : arguments.APIToken } ); - - // error + + // error if( results.response.error ){ throw( "Error searching for slugs", 'forgebox', arrayToList( results.response.messages ) ); } - + var opts = results.response.data; - + // If there's only one suggestion and it doesn't have an @ in it, add another suggestion with the @ at the end. // This is to prevent the tab completion from adding a space after the suggestion since it thinks it's the only possible option // Hitting tab will still populate the line, but won't add the space which makes it easier if the user intends to continue for a specific version. if( opts.len() == 1 && !( opts[1] contains '@' ) ) { opts.append( opts[1] & '@' ); } - + return opts; } - + @@ -424,75 +424,75 @@ or just add DEBUG to the root logger if( APIURL.endsWith( '/' ) ) { APIURL = left( APIURL, len( APIURL )-1 ); } - + // Default Content Type if( NOT structKeyExists(arguments.headers,"content-type") ){ arguments.headers["content-type"] = ""; } var thisURL = '#APIURL#/#arguments.resource#'; - + var CFHTTPParams = { method=arguments.method, url=thisURL, charset='utf-8', - result='HTTPResults', + result='HTTPResults', timeout=arguments.timeout }; - + // Get proxy settings from the config var proxyServer=ConfigService.getSetting( 'proxy.server', '' ); var proxyPort=ConfigService.getSetting( 'proxy.port', '' ); var proxyUser=ConfigService.getSetting( 'proxy.user', '' ); var proxyPassword=ConfigService.getSetting( 'proxy.password', '' ); - + if( len( proxyServer ) ) { CFHTTPParams.proxyServer = proxyServer; - + if( len( proxyPort ) ) { - CFHTTPParams.proxyPort = proxyPort; - } + CFHTTPParams.proxyPort = proxyPort; + } if( len( proxyUser ) ) { - CFHTTPParams.proxyUser = proxyUser; - } + CFHTTPParams.proxyUser = proxyUser; + } if( len( proxyPassword ) ) { - CFHTTPParams.proxyPassword = proxyPassword; + CFHTTPParams.proxyPassword = proxyPassword; } } - + - + - + - - + + - - + + - + - + // Log //log.debug("ForgeBox Rest Call ->Arguments: #arguments.toString()#",HTTPResults); - + // Set Results results.responseHeader = HTTPResults.responseHeader; results.rawResponse = HTTPResults.fileContent.toString(); - + // Error Details found? results.message = HTTPResults.errorDetail; if( len(HTTPResults.errorDetail) ){ results.error = true; } // Try to inflate JSON - + if (isJSON(results.rawResponse)) { results.response = deserializeJSON(results.rawResponse,false); } else { @@ -503,12 +503,12 @@ or just add DEBUG to the root logger errorDetail &= chr( 10 ) & statusMessage; } errorDetail = ucase( arguments.method ) & ' ' &thisURL & chr( 10 ) & errorDetail; - CommandBoxlogger.error( 'Something other than JSON returned. #errorDetail#', 'Actual HTTP Response: ' & results.rawResponse ); + CommandBoxlogger.error( 'Something other than JSON returned. #errorDetail#', 'Actual HTTP Response: ' & results.rawResponse ); throw( 'Uh-oh, ForgeBox returned something other than JSON. Run "system-log | open" to see the full response.', 'forgebox', errorDetail ); } - + return results; - + - + \ No newline at end of file diff --git a/src/cfml/system/util/Formatter.cfc b/src/cfml/system/util/Formatter.cfc index ac0819557..33ed4a427 100644 --- a/src/cfml/system/util/Formatter.cfc +++ b/src/cfml/system/util/Formatter.cfc @@ -13,9 +13,9 @@ component singleton { property name="print" inject="print"; property name="CR" inject="CR@constants"; property name="JSONPrettyPrint" inject="provider:JSONPrettyPrint"; - + function init(){ - + variables.stringEscapeUtils = createObject("java","org.apache.commons.lang.StringEscapeUtils"); return this; } @@ -36,41 +36,41 @@ component singleton { **/ function HTML2ANSI( required html, additionalFormatting='' ) { var text = html; - + if( len( trim( text ) ) == 0 ) { return ""; } - + // Trim all lines. leading/trailing whitespace in HTML is not useful text = text.listToArray( chr( 13 ) & chr( 10 ) ).map( function( i ) { return trim( i ); } ).toList( chr( 10 ) ); - + // Remove style and script blocks text = reReplaceNoCase(text, "","","all"); text = reReplaceNoCase(text, "]*>.*","","all"); - + text = ansifyHTML( text, "b", "bold", additionalFormatting ); text = ansifyHTML( text, "strong", "bold", additionalFormatting ); text = ansifyHTML( text, "em", "underline", additionalFormatting ); - + // Replace br tags (and any whitespace/line breaks after them) with a CR text = reReplaceNoCase( text , "]*>\s*", CR, 'all' ); - + var t='div'; var matches = REMatch('(?i)<#t#[^>]*>(.*?)', text); for(var match in matches) { var blockText = reReplaceNoCase(match,"<#t#[^>]*>(.*?)","\1") & CR; text = replace(text,match,blockText,"one"); } - - // If you have any < characters in your string that aren't HTML, this will truncate the text + + // If you have any < characters in your string that aren't HTML, this will truncate the text text = reReplaceNoCase(text, "<.*?>","","all"); - + text = reReplaceNoCase(text, "[\n]{2,}",chr( 10 ) & chr( 10 ),"all"); - - - + + + // Turn any escaped HTML entities into their true form text = unescapeHTML( text ); return text; diff --git a/src/cfml/system/util/Parser.cfc b/src/cfml/system/util/Parser.cfc index 1958ce13d..cfe2fa104 100644 --- a/src/cfml/system/util/Parser.cfc +++ b/src/cfml/system/util/Parser.cfc @@ -12,23 +12,23 @@ component { // DI property name="CR" inject="CR@constants"; - + /** * constructor - **/ + **/ function init( ) { return this; } - - + + /** * Tokenizes the command line entered by the user. Returns array with command statements and arguments * - * Consider making a dedicated CFC for this since some of the logic could benifit from + * Consider making a dedicated CFC for this since some of the logic could benifit from * little helper methods to increase readability and reduce duplicate code. **/ function tokenizeInput( string line ) { - + // Holds token var tokens = []; // Used to build up each token @@ -47,29 +47,29 @@ component { var prevEscaped = false; // Pointer to the current character var i = 0; - + // Loop over each character in the line while( ++i <= len( line ) ) { // Current character char = mid( line, i, 1 ); // All the remaining characters remainingChars = mid( line, i+1, len( line ) ); - + // Reset this every time isEscaped = false; - + // This character might be escaped if( prevChar == '\' && !prevEscaped ) { isEscaped = true; } - + // If we're in the middle of a quoted string, just keep appending if( inQuotes ) { // Auto-escape = in a quoted string so it doesn't screw up named-parmeter detection. // It will be unescaped later when we parse the params. if( char == '=' && !isEscaped ) { token &= '\'; - } + } token &= char; // We just reached the end of our quoted string if( char == quoteChar && !isEscaped ) { @@ -77,23 +77,23 @@ component { // Don't break if an = is next ... if( left( trim( remainingChars ), 1 ) != '=' ) { tokens.append( token); - token = ''; + token = ''; } } prevEscaped = isEscaped; prevChar = char; continue; } - + // Whitespace demarcates tokens outside of quotes // Whitespace outside of a quoted string is dumped and not added to the token if( trim(char) == '' || ( char == ';' && !isEscaped ) ) { - + // If this is an unquoted, unescaped semi colon (;) - if( char == ';' ) { + if( char == ';' ) { if( len( token ) ) { tokens.append( token); - token = ''; + token = ''; } tokens.append( char ); prevEscaped = isEscaped; @@ -114,39 +114,39 @@ component { } else { if( len( token ) ) { tokens.append( token); - token = ''; + token = ''; } prevEscaped = isEscaped; prevChar = char; continue; } } - + // We're starting a quoted string if( ( char == '"' || char == "'" || char == "`" ) && !isEscaped ) { inQuotes = true; quoteChar = char; } - + // Keep appending token &= char; - + // If we're waiting for a value in a name/value pair and just hit something OTHER than an = if( isWaitingOnValue && char != '=' ) { // Then the wait is over isWaitingOnValue = false; } - + prevEscaped = isEscaped; prevChar = char; - + } // end while - + // Anything left after the loop is our last token if( len( token ) ) { - tokens.append( token); + tokens.append( token); } - + return tokens; } @@ -155,33 +155,33 @@ component { * Parse an array of parameter tokens. unescape values and determine if named or positional params are being used. **/ function parseParameters( required array parameters, commandParameters ) { - + var results = { positionalParameters = [], namedParameters = {}, flags = {} }; - + if( !arrayLen( parameters ) ) { - return results; + return results; } - + // Pull the valid param names out into an array for easy lookup var commandParameterNameLookup=[]; for( var thisParam in commandParameters ) { commandParameterNameLookup.append( thisParam.name ); } - + for( var param in parameters ) { - + // Remove escaped characters param = removeEscapedChars( param ); - + // Flag --flagName if( param.startsWith( '--' ) && len( param ) >= 3 ) { // Strip off -- var flagName = right( param, len( param ) - 2 ); - + // Check for negation --!flagName if( flagName.startsWith( '!' ) ) { // Strip ! @@ -195,59 +195,59 @@ component { // Flag is true results.flags [ flagName ] = true; } - + // named params } else if( find( '=', param, 2 ) ) { // Extract the name and value pair var name = listFirst( param, '=' ); var value = listRest( param, '=' ); - + // Unwrap quotes from value if used name = unwrapQuotes( name ); value = unwrapQuotes( value ); - + // Mark expressions and system settings now while escaped chars are removed value = markExpressions( value ); value = markSystemSettings( value ); - + name = replaceEscapedChars( name ); value = replaceEscapedChars( value ); - + results.namedParameters[ name ] = value; - + // Positional params } else { // Unwrap quotes from value if used param = unwrapQuotes( param ); - + // Mark expressions and system settings now while escaped chars are removed param = markExpressions( param ); param = markSystemSettings( param ); - + param = replaceEscapedChars( param ); - results.positionalParameters.append( param ); + results.positionalParameters.append( param ); } - + } - + return results; - + } - + /** * Find any strings encased in backticks and flags them as a CommandBox expression */ function markExpressions( required argValue ) { return reReplaceNoCase( argValue, '`(.*?)`', '__expression__\1__expression__', 'all' ); } - + /** * Find any strings like ${foo} and flag them as a system setting */ function markSystemSettings( required argValue ) { return reReplaceNoCase( argValue, '\$\{(.*?)}', '__system__\1__system__', 'all' ); } - + /** * Escapes a value and for inclusion in a command * The following replacements are made: @@ -278,17 +278,17 @@ component { } function unwrapQuotes( theString ) { - // If the value is wrapped with backticks, leave them be. That is a signal to the CommandService + // If the value is wrapped with backticks, leave them be. That is a signal to the CommandService // that the string is special and needs to be evaluated as an expression. if( left( theString, 1 ) == '"' || left( theString, 1 ) == "'" ) { return mid( theString, 2, len( theString ) - 2 ); } return theString; } - - + + // ----------------------------- Private --------------------------------------------- - + private function removeEscapedChars( theString ) { theString = replaceNoCase( theString, "\\", '__backSlash__', "all" ); theString = replaceNoCase( theString, "\'", '__singleQuote__', "all" ); @@ -302,7 +302,7 @@ component { theString = replaceNoCase( theString, '\${', '__system_setting__', "all" ); return replaceNoCase( theString, '\|', '__pipe__', "all" ); } - + private function replaceEscapedChars( theString ) { theString = replaceNoCase( theString, '__backSlash__', "\", "all" ); theString = replaceNoCase( theString, '__singleQuote__', "'", "all" ); @@ -316,6 +316,6 @@ component { theString = replaceNoCase( theString, '__system_setting__', '${', "all" ); return replaceNoCase( theString, '__pipe__', '|', "all" ); } - - + + } \ No newline at end of file diff --git a/src/cfml/system/util/Print.cfc b/src/cfml/system/util/Print.cfc index 753f1cfcf..8ac9ce372 100644 --- a/src/cfml/system/util/Print.cfc +++ b/src/cfml/system/util/Print.cfc @@ -21,13 +21,13 @@ * * If you want to modify formatting at runtime, pass a second parameter of additional text * that will be appended to the method name upon processing. -* +* * print.text( 'Hello World', 'blue' ); * print.text( 'Hello World', statusColor ); * print.text( 'Hello World', ( status == 'running' ? 'green' : 'red' ) ); -* +* * Indent each carridge return with two spaces like so: -* +* * print.indentedLine( 'Hello World' ); * */ @@ -170,9 +170,9 @@ component { // Don't mess with the string if we didn't format it if( len( ANSIString ) ) { text = ANSIString & text; - if( !noEnd ) { + if( !noEnd ) { text &= getANSIAttribute( this.ANSIAttributes["off"] ); - } + } } // Add a CR if this was supposed to be a line diff --git a/src/cfml/system/util/PrintBuffer.cfc b/src/cfml/system/util/PrintBuffer.cfc index 68f19c311..60736411a 100644 --- a/src/cfml/system/util/PrintBuffer.cfc +++ b/src/cfml/system/util/PrintBuffer.cfc @@ -13,31 +13,31 @@ component accessors="true" extends="Print"{ // DI property name="shell" inject="shell"; - + /** * Result buffer */ property name="result" default=""; - + function init(){ return this; } - + // Force a flush function toConsole(){ variables.shell.printString( getResult() ); clear(); } - + // Reset the result function clear(){ - variables.result = ''; + variables.result = ''; } - + // Proxy through any methods to the actual print helper function onMissingMethod( missingMethodName, missingMethodArguments ){ variables.result &= super.onMissingMethod( arguments.missingMethodName, arguments.missingMethodArguments ); return this; } - + } \ No newline at end of file diff --git a/src/cfml/system/util/ProgressBar.cfc b/src/cfml/system/util/ProgressBar.cfc index 734b1359a..bbabf487e 100644 --- a/src/cfml/system/util/ProgressBar.cfc +++ b/src/cfml/system/util/ProgressBar.cfc @@ -20,85 +20,85 @@ component singleton { * Will print a line break if the percent is 100 * @downloadURL.hint The remote URL to download * @destinationFile.hint The local file path to store the downloaded file - * @statusUDF.hint A closure that will be called once for each full percent of completion. Accepts a struct containing percentage, averageKBPS, totalKB, and downloadedKB + * @statusUDF.hint A closure that will be called once for each full percent of completion. Accepts a struct containing percentage, averageKBPS, totalKB, and downloadedKB */ - public function update( + public function update( required numeric percent, required numeric totalSizeKB, required numeric completeSizeKB, required numeric speedKBps ) { - + var ansi = createObject( 'java', 'org.fusesource.jansi.Ansi' ).init(); var AnsiConsole = createObject( 'java', 'org.fusesource.jansi.AnsiConsole' ); AnsiConsole.systemInstall(); var ansiErase = createObject( 'java', 'org.fusesource.jansi.Ansi$Erase' ); // Total space availble to progress bar. Subtract 5 for good measure since it will wrap if you get too close var totalWidth = shell.getTermWidth()-5 ; - + // TODO: ETA var progressBarTemplate = '@@@% [=>] $$$$$$$ / ^^^^^^^ (&&&&&&&&)'; // Dynamically assign the remaining width to the moving progress bar var nonProgressChars = len( progressBarTemplate ) - 1; // Minimum progressbar length is 5. It will wrap if the user's console is super short, but I'm not sure I care. - var progressChars = max( totalWidth - nonProgressChars, 5 ); - + var progressChars = max( totalWidth - nonProgressChars, 5 ); + // Clear the line ansi.eraseLine(ansiErase.ALL); // Windows DOS can have a window size larger than the reported terminal size. Moving the cursor left // a ridiculous amount seems to have no ill-affect so we're just going to make darn sure we're up against the left side. ansi.cursorLeft( totalWidth+99999 ); - + // Get the template var progressRendered = progressBarTemplate; - + // Replace percent progressRendered = replace( progressRendered, '@@@', numberFormat( arguments.percent, '___' ) ); - + // Replace actual progress bar var progressSize = int( progressChars * (arguments.percent/100) ); var barChars = repeatString( '=', progressSize ) & '>' & repeatString( ' ', max( progressChars-progressSize, 0 ) ); progressRendered = replace( progressRendered, '=>', barChars ); - + // Replace sizes and speed progressRendered = replace( progressRendered, '^^^^^^^', formatSize( arguments.totalSizeKB, 7 ) ); progressRendered = replace( progressRendered, '$$$$$$$', formatSize( arguments.completeSizeKB, 7 ) ); progressRendered = replace( progressRendered, '&&&&&&&&', formatSize( min( arguments.speedKBps, 99000), 6 ) & 'ps' ); - + // Add to buffer ansi.a( progressRendered ); - + // If we're done, add a line break if( arguments.percent == 100 ) { - ansi.newline(); + ansi.newline(); } - + // Add to console and flush system.out.print(ansi); system.out.flush(); AnsiConsole.systemUninstall(); - - + + } private function formatSize( sizeKB, numberChars ) { arguments.sizeKB = round( arguments.sizeKB ); - + // Present in MB if( arguments.sizeKB >= 1000 ) { var sizeMB = arguments.sizeKB/1000; var mask = repeatString( '_' , numberChars-4 ) & '.9'; return numberFormat( sizeMB, mask) & 'MB'; - + // Present in KB } else { var mask = repeatString( '_' , numberChars-2 ); return numberFormat( arguments.sizeKB, mask) & 'KB'; - + } } - + } \ No newline at end of file diff --git a/src/cfml/system/util/ProgressableDownloader.cfc b/src/cfml/system/util/ProgressableDownloader.cfc index a9b610224..962f68c97 100644 --- a/src/cfml/system/util/ProgressableDownloader.cfc +++ b/src/cfml/system/util/ProgressableDownloader.cfc @@ -17,53 +17,53 @@ component singleton { * @downloadURL.hint The remote URL to download * @destinationFile.hint The local file path to store the downloaded file * @statusUDF.hint A closure that will be called once for each full percent of completion. Accepts a struct containing percentage, averageKBPS, totalKB, and downloadedKB - * @redirectUDF.hint A closure that will be called once for every 30X redirect followed + * @redirectUDF.hint A closure that will be called once for every 30X redirect followed */ - public function download( + public function download( required string downloadURL, required string destinationFile, any statusUDF, any redirectUDF='' ) { - + var data = getByteArray( 1024 ); var total = 0; var currentPercentage = 0; var lastPercentage = 0; var lastTotalDownloaded = 0; - + // Get connection object, following redirects. var info = resolveConnection( arguments.downloadURL, arguments.redirectUDF ); var connection = info.connection; var netURL = info.netURL; - + try { - + var lenghtOfFile = connection.getContentLength(); - + var inputStream = createObject( 'java', 'java.io.BufferedInputStream' ).init( netURL.openStream() ); var outputStream = createObject( 'java', 'java.io.FileOutputStream' ).init( arguments.destinationFile ); - + var currentTickCount = getTickCount(); var lastTickCount = currentTickCount; var kiloBytesPerSecondRunningAverage = []; var lastKiloBytesPerSeconde = 0; - - while ( ( var count = inputStream.read( data ) ) != -1 ) { + + while ( ( var count = inputStream.read( data ) ) != -1 ) { total += count; currentPercentage = int( ( total * 100 ) / lenghtOfFile ); outputStream.write( data, 0, count ); - + // Is there a callback closure if( !isNull( arguments.statusUDF ) ) { - + // Have we progressed a full percent? if( currentPercentage >= lastPercentage + 1 ) { - + currentTickCount = getTickCount(); bytesSinceLastUpdate = total - lastTotalDownloaded; milisSinceLastUpdate = currentTickCount - lastTickCount; - - // Make sure time passed since last update in case network got ahead of our loop + + // Make sure time passed since last update in case network got ahead of our loop if( milisSinceLastUpdate > 1 ) { // Add KBPS to an array so we can get an average kiloBytesPerSecondRunningAverage.append( round( ( bytesSinceLastUpdate / 1000 ) * ( 1000 / milisSinceLastUpdate ) ) ); @@ -74,7 +74,7 @@ component singleton { } else { kiloBytesPerSecond = lastKiloBytesPerSeconde; } - + // Build status data to pass to closure var status = { percent = currentPercentage, @@ -82,30 +82,30 @@ component singleton { totalSizeKB = lenghtOfFile/1000, completeSizeKB = total/1000 }; - + // Call closure arguments.statusUDF( status ); - + // Prune back array if( kiloBytesPerSecondRunningAverage.len() > 4 ) { kiloBytesPerSecondRunningAverage.deleteAt( 1 ); } - + lastTotalDownloaded = total; lastPercentage = currentPercentage; lastTickCount = currentTickCount; - + } // full percentage check - + } // Closure check - + } // End loop - - + + outputStream.flush(); outputStream.close(); inputStream.close(); - + var returnStruct = { responseCode = connection.responseCode, responseMessage = connection.responseMessage, @@ -120,37 +120,37 @@ component singleton { returnStruct.headers[ connection.getHeaderFieldKey( i ) ] = connection.getHeaderField( i ); } } - + return returnStruct; - + } catch( Any var e ) { rethrow; } finally { if( !isNull( outputStream ) ) { outputStream.flush(); - outputStream.close(); + outputStream.close(); } if( !isNull( inputStream ) ) { inputStream.close(); } } - + } - + // Creates a Java byte array of a given size private binary function getByteArray( required numeric size ) { var emptyByteArray = createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray(); var byteClass = emptyByteArray.getClass().getComponentType(); var byteArray = createObject("java","java.lang.reflect.Array").newInstance(byteClass, arguments.size); return byteArray; - } + } // Get connection following redirects private function resolveConnection( required string downloadURL, redirectUDF ) { var netURL = createObject( 'java', 'java.net.URL' ).init( arguments.downloadURL ); - + // Get proxy settings from the config var proxyServer=ConfigService.getSetting( 'proxy.server', '' ); var proxyPort=ConfigService.getSetting( 'proxy.port', 80 ); @@ -162,33 +162,33 @@ component singleton { var proxyType = createObject( 'java', 'java.net.Proxy$Type' ); var inetSocketAddress = createObject( 'java', 'java.net.InetSocketAddress' ).init( proxyServer, proxyPort ); var proxy = createObject( 'java', 'java.net.Proxy' ).init( proxyType.HTTP, inetSocketAddress ); - + // If there is a user defined, use our custom proxyAuthenticator if( len( proxyUser ) ) { var proxyAuthenticator = createObject( 'java', 'com.ortussolutions.commandbox.authentication.ProxyAuthenticator').init( proxyUser, proxyPassword ) createObject( 'java', 'java.net.Authenticator' ).setDefault( proxyAuthenticator ); - } else { - createObject( 'java', 'java.net.Authenticator' ).setDefault( JavaCast( 'null', '' ) ); + } else { + createObject( 'java', 'java.net.Authenticator' ).setDefault( JavaCast( 'null', '' ) ); } - + // Open our connection using the proxy var connection = netURL.openConnection( proxy ); } else { // Open a "regular" connection var connection = netURL.openConnection(); - } - - + } + + // The reason we're following redirects manually, is because the java class // won't switch between HTTP and HTTPS without erroring connection.setInstanceFollowRedirects( false ); - + try { connection.connect(); } catch( Any var e ) { throw( message='Connection failure #arguments.downloadURL#', detail=e.message ); } - + // If we get a redirect, follow it if( connection.responseCode >= 300 && connection.responseCode < 400 ) { var newURL = connection.getHeaderField( "Location"); @@ -196,20 +196,20 @@ component singleton { // Sometimes the HTTP location header is a relative path. var next = createObject( 'java', 'java.net.URL' ).init( netURL, newURL ); newURL = next.toExternalForm(); - + if( !isSimpleValue( arguments.redirectUDF ) ) { arguments.redirectUDF( newURL ); } - + return resolveConnection( newURL, arguments.redirectUDF ); } - + // If we didn't get a successful response, bail here if( connection.responseCode < 200 || connection.responseCode > 299 ) { throw( message='#connection.responseCode# #connection.responseMessage#', detail=arguments.downloadURL ); } - + return { connection = connection, netURL = netURL }; } - + } \ No newline at end of file diff --git a/src/cfml/system/util/REPLParser.cfc b/src/cfml/system/util/REPLParser.cfc index 31e8790d2..9a12cf116 100644 --- a/src/cfml/system/util/REPLParser.cfc +++ b/src/cfml/system/util/REPLParser.cfc @@ -133,4 +133,4 @@ component accessors="true" singleton { return reReplaceNoCase( arguments.command, "//[^""']*$|/\*.*\*/", "", "all" ); } -} +} \ No newline at end of file diff --git a/src/cfml/system/util/ReaderFactory.cfc b/src/cfml/system/util/ReaderFactory.cfc index 723643595..35202d0dc 100644 --- a/src/cfml/system/util/ReaderFactory.cfc +++ b/src/cfml/system/util/ReaderFactory.cfc @@ -4,7 +4,7 @@ * www.coldbox.org | www.ortussolutions.com ******************************************************************************** * @author Brad Wood, Luis Majano, Denny Valliant -* +* * The logic to create the console reader was hairy enough I've refactored it out into its own file. * */ @@ -13,8 +13,8 @@ component singleton{ // DI property name="completor" inject="Completor"; property name="homedir" inject="homedir@constants"; - property name="commandHistoryFile" inject="commandHistoryFile@java"; - + property name="commandHistoryFile" inject="commandHistoryFile@java"; + /** * Build a jline console reader instance * @inStream.hint input stream if running externally @@ -22,40 +22,40 @@ component singleton{ */ function getInstance( inStream, outputStream ) { var reader = ""; - + // If no print writer was passed in, create one if( isNull( arguments.outputStream ) ) { // create the jline console reader reader = createObject( "java", "jline.console.ConsoleReader" ).init(); // We were given a print writer to use } else { - + if( isNull( arguments.inStream ) ) { var FileDescriptor = createObject( "java", "java.io.FileDescriptor" ).init(); arguments.inStream = createObject( "java", "java.io.FileInputStream" ).init( FileDescriptor.in ); } - + reader = createObject( "java", "jline.console.ConsoleReader" ).init( arguments.inStream, arguments.outputStream ); } - + // Let JLine handle Cntrl-C, and throw a UserInterruptException (instead of dying) reader.setHandleUserInterrupt( true ); // This turns off special stuff that JLine2 looks for related to exclamation marks reader.setExpandEvents( false ); - + // Turn off option to add space to end of completion that messes up stuff like path completion. reader.getCompletionHandler().setPrintSpaceAfterFullCompletion( false ); - + // Create our completer and set it in the console reader var jCompletor = createDynamicProxy( completor , [ 'jline.console.completer.Completer' ] ); reader.addCompleter( jCompletor ); // Create our history file and set it in the console reader reader.setHistory( commandHistoryFile ); - + return reader; } - -} + +} \ No newline at end of file diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index 3d640c74d..7b2edcac4 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -9,7 +9,7 @@ * */ component singleton { - + variables.system = createObject( "java", "java.lang.System" ); /** @@ -19,12 +19,12 @@ component singleton { * @defaultValue The default value to use if the key does not exist in the system properties */ function getSystemSetting( required string key, defaultValue ) { - + var value = system.getProperty( arguments.key ); if ( ! isNull( value ) ) { return value; } - + value = system.getEnv( arguments.key ); if ( ! isNull( value ) ) { return value; @@ -47,7 +47,7 @@ component singleton { * @defaultValue The default value to use if the key does not exist in the system properties */ function getSystemProperty( required string key, defaultValue ) { - + var value = system.getProperty( arguments.key ); if ( ! isNull( value ) ) { return value; @@ -65,12 +65,12 @@ component singleton { /** * Retrieve an env value by name. - * + * * @key The name of the setting to look up. * @defaultValue The default value to use if the key does not exist in the env */ function getEnv( required string key, defaultValue ) { - + var value = system.getEnv( arguments.key ); if ( ! isNull( value ) ) { return value; @@ -91,7 +91,7 @@ component singleton { /** * Expands placeholders like ${foo} in a string with the matching java prop or env var. * Will replace as many place holders that exist, but will skip escaped ones like \${do.not.expand.me} - * + * * @text The string to do the replacement on */ function expandSystemSettings( required string text ) { @@ -101,7 +101,7 @@ component singleton { text = reReplaceNoCase( text, '\$\{(.*?)}', '__system__\1__system__', 'all' ); // put escaped stuff back text = replaceNoCase( text, '__system_setting__', '${', "all" ); - + // Look for a system setting "foo" flagged as "__system__foo__system__" var search = reFindNoCase( '__system__.*?__system__', text, 1, true ); @@ -114,7 +114,7 @@ component singleton { var defaultValue = ''; if( settingName.listLen( ':' ) ) { defaultValue = settingName.listRest( ':' ); - settingName = settingName.listFirst( ':' ); + settingName = settingName.listFirst( ':' ); } var result = getSystemSetting( settingName, defaultValue ); @@ -130,7 +130,7 @@ component singleton { * Expands placeholders like ${foo} in all deep struct keys and array elements with the matching java prop or env var. * Will replace as many place holders that exist, but will skip escaped ones like \${do.not.expand.me} * This will recursivley follow all nested structs and arrays. - * + * * @dataStructure A string, struct, or array to perform deep replacement on. */ function expandDeepSystemSettings( required any dataStructure ) { @@ -149,7 +149,7 @@ component singleton { i++; dataStructure[ i ] = expandDeepSystemSettings( item ); } - return dataStructure; + return dataStructure; // If it's a string... } else if ( isSimpleValue( dataStructure ) ) { // Just do the replacement diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index c378c269d..a4b021b7b 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -24,7 +24,7 @@ component accessors=true { property name='print' inject='PrintBuffer'; property name='pathPatternMatcher' inject='provider:pathPatternMatcher@globber'; property name='fileSystemUtil' inject='FileSystem'; - + // Properties property name='changeHash' type='string'; property name='watcherRun' type='boolean'; @@ -32,14 +32,14 @@ component accessors=true { property name='changeUDF' type='function'; property name='baseDirectory' type='string'; property name='delayMS' type='number'; - + function onDIComplete() { setBaseDirectory( shell.pwd() ); setDelayMS( 500 ); // Watch all files recursivley by default setPathsToWatch( [ '**' ] ); } - + /** * Pass in an array of file globbing paths or any numberof string globbing arguments. */ @@ -51,7 +51,7 @@ component accessors=true { } return this; } - + /** * Pass in the base directory that the globbing patterns are relative to */ @@ -59,7 +59,7 @@ component accessors=true { setBaseDirectory( arguments.baseDirectory ); return this; } - + /** * Pass in the number of miliseconds to wait between polls */ @@ -67,7 +67,7 @@ component accessors=true { setDelayMS( arguments.delayMS ); return this; } - + /** * Pass in a UDF refernce to be executed when the watcher senses a chnage on the file system */ @@ -75,24 +75,24 @@ component accessors=true { setChangeUDF( arguments.changeUDF ); return this; } - + /** * Call to start the watcher. This method will block until the user ends it with Ctrl+C */ public function start() { - + if( isNull( getChangeUDF() ) ) { - throw( "No onChange UDF specified. There's nothing to do!" ); - } - + throw( "No onChange UDF specified. There's nothing to do!" ); + } + setChangeHash( calculateHashes() ); setWatcherRun( true ); - + print .line() .boldRedLine( "Watching Files..." ) .toConsole(); - + try { var threadName = 'watcher#createUUID()#'; thread action="run" name="#threadname#" priority="HIGH"{ @@ -101,11 +101,11 @@ component accessors=true { while( getWatcherRun() ){ // Verify if we have a change if( changeDetected() ){ - + // Fire onChange listener var thisChangeUDF = getChangeUDF(); thisChangeUDF(); - + } else { // Sleep and test again. sleep( getDelayMS() ); @@ -114,32 +114,32 @@ component accessors=true { // Handle "expected" exceptions from commands } catch( commandException e ) { shell.printError( { message : e.message, detail: e.detail } ); - + print .line() .printGreenLine( "Starting watcher again..." ) .line() .toConsole(); - + // Fire the watcher up again. retry; - } catch( any e ) { + } catch( any e ) { shell.printError( e ); - + print .line() .printGreenLine( "Starting watcher again..." ) .line() .toConsole(); - + // Fire the watcher up again. retry; } } // end thread - + while( true ){ // Wipe out prompt so it doesn't redraw if the user hits enter - shell.getReader().setPrompt( '' ); + shell.getReader().setPrompt( '' ); // Detect user pressing Ctrl-C // Any other characters captured will be ignored var line = shell.getReader().readLine(); @@ -151,16 +151,16 @@ component accessors=true { .toConsole(); } } - - - // user wants to exit, they've pressed Ctrl-C + + + // user wants to exit, they've pressed Ctrl-C } catch ( jline.console.UserInterruptException e ) { - + print .printLine( "" ) .printBoldRedLine( "Stopping..." ) .toConsole(); - + // make sure the thread exits setWatcherRun( false ); // Wait until the thread finishes its last draw @@ -175,12 +175,12 @@ component accessors=true { } finally{ shell.setPrompt(); } - + // make sure the thread exits setWatcherRun( false ); // Wait until the thread finishes thread action="join" name=threadName; - + return this; } @@ -188,7 +188,7 @@ component accessors=true { private function calculateHashes() { var globPatterns = getPathsToWatch(); var thisBaseDir = fileSystemUtil.resolvePath( getBaseDirectory() ); - + var fileListing = directoryList( thisBaseDir, true, @@ -196,27 +196,27 @@ component accessors=true { function( path ) { // This will normalize the slashes to match arguments.path = fileSystemUtil.resolvePath( arguments.path ); - + // cleanup path so we just get what's inside the base dir var thisPath = replacenocase( arguments.path, thisBaseDir, "" ); - + // Does this path match one of our glob patterns return pathPatternMatcher.matchPatterns( globPatterns, thisPath ); }, "DateLastModified desc" ); - + var directoryHash = hash( serializeJSON( fileListing ) ); - + return directoryHash; } - + private function changeDetected() { var newHash = calculateHashes(); if( getChangeHash() == newHash ){ return false; - } + } setChangeHash( newHash ); return true; } - + } \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/aop/Matcher.cfc b/src/cfml/system/wirebox/system/aop/Matcher.cfc index f71e2e361..1cce3e010 100644 --- a/src/cfml/system/wirebox/system/aop/Matcher.cfc +++ b/src/cfml/system/wirebox/system/aop/Matcher.cfc @@ -1,4 +1,4 @@ - - + - - + + reset(); - + return this; - - - + + + // prepare instance for this matcher instance = { @@ -36,63 +36,63 @@ Description : regex = "", methods = "" }; - + // Aggregators instance.and = ""; - instance.or = ""; - - return this; - - - - - + instance.or = ""; + + return this; + + + + + - return instance; - + return instance; + - - - + + + var results = matchClassRules(argumentCollection=arguments); - + // AND matcher set? if( isObject( instance.and ) ){ return (results AND instance.and.matchClass(argumentCollection=arguments) ); } // OR matcher set? if( isObject( instance.or ) ){ return (results OR instance.or.matchClass(argumentCollection=arguments) ); } - - return results; - + + return results; + - - - + + + var results = matchMethodRules(arguments.metadata); - + // AND matcher set? if( isObject( instance.and ) ){ return (results AND instance.and.matchMethod(arguments.metadata) ); } // OR matcher set? if( isObject( instance.or ) ){ return (results OR instance.or.matchMethod(arguments.metadata) ); } - - return results; - + + return results; + - - - + + + - + // Some metadata defaults var name = arguments.metadata.name; var returns = "any"; - + if( structKeyExists(arguments.metadata, "returntype") ){ returns = arguments.metadata.returntype; } - + // Start with any() if( instance.any ){ return true; } // Check explicit methods @@ -111,25 +111,25 @@ Description : if( len(instance.annotation) AND structKeyExists(arguments.metadata, instance.annotation)){ // No annotation value if( NOT structKeyExists(instance,"annotationValue") ){ return true; } - + // check annotation value if( structKeyExists(instance,"annotationValue") AND arguments.metadata[instance.annotation] EQ instance.annotationValue ){ - return true; + return true; } } - - return false; - + + return false; + - - - + + + - + var md = arguments.mapping.getObjectMetadata(); var path = reReplace(md.name, "(\/|\\)", ".","all"); - + // Start with any() if( instance.any ){ return true; } // Check explicit mappings @@ -148,36 +148,36 @@ Description : if( len(instance.annotation) AND structKeyExists(md, instance.annotation)){ // No annotation value if( NOT structKeyExists(instance,"annotationValue") ){ return true; } - + // check annotation value if( structKeyExists(instance,"annotationValue") AND md[instance.annotation] EQ instance.annotationValue ){ - return true; + return true; } } - - return false; - + + return false; + - - - + + + instance.any = true; return this; - + - - - + + + - + instance.returns = arguments.type; return this; - + - - - + + + @@ -187,63 +187,63 @@ Description : instance.annotationValue = arguments.value; } return this; - + - - - + + + if( isArray( arguments.mappings ) ){ arguments.mappings = arrayToList(arguments.mappings); } instance.mappings = arguments.mappings; return this; - + - - - + + + - + instance.instanceOf = arguments.classPath; return this; - + - - - + + + instance.regex = arguments.regex; - return this; - + return this; + - - - + + + if( isArray( arguments.methods ) ){ arguments.methods = arrayToList(arguments.methods); } instance.methods = arguments.methods; return this; - + - - - + + + - + instance.and = arguments.matcher; return this; - + - - - + + + - + instance.or = arguments.matcher; return this; - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc b/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc index 18a441241..a12d8c9a2 100644 --- a/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc +++ b/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc @@ -1,4 +1,4 @@ - - - + + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc b/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc index 3ea98a4be..3b76c7322 100644 --- a/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc +++ b/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc @@ -1,4 +1,4 @@ - - + - - + + @@ -22,7 +22,7 @@ Description : - + // store references instance = { // Method intercepted @@ -44,70 +44,70 @@ Description : // Length of interceptor interceptorLen = arrayLen( arguments.interceptors ) }; - + return this; - - + + instance.interceptorIndex++; - return this; - + return this; + - - + + - return instance.interceptorIndex; - + return instance.interceptorIndex; + - - - - return instance.method; - + + + + return instance.method; + - - - - - return instance.methodMetadata; - + + + + + return instance.methodMetadata; + - - - + + + - return instance.target; - + return instance.target; + - - - + + + - return instance.targetName; - + return instance.targetName; + - - - + + + - return instance.targetMapping; - - - - - - - return instance.args; - + return instance.targetMapping; + - + + + + + return instance.args; + + + @@ -117,27 +117,27 @@ Description : - - + + - return instance.interceptors; - + return instance.interceptors; + - - - + + + // We will now proceed with our interceptor execution chain or regular method pointer call // execute the next interceptor in the chain - + // Check Current Index against interceptor length if( instance.interceptorIndex LTE instance.interceptorLen ){ return instance.interceptors[ instance.interceptorIndex ].invokeMethod( this.incrementInterceptorIndex() ); } - + // If we get here all interceptors have fired and we need to fire the original proxied method return instance.target.$wbAOPInvokeProxy(method=instance.method,args=instance.args); - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/aop/Mixer.cfc b/src/cfml/system/wirebox/system/aop/Mixer.cfc index 0d96f005b..15a2701ab 100644 --- a/src/cfml/system/wirebox/system/aop/Mixer.cfc +++ b/src/cfml/system/wirebox/system/aop/Mixer.cfc @@ -1,4 +1,4 @@ - - + - + - + instance = { logResults = arguments.logResults }; - + return this; - - - - + + + + var refLocal = {}; var debugString = "target: #arguments.invocation.getTargetName()#,method: #arguments.invocation.getMethod()#,arguments:#serializeJSON(arguments.invocation.getArgs())#"; - + // log incoming call log.debug(debugString); - + // proceed execution refLocal.results = arguments.invocation.proceed(); - + // result logging and returns - if( structKeyExists(refLocal,"results") ){ + if( structKeyExists(refLocal,"results") ){ if( instance.logResults ){ log.debug("#debugString#, results:", refLocal.results); } - return refLocal.results; + return refLocal.results; } - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc b/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc index 573156505..6071a6f42 100644 --- a/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc +++ b/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc @@ -1,4 +1,4 @@ - - + + + @@ -31,7 +31,7 @@ Description : scopePointer[arguments.key] = arguments.value; - + @@ -39,7 +39,7 @@ Description : return structDelete(getScope(arguments.scope),arguments.key,true); - + @@ -55,22 +55,22 @@ Description : - + - return structKeyExists(getScope(arguments.scope),arguments.key); + return structKeyExists(getScope(arguments.scope),arguments.key); - + scopeCheck(arguments.scope); - + switch( arguments.scope ){ - case "session" : { + case "session" : { if( isDefined("session") ){ return session; } @@ -85,9 +85,9 @@ Description : case "cluster" : return cluster; case "request" : return request; } - + - + @@ -106,7 +106,7 @@ Description : - + @@ -116,6 +116,6 @@ Description : - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc b/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc index 3d785b143..6ad80877c 100644 --- a/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc +++ b/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc @@ -1,4 +1,4 @@ - var objFile = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); // Calculate adjustments fot timezone and daylightsavindtime var Offset = ((GetTimeZoneInfo().utcHourOffset)+1)*-3600; // Date is returned as number of seconds since 1-1-1970 return DateAdd('s', (Round(objFile.lastModified()/1000))+Offset, CreateDateTime(1970, 1, 1, 0, 0, 0)); var objFile = createObject("java","java.io.File"); objFile.init(JavaCast("string", filename)); if ( arguments.sizeFormat eq "bytes" ) return objFile.length(); if ( arguments.sizeFormat eq "kbytes" ) return (objFile.length()/1024); if ( arguments.sizeFormat eq "mbytes" ) return (objFile.length()/(1048576)); if ( arguments.sizeFormat eq "gbytes" ) return (objFile.length()/1073741824); var fileObj = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); return fileObj.delete(); var fileObj = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); fileObj.createNewFile(); var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); return FileObj.canWrite(); var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); return FileObj.canRead(); var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); return FileObj.isFile(); var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); return FileObj.isDirectory(); var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.path)); if(FileObj.isAbsolute()){ return arguments.path; } else{ return ExpandPath(arguments.path); } if ( listFindNoCase(this.CHAR_SETS,lcase(arguments.charset)) ) return this.DEFAULT_CHAR_SET; else return arguments.charset; \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + var objFile = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); + // Calculate adjustments fot timezone and daylightsavindtime + var Offset = ((GetTimeZoneInfo().utcHourOffset)+1)*-3600; + // Date is returned as number of seconds since 1-1-1970 + return DateAdd('s', (Round(objFile.lastModified()/1000))+Offset, CreateDateTime(1970, 1, 1, 0, 0, 0)); + + + + + + + + + + + var objFile = createObject("java","java.io.File"); + objFile.init(JavaCast("string", filename)); + if ( arguments.sizeFormat eq "bytes" ) + return objFile.length(); + if ( arguments.sizeFormat eq "kbytes" ) + return (objFile.length()/1024); + if ( arguments.sizeFormat eq "mbytes" ) + return (objFile.length()/(1048576)); + if ( arguments.sizeFormat eq "gbytes" ) + return (objFile.length()/1073741824); + + + + + + + + + + var fileObj = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); + return fileObj.delete(); + + + + + + + + + + var fileObj = createObject("java","java.io.File").init(JavaCast("string",arguments.filename)); + fileObj.createNewFile(); + + + + + + + + + + var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); + return FileObj.canWrite(); + + + + + + + + + + var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); + return FileObj.canRead(); + + + + + + + + + + var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); + return FileObj.isFile(); + + + + + + + + + + var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.Filename)); + return FileObj.isDirectory(); + + + + + + + + + + var FileObj = CreateObject("java","java.io.File").init(JavaCast("String",arguments.path)); + if(FileObj.isAbsolute()){ + return arguments.path; + } + else{ + return ExpandPath(arguments.path); + } + + + + + + + + + + if ( listFindNoCase(this.CHAR_SETS,lcase(arguments.charset)) ) + return this.DEFAULT_CHAR_SET; + else + return arguments.charset; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc b/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc index 8ce4e3185..746c1bc8b 100644 --- a/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc +++ b/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc @@ -1,4 +1,4 @@ -/** +/** ******************************************************************************** * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp * www.ortussolutions.com diff --git a/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc b/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc index de45bc936..ab39dc366 100644 --- a/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc +++ b/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc @@ -1,4 +1,4 @@ - - + - + - + @@ -27,7 +27,7 @@ Description : - + @@ -36,5 +36,5 @@ Description : - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/IProvider.cfc b/src/cfml/system/wirebox/system/ioc/IProvider.cfc index 34ba4687a..1a451099e 100644 --- a/src/cfml/system/wirebox/system/ioc/IProvider.cfc +++ b/src/cfml/system/wirebox/system/ioc/IProvider.cfc @@ -1,4 +1,4 @@ - - + diff --git a/src/cfml/system/wirebox/system/ioc/Injector.cfc b/src/cfml/system/wirebox/system/ioc/Injector.cfc index 203bb7d5f..da9d3e003 100644 --- a/src/cfml/system/wirebox/system/ioc/Injector.cfc +++ b/src/cfml/system/wirebox/system/ioc/Injector.cfc @@ -1,4 +1,4 @@ - - + @@ -26,11 +26,11 @@ Description : scopeStorage = arguments.scopeStorage, targetObject = arguments.targetObject }; - + // Verify incoming name or DSL if( structKeyExists( arguments, "name" ) ){ instance.name = arguments.name; } if( structKeyExists( arguments, "dsl" ) ){ instance.dsl = arguments.dsl; } - + return this; @@ -39,7 +39,7 @@ Description : var scopeInfo = instance.scopeRegistration; - + // Return if scope exists, else throw exception if( instance.scopeStorage.exists(scopeInfo.key, scopeInfo.scope) ){ // retrieve by name or DSL @@ -49,24 +49,24 @@ Description : return instance.scopeStorage.get( scopeInfo.key, scopeInfo.scope ).getInstance( dsl=instance.dsl, targetObject=instance.targetObject ); } - + - + - + - + - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/Scopes.cfc b/src/cfml/system/wirebox/system/ioc/Scopes.cfc index dd273615d..c11dc393e 100644 --- a/src/cfml/system/wirebox/system/ioc/Scopes.cfc +++ b/src/cfml/system/wirebox/system/ioc/Scopes.cfc @@ -1,4 +1,4 @@ - //DECLARED SCOPES this.NOSCOPE = "NoScope"; this.PROTOTYPE = "NoScope"; - this.SINGLETON = "singleton"; + this.SINGLETON = "singleton"; this.SESSION = "session"; this.APPLICATION = "application"; this.REQUEST = "request"; this.SERVER = "server"; this.CACHEBOX = "cachebox"; - + function isValidScope(scope){ var key = ""; for(key in this){ @@ -30,7 +30,7 @@ Description : } return false; } - + function getValidScopes(){ var key = ""; var scopes = {}; diff --git a/src/cfml/system/wirebox/system/ioc/Types.cfc b/src/cfml/system/wirebox/system/ioc/Types.cfc index 768dfab5e..3b799bef0 100644 --- a/src/cfml/system/wirebox/system/ioc/Types.cfc +++ b/src/cfml/system/wirebox/system/ioc/Types.cfc @@ -1,4 +1,4 @@ - - + //DECLARED WIREBOX INSTANTIATION TYPES this.CFC = "cfc"; this.JAVA = "java"; - this.WEBSERVICE = "webservice"; - this.RSS = "rss"; + this.WEBSERVICE = "webservice"; + this.RSS = "rss"; this.DSL = "dsl"; this.CONSTANT = "constant"; this.FACTORY = "factory"; this.PROVIDER = "provider"; - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/config/Binder.cfc b/src/cfml/system/wirebox/system/ioc/config/Binder.cfc index 8ff02b59f..505152658 100644 --- a/src/cfml/system/wirebox/system/ioc/config/Binder.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/Binder.cfc @@ -1,4 +1,4 @@ - - + /** * Configure WireBox, that's it! */ function configure(){ - + // The WireBox configuration structure DSL wireBox = { // Default LogBox Configuration file - logBoxConfig = "wirebox.system.ioc.config.LogBox", - + logBoxConfig = "wirebox.system.ioc.config.LogBox", + // CacheBox Integration OFF by default cacheBox = { - enabled = false + enabled = false // configFile = "wirebox.system.ioc.config.CacheBox", An optional configuration file to use for loading CacheBox // cacheFactory = "" A reference to an already instantiated CacheBox CacheFactory // classNamespace = "" A class path namespace to use to create CacheBox: Default=wirebox.system.cache or wirebox.system.cache - }, - + }, + // Scope registration, automatically register a wirebox injector instance on any CF scope // By default it registeres itself on application scope scopeRegistration = { @@ -41,26 +41,26 @@ Description : customDSL = { // namespace = "mapping name" }, - + // Custom Storage Scopes customScopes = { // annotationName = "mapping name" }, - + // Package scan locations scanLocations = [], - + // Stop Recursions stopRecursions = [], - + // Parent Injector to assign to the configured injector, this must be an object reference parentInjector = "", - + // Register all event listeners here, they are created in the specified order listeners = [ // { class="", name="", properties={} } - ] + ] }; - } + } \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc b/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc index f598972de..d5174f777 100644 --- a/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc @@ -1,4 +1,4 @@ - - + + + - + - + @@ -17,16 +17,16 @@ - + for(key in variables){ if( isCustomFunction( variables[key] ) AND NOT structKeyExists(this, key) ){ this[ key ] = variables[ key ]; } - } + } return this; - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc index 87472a370..a57019067 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc @@ -1,4 +1,4 @@ - @@ -18,11 +18,11 @@ Description : instance = { injector = arguments.injector }; instance.cacheBox = instance.injector.getCacheBox(); instance.log = instance.injector.getLogBox().getLogger( this ); - + return this; - + - + @@ -32,7 +32,7 @@ Description : var thisTypeLen = listLen(thisType,":"); var cacheName = ""; var cacheElement = ""; - + // DSL stages switch(thisTypeLen){ // CacheBox @@ -63,7 +63,7 @@ Description : break; } // end level 3 main DSL } - - - + + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc index 0f0f78d66..40d83ee21 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc @@ -1,4 +1,4 @@ - @@ -15,12 +15,12 @@ Description : - + - + - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc index e3ad78981..28e07db1e 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc @@ -1,4 +1,4 @@ - @@ -18,11 +18,11 @@ Description : instance = { injector = arguments.injector }; instance.logBox = instance.injector.getLogBox(); instance.log = instance.logBox.getLogger( this ); - + return this; - + - + @@ -32,12 +32,12 @@ Description : var thisTypeLen = listLen(thisType,":"); var thisLocationType = ""; var thisLocationKey = ""; - + // DSL stages switch(thisTypeLen){ // logbox case 1 : { return instance.logBox; } - // logbox:root and logbox:logger + // logbox:root and logbox:logger case 2 : { thisLocationKey = getToken(thisType,2,":"); switch( thisLocationKey ){ @@ -53,19 +53,19 @@ Description : // DSL Level 2 Stage Types switch(thisLocationType){ // Get a named Logger - case "logger" : { + case "logger" : { // Check for {this} and targetobject exists - if( thisLocationKey eq "{this}" AND structKeyExists(arguments, "targetObject") ){ - return instance.logBox.getLogger( arguments.targetObject ); + if( thisLocationKey eq "{this}" AND structKeyExists(arguments, "targetObject") ){ + return instance.logBox.getLogger( arguments.targetObject ); } // Normal Logger injection - return instance.logBox.getLogger(thisLocationKey); break; + return instance.logBox.getLogger(thisLocationKey); break; } } break; } // end level 3 main DSL } - - - + + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc b/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc index 0ca59b1a4..72f33e9df 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc @@ -1,4 +1,4 @@ - @@ -20,7 +20,7 @@ Description : - + - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc b/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc index dbc79e0ef..928a40021 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc @@ -1,4 +1,4 @@ - @@ -35,5 +35,5 @@ Description : return object; - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc b/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc index 1f72bf5e8..1289334cf 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc @@ -1,4 +1,4 @@ - @@ -20,20 +20,20 @@ Description : // A line Sep Constant, man, wish we had final in CF. this.LINE_SEP = chr(13) & chr(10); - + - + // The appender we are linked to. instance.appender = arguments.appender; - - // Return + + // Return return this; - + @@ -42,5 +42,5 @@ Description : - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/LogBox.cfc b/src/cfml/system/wirebox/system/logging/LogBox.cfc index 021a9f26f..7254dfc14 100644 --- a/src/cfml/system/wirebox/system/logging/LogBox.cfc +++ b/src/cfml/system/wirebox/system/logging/LogBox.cfc @@ -1,4 +1,4 @@ - @@ -31,32 +31,32 @@ Description : var key = ""; for(key in arguments){ if( isSimpleValue(arguments[key]) ){ - arguments[key] = trim(arguments[key]); + arguments[key] = trim(arguments[key]); } instance[key] = arguments[key]; } return this; - + // Simple value, just return it if( isSimpleValue(instance.extraInfo) ){ return instance.extraInfo; } - + // Convention translation: $toString(); if( isObject(instance.extraInfo) AND structKeyExists(instance.extraInfo,"$toString") ){ return instance.extraInfo.$toString(); } - + // Component XML conversion if( isObject(instance.extraInfo) ){ return instance.xmlConverter.toXML( instance.extraInfo ); } - + // Complex values, return serialized in json - return serializeJSON( instance.extraInfo ); + return serializeJSON( instance.extraInfo ); - + @@ -64,7 +64,7 @@ Description : - + @@ -72,7 +72,7 @@ Description : - + @@ -80,7 +80,7 @@ Description : - + @@ -88,7 +88,7 @@ Description : - + diff --git a/src/cfml/system/wirebox/system/logging/LogLevels.cfc b/src/cfml/system/wirebox/system/logging/LogLevels.cfc index 9e0e7ff89..ed9cf729b 100644 --- a/src/cfml/system/wirebox/system/logging/LogLevels.cfc +++ b/src/cfml/system/wirebox/system/logging/LogLevels.cfc @@ -1,4 +1,4 @@ -/** +/** ********************************************************************************* * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp * www.ortussolutions.com @@ -15,14 +15,14 @@ component{ this.WARN = 2; this.INFO = 3; this.DEBUG = 4; - + // List of valid levels this.VALIDLEVELS = "off,fatal,error,warn,info,debug"; - + // Max this.MINLEVEL = -1; this.MAXLEVEL = 4; - + function lookup(level){ switch(level){ case -1: return "OFF"; @@ -30,10 +30,10 @@ component{ case 1: return "ERROR"; case 2: return "WARN"; case 3: return "INFO"; - case 4: return "DEBUG"; + case 4: return "DEBUG"; } } - + function lookupAsInt(level){ switch(level){ case "OFF": return -1; @@ -43,11 +43,11 @@ component{ case "WARNING" : return 2; case "INFO": return 3; case "INFORMATION" : return 3; - case "DEBUG": return 4; - default: return 999; + case "DEBUG": return 4; + default: return 999; } } - + function lookupCF(level){ switch(level){ case -1: return "OFF"; @@ -56,10 +56,10 @@ component{ case 2: return "Warning"; case 3: return "Information"; case 4: return "Information"; - default: return "Information"; + default: return "Information"; } } - + function isLevelValid(level){ return ( arguments.level gte this.MINLEVEL AND arguments.level lte this.MAXLEVEL ); } diff --git a/src/cfml/system/wirebox/system/logging/Logger.cfc b/src/cfml/system/wirebox/system/logging/Logger.cfc index 0dc07b27d..19c98e2b0 100644 --- a/src/cfml/system/wirebox/system/logging/Logger.cfc +++ b/src/cfml/system/wirebox/system/logging/Logger.cfc @@ -1,4 +1,4 @@ - - - + @@ -30,7 +30,7 @@ Properties: // Init supertype super.init(argumentCollection=arguments); - + // Verify properties if( NOT propertyExists('logType') ){ setProperty("logType","file"); @@ -46,11 +46,11 @@ Properties: if( NOT propertyExists("fileName") ){ setProperty("fileName", getName()); } - + return this; - - + + @@ -58,15 +58,15 @@ Properties: - + - + - @@ -74,10 +74,10 @@ Properties: type="#this.logLevels.lookupCF(loge.getSeverity())#" text="#entry#"> - + - + - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc index 224b4957a..24d90d860 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc @@ -1,4 +1,4 @@ -/** +/** ********************************************************************************* * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp * www.ortussolutions.com @@ -21,7 +21,7 @@ component extends="wirebox.system.logging.AbstractAppender"{ struct properties = {}, string layout = "", string levelMin = 0, - string levelMax = 4 + string levelMax = 4 ){ super.init( argumentCollection=arguments ); instance.out = createObject( "java", "java.lang.System" ).out; @@ -42,10 +42,10 @@ component extends="wirebox.system.logging.AbstractAppender"{ logEvent.getmessage() & " ExtraInfo: " & logEvent.getextraInfoAsString(); } - + // log message instance.out.println( entry ); - + return; } diff --git a/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc index 3d5cad1f3..c5f3f8690 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc @@ -1,4 +1,4 @@ - - - + @@ -50,21 +50,21 @@ If you are building a mapper, the map must have the above keys in it. // Init supertype super.init(argumentCollection=arguments); - + // valid columns instance.columns = "id,severity,category,logdate,appendername,message,extrainfo"; // UUID generator instance.uuid = createobject("java", "java.util.UUID"); - + // Verify properties - if( NOT propertyExists('dsn') ){ - throw(message="No dsn property defined",type="DBAppender.InvalidProperty"); + if( NOT propertyExists('dsn') ){ + throw(message="No dsn property defined",type="DBAppender.InvalidProperty"); } - if( NOT propertyExists('table') ){ - throw(message="No table property defined",type="DBAppender.InvalidProperty"); + if( NOT propertyExists('table') ){ + throw(message="No table property defined",type="DBAppender.InvalidProperty"); } - if( NOT propertyExists('autoCreate') OR NOT isBoolean(getProperty('autoCreate')) ){ - setProperty('autoCreate',false); + if( NOT propertyExists('autoCreate') OR NOT isBoolean(getProperty('autoCreate')) ){ + setProperty('autoCreate',false); } if( NOT propertyExists('defaultCategory') ){ setProperty("defaultCategory",arguments.name); @@ -90,15 +90,15 @@ If you are building a mapper, the map must have the above keys in it. if( NOT propertyExists( "schema" ) ){ setProperty( "schema", "" ); } - - + + // DB Rotation Time instance.lastDBRotation = ""; - + return this; - - + + @@ -108,7 +108,7 @@ If you are building a mapper, the map must have the above keys in it. } - + @@ -121,12 +121,12 @@ If you are building a mapper, the map must have the above keys in it. var cols = ""; var loge = arguments.logEvent; var message = loge.getMessage(); - + // Check Category Sent? if( NOT loge.getCategory() eq "" ){ category = loge.getCategory(); } - + // Column Maps if( propertyExists('columnMap') ){ cmap = getProperty('columnMap'); @@ -136,7 +136,7 @@ If you are building a mapper, the map must have the above keys in it. cols = instance.columns; } - + INSERT INTO #getTable()# (#cols#) VALUES ( @@ -149,47 +149,47 @@ If you are building a mapper, the map must have the above keys in it. ) - + - - - - + + + + // Verify if in rotation frequency if( isDate( instance.lastDBRotation ) AND dateDiff( "n", instance.lastDBRotation, now() ) LTE getProperty( "rotationFrequency" ) ){ return; } - + // Rotations this.doRotation(); - + // Store last profile time - instance.lastDBRotation = now(); - + instance.lastDBRotation = now(); + - - - + + + - + DELETE FROM #getTable()# WHERE #listgetAt( cols,4)# < - + - + - + if( len( getProperty( 'schema' ) ) ){ - return getProperty( 'schema' ) & "." & getProperty( 'table' ); + return getProperty( 'schema' ) & "." & getProperty( 'table' ); } return getProperty( 'table' ); @@ -202,7 +202,7 @@ If you are building a mapper, the map must have the above keys in it. - + @@ -213,7 +213,7 @@ If you are building a mapper, the map must have the above keys in it. - + @@ -236,13 +236,13 @@ If you are building a mapper, the map must have the above keys in it. type="DBAppender.TableNotFoundException"> - + var map = getProperty('columnMap'); var key = ""; - + for(key in map){ if( NOT listFindNoCase(instance.columns,key) ){ throw(message="Invalid column map key: #key#",detail="The available keys are #instance.columns#",type="DBAppender.InvalidColumnMapException"); @@ -250,12 +250,12 @@ If you are building a mapper, the map must have the above keys in it. } - - - + + + - + switch( qResults.database_productName ){ case "PostgreSQL" : { return "cf_sql_timestamp"; @@ -272,15 +272,15 @@ If you are building a mapper, the map must have the above keys in it. default : { return "cf_sql_timestamp"; } - } - + } + - - + + - + switch( qResults.database_productName ){ case "PostgreSQL" : { return "TIMESTAMP"; @@ -297,8 +297,8 @@ If you are building a mapper, the map must have the above keys in it. default : { return "DATETIME"; } - } - + } + - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc index d35051168..2b25dd56a 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc @@ -1,4 +1,4 @@ - - - + @@ -28,20 +28,20 @@ Properties: // Init supertype super.init(argumentCollection=arguments); - + return this; - - + + - + - + - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc index cbf36420b..cbcb871b6 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc @@ -1,4 +1,4 @@ - - - + - + @@ -37,20 +37,20 @@ Properties: super.init(argumentCollection=arguments); - + if( NOT propertyExists("fileMaxSize") OR NOT isNumeric(getProperty("fileMaxSize")) ){ setProperty("fileMaxSize","2000"); } if( NOT propertyExists("fileMaxArchives") OR NOT isNumeric(getProperty("fileMaxArchives")) ){ setProperty("fileMaxArchives","2"); } - + instance.fileRotator = createObject("component","wirebox.system.logging.util.FileRotator").init(); - + return this; - + @@ -59,7 +59,7 @@ Properties: // Log the message in the super. super.logMessage(arguments.logEvent); - + // Rotate try{ instance.fileRotator.checkRotation(this); @@ -71,6 +71,6 @@ Properties: - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc index 0ddc55529..d50336f5a 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc @@ -1,4 +1,4 @@ - - - + @@ -33,7 +33,7 @@ Properties: // Init supertype super.init(argumentCollection=arguments); - + // Verify properties if( NOT propertyExists('scope') ){ setProperty("scope","request"); @@ -44,19 +44,19 @@ Properties: if( NOT propertyExists('limit') OR NOT isNumeric(getProperty("limit"))){ setProperty("limit",0); } - + // Scope storage instance.scopeStorage = createObject("component","wirebox.system.core.collections.ScopeStorage").init(); // Scope Checks instance.scopeStorage.scopeCheck(getproperty('scope')); // UUID generator instance.uuid = createobject("java", "java.util.UUID"); - - + + return this; - - + + @@ -67,18 +67,18 @@ Properties: var entry = structnew(); var limit = getProperty('limit'); var loge = arguments.logEvent; - + // Verify storage ensureStorage(); - + // Check Limits logStack = getStorage(); - + if( limit GT 0 and arrayLen(logStack) GTE limit ){ // pop one out, the oldest arrayDeleteAt(logStack,1); } - + // Log Away entry.id = instance.uuid.randomUUID().toString(); entry.logDate = loge.getTimeStamp(); @@ -87,13 +87,13 @@ Properties: entry.message = loge.getMessage(); entry.extraInfo = loge.getextraInfo(); entry.category = loge.getCategory(); - + // Save Storage arrayAppend(logStack, entry); - saveStorage(logStack); - + saveStorage(logStack); + - + @@ -102,7 +102,7 @@ Properties: - + @@ -119,6 +119,6 @@ Properties: } - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc index ca843eff0..59b2f66b8 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc @@ -1,4 +1,4 @@ - - - + @@ -33,7 +33,7 @@ Properties: // Init supertype super.init(argumentCollection=arguments); - + // Verify properties if( NOT propertyExists('host') ){ throw(message="The host must be provided",type="SocketAppender.HostNotFound"); @@ -47,29 +47,29 @@ Properties: if( NOT propertyExists('persistConnection') ){ setProperty("persistConnection",true); } - + // Socket storage instance.socket = ""; instance.socketWriter = ""; - + return this; - - + + - + - + @@ -78,20 +78,20 @@ Properties: var loge = arguments.logEvent; var entry = ""; - + // Prepare entry to send. if( hasCustomLayout() ){ entry = getCustomLayout().format(loge); } else{ entry = "#severityToString(loge.getseverity())# #loge.getCategory()# #loge.getmessage()# ExtraInfo: #loge.getextraInfoAsString()#"; - } - + } + // Open connection? if( NOT getProperty("persistConnection") ){ openConnection(); } - + // Send data to Socket try{ getSocketWriter().println(entry); @@ -99,22 +99,22 @@ Properties: catch(Any e){ $log("ERROR","#getName()# - Error sending entry to socket #getProperties().toString()#. #e.message# #e.detail#"); } - + // Close Connection? if( NOT getProperty("persistConnection") ){ closeConnection(); - } - + } + - + - + - + @@ -130,7 +130,7 @@ Properties: } // Set Timeout instance.socket.setSoTimeout(javaCast("int",getProperty("timeout") * 1000)); - + //Prepare Writer instance.socketWriter = createObject("java","java.io.PrintWriter").init(instance.socket.getOutputStream()); @@ -143,6 +143,6 @@ Properties: getSocket().close(); - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc index b47164244..22af474c5 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc @@ -1,4 +1,4 @@ - - - + @@ -28,11 +28,11 @@ Properties: // Init supertype super.init(argumentCollection=arguments); - + return this; - - + + @@ -42,14 +42,14 @@ Properties: var loge = arguments.logEvent; var entry = ""; var traceSeverity = "information"; - + if ( hasCustomLayout() ){ entry = getCustomLayout().format(loge); } else{ entry = "#loge.getMessage()# ExtraInfo: #loge.getextraInfoAsString()#"; } - + // Severity by cftrace switch( this.logLevels.lookupCF(loge.getSeverity()) ){ case "FATAL" : { traceSeverity = "fatal information"; break; } @@ -57,14 +57,14 @@ Properties: case "WARN" : { traceSeverity = "warning"; break; } } - + - + - - + + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc b/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc index 471a3bbba..545774ab7 100644 --- a/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc +++ b/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc @@ -1,4 +1,4 @@ - var logBoxDSL = arguments.rawDSL; var key = ""; - + // Are appenders defined? if( NOT structKeyExists( logBoxDSL, "appenders" ) ){ throw("No appenders defined","Please define at least one appender","#getMetadata(this).name#.NoAppendersFound"); @@ -70,13 +70,13 @@ Description : logBoxDSL.appenders[key].name = key; appender(argumentCollection=logBoxDSL.appenders[key]); } - + // Register Root Logger if( NOT structKeyExists( logBoxDSL, "root" ) ){ throw("No Root Logger Defined","Please define the root logger","#getMetadata(this).name#.NoRootLoggerException"); } root(argumentCollection=logBoxDSL.root); - + // Register Categories if( structKeyExists( logBoxDSL, "categories") ){ for( key in logBoxDSL.categories ){ @@ -84,29 +84,29 @@ Description : category(argumentCollection=logBoxDSL.categories[key]); } } - + // Register Level Categories - if( structKeyExists( logBoxDSL, "debug" ) ){ + if( structKeyExists( logBoxDSL, "debug" ) ){ DEBUG(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.debug) ); } - if( structKeyExists( logBoxDSL, "info" ) ){ + if( structKeyExists( logBoxDSL, "info" ) ){ INFO(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.info) ); } - if( structKeyExists( logBoxDSL, "warn" ) ){ + if( structKeyExists( logBoxDSL, "warn" ) ){ WARN(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.warn) ); } - if( structKeyExists( logBoxDSL, "error" ) ){ + if( structKeyExists( logBoxDSL, "error" ) ){ ERROR(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.error) ); } - if( structKeyExists( logBoxDSL, "fatal" ) ){ + if( structKeyExists( logBoxDSL, "fatal" ) ){ FATAL(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.fatal) ); } - if( structKeyExists( logBoxDSL, "off" ) ){ + if( structKeyExists( logBoxDSL, "off" ) ){ OFF(argumentCollection=variables.utility.arrayToStruct(logBoxDSL.off) ); - } + } - + @@ -118,33 +118,33 @@ Description : instance.rootLogger = structnew(); - + - + - + - + - + var x=1; var key =""; - + // Are appenders defined if( structIsEmpty(instance.appenders) ){ throw(message="Invalid Configuration. No appenders defined.",type="#getMetadata(this).name#.NoAppendersFound"); @@ -153,7 +153,7 @@ Description : if( structIsEmpty(instance.rootLogger) ){ throw(message="Invalid Configuration. No root logger defined.",type="#getMetadata(this).name#.RootLoggerNotFound"); } - + // All root appenders? if( instance.rootLogger.appenders eq "*"){ instance.rootLogger.appenders = structKeyList(getAllAppenders()); @@ -166,15 +166,15 @@ Description : type="#getMetadata(this).name#.AppenderNotFound"); } } - + // Check all Category Appenders for(key in instance.categories){ - + // Check * all appenders if( instance.categories[key].appenders eq "*"){ instance.categories[key].appenders = structKeyList(getAllAppenders()); } - + for(x=1; x lte listlen(instance.categories[key].appenders); x=x+1){ if( NOT structKeyExists(instance.appenders, listGetAt(instance.categories[key].appenders,x)) ){ throw(message="Invalid appender in Category: #key#", @@ -185,7 +185,7 @@ Description : } - + @@ -194,20 +194,20 @@ Description : - + // Convert Levels convertLevels(arguments); - + // Check levels levelChecks(arguments.levelMin, arguments.levelMax); - + // Register appender instance.appenders[arguments.name] = arguments; - + return this; - + @@ -217,10 +217,10 @@ Description : var x = 1; // Convert Levels convertLevels(arguments); - + // Check levels levelChecks(arguments.levelMin, arguments.levelMax); - + //Verify appender list if( NOT listLen(arguments.appenders) ){ throw("Invalid Appenders","Please send in at least one appender for the root logger","#getMetadata(this).name#.InvalidAppenders"); @@ -228,16 +228,16 @@ Description : // Add definition instance.rootLogger = arguments; - + return this; - + - + @@ -247,41 +247,41 @@ Description : // Convert Levels convertLevels(arguments); - + // Check levels levelChecks(arguments.levelMin, arguments.levelMax); - + // Add category registration instance.categories[arguments.name] = arguments; - + return this; - + - + - + - + - + - + @@ -292,7 +292,7 @@ Description : return this; - + @@ -303,7 +303,7 @@ Description : return this; - + @@ -314,7 +314,7 @@ Description : return this; - + @@ -325,7 +325,7 @@ Description : return this; - + @@ -336,7 +336,7 @@ Description : return this; - + @@ -362,7 +362,7 @@ Description : if( structKeyExists(arguments.target, "levelMax") and NOT isNumeric(arguments.target.levelMax)){ arguments.target.levelMax = this.logLevels.lookupAsInt(arguments.target.levelMax); } - + // For chaining return arguments.target; @@ -378,5 +378,5 @@ Description : - + \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc b/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc index ff9f30cf6..12499b66c 100644 --- a/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc +++ b/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp * www.ortussolutions.com ******************************************************************************** @@ -13,9 +13,9 @@ component{ logBox = { // Define Appenders appenders = { - coldboxTracer = { + coldboxTracer = { class="wirebox.system.logging.appenders.ConsoleAppender", - layout="coldbox.testing.cases.logging.MockLayout", + layout="coldbox.testing.cases.logging.MockLayout", properties = { name = "awesome" } @@ -34,8 +34,8 @@ component{ warn = [ "hello.model", "yes.wow.wow" ], error = [ "hello.model", "yes.wow.wow" ], fatal = [ "hello.model", "yes.wow.wow" ], - OFF = [ "hello.model", "yes.wow.wow" ] + OFF = [ "hello.model", "yes.wow.wow" ] }; } -} +} \ No newline at end of file diff --git a/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc b/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc index c72df1d07..028e183d7 100644 --- a/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc +++ b/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc @@ -1,4 +1,4 @@ - - \ No newline at end of file + diff --git a/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/specs/BDDTest.cfc b/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/specs/BDDTest.cfc index d1265c4b3..e4ffc10d3 100644 --- a/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/specs/BDDTest.cfc +++ b/src/cfml/system/modules_app/testbox-commands/templates/testbox/test-harness/specs/BDDTest.cfc @@ -104,4 +104,4 @@ component extends="coldbox.system.BaseSpec"{ return ( structKeyExists( server, "railo" ) ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc index f63d54e5b..9ca442169 100644 --- a/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc +++ b/src/cfml/system/modules_app/utils-commands/ModuleConfig.cfc @@ -8,4 +8,4 @@ */ component { function configure(){} -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc index 81ad8b11a..696f772fc 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc @@ -101,4 +101,4 @@ component aliases="eol" { return chr( 10 ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc index 267fb7a1c..c8cb43102 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -114,4 +114,4 @@ component aliases="rts" { return chr( 10 ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/wirebox-commands/ModuleConfig.cfc index a400988b5..1531d200d 100644 --- a/src/cfml/system/modules_app/wirebox-commands/ModuleConfig.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/ModuleConfig.cfc @@ -8,4 +8,4 @@ component { function configure() { } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc index 0f46de0ac..0b1aa06c2 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/aspect.cfc @@ -10,4 +10,4 @@ component { print.line( "Command not implemented!" ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc index 0f46de0ac..0b1aa06c2 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/binder.cfc @@ -10,4 +10,4 @@ component { print.line( "Command not implemented!" ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc index 0f46de0ac..0b1aa06c2 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/dsl.cfc @@ -10,4 +10,4 @@ component { print.line( "Command not implemented!" ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc index 9094360cd..82620a6c9 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/help.cfc @@ -9,4 +9,4 @@ component excludeFromHelp=true { } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc index 0f46de0ac..0b1aa06c2 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/create/scope.cfc @@ -10,4 +10,4 @@ component { print.line( "Command not implemented!" ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc index 675d29a95..c47a412a2 100644 --- a/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc +++ b/src/cfml/system/modules_app/wirebox-commands/commands/wirebox/help.cfc @@ -9,4 +9,4 @@ component excludeFromHelp=true { } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/ArtifactService.cfc b/src/cfml/system/services/ArtifactService.cfc index a592fee94..a36aab35e 100644 --- a/src/cfml/system/services/ArtifactService.cfc +++ b/src/cfml/system/services/ArtifactService.cfc @@ -271,4 +271,4 @@ component accessors="true" singleton { string function getArtifactsDirectory() { return configService.getSetting( 'artifactsDirectory', variables.artifactDir ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index daa58d23f..9ad40f254 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -1049,4 +1049,4 @@ component accessors="true" singleton { } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index b22bdb3e9..da58780a6 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -177,4 +177,4 @@ component accessors="true" singleton { } return props; } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/EndpointService.cfc b/src/cfml/system/services/EndpointService.cfc index ee11c3d2a..861ec429a 100644 --- a/src/cfml/system/services/EndpointService.cfc +++ b/src/cfml/system/services/EndpointService.cfc @@ -280,4 +280,4 @@ component accessors="true" singleton { endpoint.unpublish( argumentCollection=arguments ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/InterceptorService.cfc b/src/cfml/system/services/InterceptorService.cfc index 9f88a8211..9401d8345 100644 --- a/src/cfml/system/services/InterceptorService.cfc +++ b/src/cfml/system/services/InterceptorService.cfc @@ -180,4 +180,4 @@ component accessors=true singleton { return getEventPoolManager().unregister( arguments.name, arguments.state ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/JSONService.cfc b/src/cfml/system/services/JSONService.cfc index f36ff27f2..04806c001 100644 --- a/src/cfml/system/services/JSONService.cfc +++ b/src/cfml/system/services/JSONService.cfc @@ -204,4 +204,4 @@ component accessors="true" singleton { return props; } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index af1be7ad4..8d7e49f57 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -828,4 +828,4 @@ - \ No newline at end of file + diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 1e581bf2d..5539cf3ea 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -1111,4 +1111,4 @@ component accessors="true" singleton { consoleLogger.error( 'The script [#arguments.scriptName#] does not exist in this package.' ); } } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index 975ec3df6..06265ac47 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -357,4 +357,4 @@ component accessors="true" singleton="true" { return true; } -} \ No newline at end of file +} diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 7163e01a9..df08162ff 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1734,4 +1734,4 @@ component accessors="true" singleton { return props; } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/ANSIConsoleAppender.cfc b/src/cfml/system/util/ANSIConsoleAppender.cfc index c5ac5e880..0a413ca04 100644 --- a/src/cfml/system/util/ANSIConsoleAppender.cfc +++ b/src/cfml/system/util/ANSIConsoleAppender.cfc @@ -74,4 +74,4 @@ component extends="wirebox.system.logging.AbstractAppender" { return variables.printBuffer; } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/CommandDSL.cfc b/src/cfml/system/util/CommandDSL.cfc index 899d5983a..b30628d0d 100644 --- a/src/cfml/system/util/CommandDSL.cfc +++ b/src/cfml/system/util/CommandDSL.cfc @@ -202,4 +202,4 @@ component accessors=true { } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/Completor.cfc b/src/cfml/system/util/Completor.cfc index c3589f7bc..f4849e79f 100644 --- a/src/cfml/system/util/Completor.cfc +++ b/src/cfml/system/util/Completor.cfc @@ -433,4 +433,4 @@ component singleton { } } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/Executor.cfc b/src/cfml/system/util/Executor.cfc index 6753ff951..12ef451d6 100644 --- a/src/cfml/system/util/Executor.cfc +++ b/src/cfml/system/util/Executor.cfc @@ -85,4 +85,4 @@ component { return $wirebox.getInstance( argumentCollection = arguments ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 1540ac6f6..b37a96a43 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -253,4 +253,4 @@ component accessors="true" singleton { } } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 4e3e104c6..7eb7bbdd1 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -511,4 +511,4 @@ or just add DEBUG to the root logger - \ No newline at end of file + diff --git a/src/cfml/system/util/Formatter.cfc b/src/cfml/system/util/Formatter.cfc index 33ed4a427..112660895 100644 --- a/src/cfml/system/util/Formatter.cfc +++ b/src/cfml/system/util/Formatter.cfc @@ -101,4 +101,4 @@ component singleton { // This is an external lib now. Leaving here for backwards compat. return JSONPrettyPrint.formatJSON( json ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/Parser.cfc b/src/cfml/system/util/Parser.cfc index cfe2fa104..e96159f27 100644 --- a/src/cfml/system/util/Parser.cfc +++ b/src/cfml/system/util/Parser.cfc @@ -318,4 +318,4 @@ component { } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/Print.cfc b/src/cfml/system/util/Print.cfc index 8ac9ce372..d33240402 100644 --- a/src/cfml/system/util/Print.cfc +++ b/src/cfml/system/util/Print.cfc @@ -198,4 +198,4 @@ component { return ' ' & replaceNoCase( arguments.text, this.cr, this.cr & ' ', 'all' ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/PrintBuffer.cfc b/src/cfml/system/util/PrintBuffer.cfc index 60736411a..214d11a6a 100644 --- a/src/cfml/system/util/PrintBuffer.cfc +++ b/src/cfml/system/util/PrintBuffer.cfc @@ -40,4 +40,4 @@ component accessors="true" extends="Print"{ return this; } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/ProgressBar.cfc b/src/cfml/system/util/ProgressBar.cfc index bbabf487e..69bf3ed13 100644 --- a/src/cfml/system/util/ProgressBar.cfc +++ b/src/cfml/system/util/ProgressBar.cfc @@ -101,4 +101,4 @@ component singleton { } } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/ProgressableDownloader.cfc b/src/cfml/system/util/ProgressableDownloader.cfc index 962f68c97..ae8623484 100644 --- a/src/cfml/system/util/ProgressableDownloader.cfc +++ b/src/cfml/system/util/ProgressableDownloader.cfc @@ -212,4 +212,4 @@ component singleton { return { connection = connection, netURL = netURL }; } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/REPLParser.cfc b/src/cfml/system/util/REPLParser.cfc index 9a12cf116..31e8790d2 100644 --- a/src/cfml/system/util/REPLParser.cfc +++ b/src/cfml/system/util/REPLParser.cfc @@ -133,4 +133,4 @@ component accessors="true" singleton { return reReplaceNoCase( arguments.command, "//[^""']*$|/\*.*\*/", "", "all" ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/ReaderFactory.cfc b/src/cfml/system/util/ReaderFactory.cfc index 35202d0dc..3e3c92ff4 100644 --- a/src/cfml/system/util/ReaderFactory.cfc +++ b/src/cfml/system/util/ReaderFactory.cfc @@ -58,4 +58,4 @@ component singleton{ } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index 7b2edcac4..f664ca33f 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -159,4 +159,4 @@ component singleton { return dataStructure; } -} \ No newline at end of file +} diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index a4b021b7b..864eeec89 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -219,4 +219,4 @@ component accessors=true { return true; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/aop/Matcher.cfc b/src/cfml/system/wirebox/system/aop/Matcher.cfc index 1cce3e010..c83c40de2 100644 --- a/src/cfml/system/wirebox/system/aop/Matcher.cfc +++ b/src/cfml/system/wirebox/system/aop/Matcher.cfc @@ -246,4 +246,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc b/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc index a12d8c9a2..1e4c30d6f 100644 --- a/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc +++ b/src/cfml/system/wirebox/system/aop/MethodInterceptor.cfc @@ -15,4 +15,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc b/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc index 3b76c7322..7ae090714 100644 --- a/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc +++ b/src/cfml/system/wirebox/system/aop/MethodInvocation.cfc @@ -140,4 +140,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/Mixer.cfc b/src/cfml/system/wirebox/system/aop/Mixer.cfc index 15a2701ab..4827de3ad 100644 --- a/src/cfml/system/wirebox/system/aop/Mixer.cfc +++ b/src/cfml/system/wirebox/system/aop/Mixer.cfc @@ -338,4 +338,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/MixerUtil.cfc b/src/cfml/system/wirebox/system/aop/MixerUtil.cfc index e276c8444..b6c38fc3d 100644 --- a/src/cfml/system/wirebox/system/aop/MixerUtil.cfc +++ b/src/cfml/system/wirebox/system/aop/MixerUtil.cfc @@ -76,4 +76,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/aspects/CFTransaction.cfc b/src/cfml/system/wirebox/system/aop/aspects/CFTransaction.cfc index e567e1623..71bd536f4 100644 --- a/src/cfml/system/wirebox/system/aop/aspects/CFTransaction.cfc +++ b/src/cfml/system/wirebox/system/aop/aspects/CFTransaction.cfc @@ -71,4 +71,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/aop/aspects/MethodLogger.cfc b/src/cfml/system/wirebox/system/aop/aspects/MethodLogger.cfc index b933aa5be..9089fa9f5 100644 --- a/src/cfml/system/wirebox/system/aop/aspects/MethodLogger.cfc +++ b/src/cfml/system/wirebox/system/aop/aspects/MethodLogger.cfc @@ -48,4 +48,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc b/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc index 6071a6f42..88485f75c 100644 --- a/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc +++ b/src/cfml/system/wirebox/system/core/collections/ScopeStorage.cfc @@ -118,4 +118,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc b/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc index 6ad80877c..61483c310 100644 --- a/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc +++ b/src/cfml/system/wirebox/system/core/conversion/DataMarshaller.cfc @@ -123,4 +123,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/conversion/ObjectMarshaller.cfc b/src/cfml/system/wirebox/system/core/conversion/ObjectMarshaller.cfc index b117225b7..11829e78f 100644 --- a/src/cfml/system/wirebox/system/core/conversion/ObjectMarshaller.cfc +++ b/src/cfml/system/wirebox/system/core/conversion/ObjectMarshaller.cfc @@ -94,4 +94,4 @@ component accessors="true"{ return obj; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/core/conversion/XMLConverter.cfc b/src/cfml/system/wirebox/system/core/conversion/XMLConverter.cfc index beaf161d4..ab9ca5505 100644 --- a/src/cfml/system/wirebox/system/core/conversion/XMLConverter.cfc +++ b/src/cfml/system/wirebox/system/core/conversion/XMLConverter.cfc @@ -353,4 +353,4 @@ Modifications - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/dynamic/BeanPopulator.cfc b/src/cfml/system/wirebox/system/core/dynamic/BeanPopulator.cfc index ea9b17a6d..c01d2ceaa 100644 --- a/src/cfml/system/wirebox/system/core/dynamic/BeanPopulator.cfc +++ b/src/cfml/system/wirebox/system/core/dynamic/BeanPopulator.cfc @@ -440,4 +440,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/dynamic/HTMLHelper.cfc b/src/cfml/system/wirebox/system/core/dynamic/HTMLHelper.cfc index 071163e75..59e918de4 100644 --- a/src/cfml/system/wirebox/system/core/dynamic/HTMLHelper.cfc +++ b/src/cfml/system/wirebox/system/core/dynamic/HTMLHelper.cfc @@ -1755,4 +1755,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/dynamic/MixerUtil.cfc b/src/cfml/system/wirebox/system/core/dynamic/MixerUtil.cfc index 9a827718a..2978510d3 100644 --- a/src/cfml/system/wirebox/system/core/dynamic/MixerUtil.cfc +++ b/src/cfml/system/wirebox/system/core/dynamic/MixerUtil.cfc @@ -224,4 +224,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/events/EventPool.cfc b/src/cfml/system/wirebox/system/core/events/EventPool.cfc index 271658f9d..797b8d556 100644 --- a/src/cfml/system/wirebox/system/core/events/EventPool.cfc +++ b/src/cfml/system/wirebox/system/core/events/EventPool.cfc @@ -140,4 +140,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/events/EventPoolManager.cfc b/src/cfml/system/wirebox/system/core/events/EventPoolManager.cfc index ff5054c35..4650bfb28 100644 --- a/src/cfml/system/wirebox/system/core/events/EventPoolManager.cfc +++ b/src/cfml/system/wirebox/system/core/events/EventPoolManager.cfc @@ -261,4 +261,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/util/CFMLEngine.cfc b/src/cfml/system/wirebox/system/core/util/CFMLEngine.cfc index 9ee65b31f..269dd3acd 100644 --- a/src/cfml/system/wirebox/system/core/util/CFMLEngine.cfc +++ b/src/cfml/system/wirebox/system/core/util/CFMLEngine.cfc @@ -72,4 +72,4 @@ component { return instance[ arguments.engine ][ arguments.feature ]; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/core/util/CFMappingHelper.cfc b/src/cfml/system/wirebox/system/core/util/CFMappingHelper.cfc index 98e2347d1..ebb758535 100644 --- a/src/cfml/system/wirebox/system/core/util/CFMappingHelper.cfc +++ b/src/cfml/system/wirebox/system/core/util/CFMappingHelper.cfc @@ -41,4 +41,4 @@ component{ } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/core/util/FileUtils.cfc b/src/cfml/system/wirebox/system/core/util/FileUtils.cfc index 964b02a02..318ad6188 100644 --- a/src/cfml/system/wirebox/system/core/util/FileUtils.cfc +++ b/src/cfml/system/wirebox/system/core/util/FileUtils.cfc @@ -447,4 +447,4 @@ Modification History: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc b/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc index 746c1bc8b..19a5e06a7 100644 --- a/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc +++ b/src/cfml/system/wirebox/system/core/util/RailoMappingHelper.cfc @@ -16,4 +16,4 @@ component{ application action='update' mappings='#mappings#'; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc b/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc index ab39dc366..0357f7ded 100644 --- a/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc +++ b/src/cfml/system/wirebox/system/core/util/RequestBuffer.cfc @@ -80,4 +80,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/core/util/Util.cfc b/src/cfml/system/wirebox/system/core/util/Util.cfc index f28d836a1..6e706e759 100644 --- a/src/cfml/system/wirebox/system/core/util/Util.cfc +++ b/src/cfml/system/wirebox/system/core/util/Util.cfc @@ -312,4 +312,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/Builder.cfc b/src/cfml/system/wirebox/system/ioc/Builder.cfc index 04b5bcd7f..a9a1a54d0 100644 --- a/src/cfml/system/wirebox/system/ioc/Builder.cfc +++ b/src/cfml/system/wirebox/system/ioc/Builder.cfc @@ -577,4 +577,4 @@ TODO: update dsl consistency, so it is faster. - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/IInjector.cfc b/src/cfml/system/wirebox/system/ioc/IInjector.cfc index 77c9dc41d..4af243b81 100644 --- a/src/cfml/system/wirebox/system/ioc/IInjector.cfc +++ b/src/cfml/system/wirebox/system/ioc/IInjector.cfc @@ -37,4 +37,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/IProvider.cfc b/src/cfml/system/wirebox/system/ioc/IProvider.cfc index 1a451099e..4ded0b18a 100644 --- a/src/cfml/system/wirebox/system/ioc/IProvider.cfc +++ b/src/cfml/system/wirebox/system/ioc/IProvider.cfc @@ -15,4 +15,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/Injector.cfc b/src/cfml/system/wirebox/system/ioc/Injector.cfc index da9d3e003..ee3a467cd 100644 --- a/src/cfml/system/wirebox/system/ioc/Injector.cfc +++ b/src/cfml/system/wirebox/system/ioc/Injector.cfc @@ -1016,4 +1016,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/Provider.cfc b/src/cfml/system/wirebox/system/ioc/Provider.cfc index 9b4a9c2f8..945ab1d54 100644 --- a/src/cfml/system/wirebox/system/ioc/Provider.cfc +++ b/src/cfml/system/wirebox/system/ioc/Provider.cfc @@ -69,4 +69,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/Scopes.cfc b/src/cfml/system/wirebox/system/ioc/Scopes.cfc index c11dc393e..fbdb02716 100644 --- a/src/cfml/system/wirebox/system/ioc/Scopes.cfc +++ b/src/cfml/system/wirebox/system/ioc/Scopes.cfc @@ -41,4 +41,4 @@ Description : } return structKeyArray(scopes); } - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/Types.cfc b/src/cfml/system/wirebox/system/ioc/Types.cfc index 3b799bef0..8dd62d29d 100644 --- a/src/cfml/system/wirebox/system/ioc/Types.cfc +++ b/src/cfml/system/wirebox/system/ioc/Types.cfc @@ -22,4 +22,4 @@ Description : this.FACTORY = "factory"; this.PROVIDER = "provider"; - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/config/Binder.cfc b/src/cfml/system/wirebox/system/ioc/config/Binder.cfc index 505152658..ae88ca02e 100644 --- a/src/cfml/system/wirebox/system/ioc/config/Binder.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/Binder.cfc @@ -1000,4 +1000,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/config/DefaultBinder.cfc b/src/cfml/system/wirebox/system/ioc/config/DefaultBinder.cfc index a1af73a0b..d26187489 100644 --- a/src/cfml/system/wirebox/system/ioc/config/DefaultBinder.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/DefaultBinder.cfc @@ -63,4 +63,4 @@ Description : }; } - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc b/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc index d5174f777..7b11402bf 100644 --- a/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/LogBox.cfc @@ -35,4 +35,4 @@ Description : }; } - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/config/Mapping.cfc b/src/cfml/system/wirebox/system/ioc/config/Mapping.cfc index 569236fcb..e2ff81bdf 100644 --- a/src/cfml/system/wirebox/system/ioc/config/Mapping.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/Mapping.cfc @@ -928,4 +928,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/config/Mixin.cfc b/src/cfml/system/wirebox/system/ioc/config/Mixin.cfc index 7630a82e0..b1f835071 100644 --- a/src/cfml/system/wirebox/system/ioc/config/Mixin.cfc +++ b/src/cfml/system/wirebox/system/ioc/config/Mixin.cfc @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc index a57019067..1f6759657 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/CacheBoxDSL.cfc @@ -66,4 +66,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc index 40d83ee21..1b75af875 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/ColdBoxDSL.cfc @@ -156,4 +156,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/dsl/IDSLBuilder.cfc b/src/cfml/system/wirebox/system/ioc/dsl/IDSLBuilder.cfc index a9573e017..5cf4d2611 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/IDSLBuilder.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/IDSLBuilder.cfc @@ -23,4 +23,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc b/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc index 28e07db1e..818762f19 100644 --- a/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc +++ b/src/cfml/system/wirebox/system/ioc/dsl/LogBoxDSL.cfc @@ -68,4 +68,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc b/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc index 72f33e9df..1e22c62c9 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/CFScopes.cfc @@ -77,4 +77,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/CacheBox.cfc b/src/cfml/system/wirebox/system/ioc/scopes/CacheBox.cfc index 7b603a314..317a0fec6 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/CacheBox.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/CacheBox.cfc @@ -81,4 +81,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/IScope.cfc b/src/cfml/system/wirebox/system/ioc/scopes/IScope.cfc index 153e7ae90..4307481c1 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/IScope.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/IScope.cfc @@ -23,4 +23,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc b/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc index 928a40021..1d7df16b6 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/NoScope.cfc @@ -36,4 +36,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc b/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc index 1289334cf..356e712b7 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/RequestScope.cfc @@ -53,4 +53,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/ioc/scopes/Singleton.cfc b/src/cfml/system/wirebox/system/ioc/scopes/Singleton.cfc index e5feb44fd..681f71893 100644 --- a/src/cfml/system/wirebox/system/ioc/scopes/Singleton.cfc +++ b/src/cfml/system/wirebox/system/ioc/scopes/Singleton.cfc @@ -87,4 +87,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/AbstractAppender.cfc b/src/cfml/system/wirebox/system/logging/AbstractAppender.cfc index 89bf50650..6d6182506 100644 --- a/src/cfml/system/wirebox/system/logging/AbstractAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/AbstractAppender.cfc @@ -219,4 +219,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/Layout.cfc b/src/cfml/system/wirebox/system/logging/Layout.cfc index 5c911dd49..df54b41a1 100644 --- a/src/cfml/system/wirebox/system/logging/Layout.cfc +++ b/src/cfml/system/wirebox/system/logging/Layout.cfc @@ -43,4 +43,4 @@ Description : type="Layout.FormatNotImplementedException"> - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/LogBox.cfc b/src/cfml/system/wirebox/system/logging/LogBox.cfc index 7254dfc14..68af60b60 100644 --- a/src/cfml/system/wirebox/system/logging/LogBox.cfc +++ b/src/cfml/system/wirebox/system/logging/LogBox.cfc @@ -272,4 +272,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/LogEvent.cfc b/src/cfml/system/wirebox/system/logging/LogEvent.cfc index 562d9c138..a3dc95aac 100644 --- a/src/cfml/system/wirebox/system/logging/LogEvent.cfc +++ b/src/cfml/system/wirebox/system/logging/LogEvent.cfc @@ -97,4 +97,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/LogLevels.cfc b/src/cfml/system/wirebox/system/logging/LogLevels.cfc index ed9cf729b..4d2c172b2 100644 --- a/src/cfml/system/wirebox/system/logging/LogLevels.cfc +++ b/src/cfml/system/wirebox/system/logging/LogLevels.cfc @@ -63,4 +63,4 @@ component{ function isLevelValid(level){ return ( arguments.level gte this.MINLEVEL AND arguments.level lte this.MAXLEVEL ); } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/logging/Logger.cfc b/src/cfml/system/wirebox/system/logging/Logger.cfc index 19c98e2b0..ea4253a85 100644 --- a/src/cfml/system/wirebox/system/logging/Logger.cfc +++ b/src/cfml/system/wirebox/system/logging/Logger.cfc @@ -387,4 +387,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/CFAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/CFAppender.cfc index b30c70a60..57908d252 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/CFAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/CFAppender.cfc @@ -80,4 +80,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc index 24d90d860..5a33cc59a 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/ConsoleAppender.cfc @@ -49,4 +49,4 @@ component extends="wirebox.system.logging.AbstractAppender"{ return; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc index c5f3f8690..6dd75d8b6 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/DBAppender.cfc @@ -301,4 +301,4 @@ If you are building a mapper, the map must have the above keys in it. - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc index 2b25dd56a..e583190fe 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/DummyAppender.cfc @@ -44,4 +44,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc index cbcb871b6..01c501c0a 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/EmailAppender.cfc @@ -146,4 +146,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/FileAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/FileAppender.cfc index 27bc9b160..98f9d2701 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/FileAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/FileAppender.cfc @@ -202,4 +202,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/RollingFileAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/RollingFileAppender.cfc index 436dbdc50..999c2855e 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/RollingFileAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/RollingFileAppender.cfc @@ -73,4 +73,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc index d50336f5a..19423435c 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/ScopeAppender.cfc @@ -121,4 +121,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc index 59b2f66b8..102b9317a 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/SocketAppender.cfc @@ -145,4 +145,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc b/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc index 22af474c5..ae0466ca4 100644 --- a/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc +++ b/src/cfml/system/wirebox/system/logging/appenders/TracerAppender.cfc @@ -67,4 +67,4 @@ Properties: - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc b/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc index 545774ab7..aa78756f7 100644 --- a/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc +++ b/src/cfml/system/wirebox/system/logging/config/LogBoxConfig.cfc @@ -379,4 +379,4 @@ Description : - \ No newline at end of file + diff --git a/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc b/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc index 12499b66c..43687ce63 100644 --- a/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc +++ b/src/cfml/system/wirebox/system/logging/config/samples/Sample.LogBox.cfc @@ -38,4 +38,4 @@ component{ }; } -} \ No newline at end of file +} diff --git a/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc b/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc index 028e183d7..674a6cab3 100644 --- a/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc +++ b/src/cfml/system/wirebox/system/logging/util/FileRotator.cfc @@ -87,4 +87,4 @@ Description : - \ No newline at end of file + From 485e1abd5ffb25a9c13ecf530d619892c81af562 Mon Sep 17 00:00:00 2001 From: Mark Skelton Date: Thu, 6 Jul 2017 08:26:13 -0500 Subject: [PATCH 119/123] Only save the file if it is changed (#125) --- .../commands/utils/add-eol-at-eof.cfc | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc index 696f772fc..6d4c1ac93 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/add-eol-at-eof.cfc @@ -57,23 +57,27 @@ component aliases="eol" { } for ( var file in arguments.files ){ - if ( arguments.verbose ){ - print.line( "Adding EOL at EOF to " & file & "..." ); - } - - addEOL( file ); + addEOL( file, arguments.verbose ); } } - private function addEOL( filePath ){ + private function addEOL( filePath, verbose ){ // trim and get line endings - var content = rTrim( fileRead( arguments.filePath ) ); + var content = fileRead( arguments.filePath ); + var newContent = rTrim( content ); // Add single newline to file content - content &= getLineEndings( content ); + newContent &= getLineEndings( newContent ); - // write new file - fileWrite( arguments.filePath, content ); + if ( content != newContent ) { + if ( arguments.verbose ){ + print.line( "Adding EOL at EOF to " & arguments.filePath & "..." ) + .toConsole(); + } + + // write new file + fileWrite( arguments.filePath, newContent ); + } } private function filterFiles( files, exclude ){ From 5b75809f39b0c06a52adda568c38036af4dc5f54 Mon Sep 17 00:00:00 2001 From: Mark Skelton Date: Sat, 8 Jul 2017 22:35:33 -0500 Subject: [PATCH 120/123] Updated remove trailing spaces function to only save files if they have been changed (#126) --- .../commands/utils/remove-trailing-spaces.cfc | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc index c8cb43102..df6445204 100644 --- a/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc +++ b/src/cfml/system/modules_app/utils-commands/commands/utils/remove-trailing-spaces.cfc @@ -57,36 +57,47 @@ component aliases="rts" { } for ( var file in arguments.files ){ - if ( arguments.verbose ){ - print.line( "Removing trailing spaces from " & file & "..." ); - } - - removeTrailingSpaces( file ); + removeTrailingSpaces( file, verbose ); } } - private function removeTrailingSpaces( filePath ){ + private function removeTrailingSpaces( filePath, verbose ){ // trim trailing spaces and get line endings var trimLinesResult = fileTrimLines( arguments.filePath ); - // write new file - fileWrite( arguments.filePath, arrayToList( trimLinesResult.lines, trimLinesResult.lineEndings ) ); + if ( trimLinesResult.fileChanged ){ + if ( arguments.verbose ){ + print.line( "Removing trailing spaces from " & arguments.filePath & "..." ) + .toConsole(); + } + + // write new file + fileWrite( arguments.filePath, arrayToList( trimLinesResult.lines, trimLinesResult.lineEndings ) ); + } } private function fileTrimLines( filePath ){ var lines = []; var lineEndings = ""; + var currentLine = ""; + var fileChanged = false; cfloop( file=filePath, index="line" ){ // get the file line endings if ( lineEndings == "" ){ lineEndings = getLineEndings( line ); } + // trim the trailing spaces - lines.append( rTrim( line ) ); + currentLine = rTrim( line ); + lines.append( currentLine ); + + if ( currentLine != line ) { + fileChanged = true; + } } - return { lines: lines, lineEndings: lineEndings }; + return { lines: lines, lineEndings: lineEndings, fileChanged: fileChanged }; } private function filterFiles( files, exclude ){ From 86806e4ff665a3cccd92456bd79cc8e33e3500ab Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 11 Jul 2017 18:22:10 -0500 Subject: [PATCH 121/123] COMMANDBOX-657 --- src/cfml/system/services/ServerService.cfc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index df08162ff..21c23ea52 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -118,6 +118,7 @@ component accessors="true" singleton { 'stopsocket' : d.stopsocket ?: 0, 'debug' : d.debug ?: false, 'trace' : d.trace ?: false, + 'console' : d.console ?: false, 'trayicon' : d.trayicon ?: '', // Duplicate so onServerStart interceptors don't actually change config settings via refernce. 'trayOptions' : duplicate( d.trayOptions ?: [] ), @@ -453,6 +454,7 @@ component accessors="true" singleton { // The big servers.json is only used to keep a record of the last values the server was started with serverInfo.trace = serverProps.trace ?: serverJSON.trace ?: defaults.trace; serverInfo.debug = serverProps.debug ?: serverJSON.debug ?: defaults.debug; + serverInfo.console = serverProps.console ?: serverJSON.console ?: defaults.console; serverInfo.openbrowser = serverProps.openbrowser ?: serverJSON.openbrowser ?: defaults.openbrowser; serverInfo.openbrowserURL = serverProps.openbrowserURL ?: serverJSON.openbrowserURL ?: defaults.openbrowserURL; @@ -825,7 +827,7 @@ component accessors="true" singleton { 'items' : serverInfo.trayOptions }; fileWrite( trayOptionsPath, serializeJSON( trayJSON ) ); - var background = !(serverProps.console ?: false); + var background = !(serverInfo.console ?: false); // The java arguments to execute: Shared server, custom web configs // This is an array of tokens to send to the process builder From dd82fa245a280241d90bdc43d71455cd587c5136 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 13 Jul 2017 00:37:43 -0500 Subject: [PATCH 122/123] COMMANDBOX-658 --- src/cfml/system/endpoints/ForgeBox.cfc | 1 + src/cfml/system/util/ForgeBox.cfc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 3f45b8a4c..fe51da505 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -198,6 +198,7 @@ component accessors="true" implements="IEndpointInteractive" singleton { var props = {} props.slug = boxJSON.slug; + props.private = boxJSON.private; props.version = boxJSON.version; props.boxJSON = serializeJSON( boxJSON ); props.isStable = !semanticVersion.isPreRelease( boxJSON.version ); diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 7eb7bbdd1..10bb4fb22 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -245,6 +245,7 @@ or just add DEBUG to the root logger */ function publish( required string slug, + required boolean private, required string version, required string boxJSON, required string isStable=true, @@ -258,6 +259,7 @@ or just add DEBUG to the root logger var body = { slug : arguments.slug, + private : arguments.private, version : arguments.version, boxJSON : arguments.boxJSON, isStable : arguments.isStable, @@ -458,7 +460,6 @@ or just add DEBUG to the root logger CFHTTPParams.proxyPassword = proxyPassword; } } - From edb63f0f8dbf53f64f4bcfeb8517bb8dd9f80037 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 14 Jul 2017 23:52:17 -0500 Subject: [PATCH 123/123] Final 3.7.0 build --- build/build.properties | 2 +- build/build.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build.properties b/build/build.properties index 0202b7baf..1d2500bdf 100644 --- a/build/build.properties +++ b/build/build.properties @@ -11,7 +11,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib cfml.version=4.5.5.006 -cfml.loader.version=1.5.3 +cfml.loader.version=1.5.4 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} jre.version=1.8.0_102 diff --git a/build/build.xml b/build/build.xml index c04ac0851..a17a4690c 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,8 +16,8 @@ External Dependencies: - - + +