From 6f126d37320b625b62abe0963900e7af45682da7 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 4 Oct 2021 09:07:22 -0500 Subject: [PATCH 001/118] Re-bump for 5.5.0 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index bb52e37a..5663d762 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From 9009fbe253130eb1d6c7ba5822eee811e27bdf63 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 4 Oct 2021 09:27:10 -0500 Subject: [PATCH 002/118] Need prerelease id --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 5663d762..47ff10b5 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,7 +16,7 @@ External Dependencies: - + From 4c0b54c372bf84e927a703fc3eb541e58251af46 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 8 Oct 2021 12:28:10 -0500 Subject: [PATCH 003/118] COMMANDBOX-1390 --- .../package-commands/commands/package/outdated.cfc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) 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 735e4ed7..ddf70cfd 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 @@ -34,7 +34,9 @@ component aliases="outdated" { function run( boolean verbose=false, boolean JSON=false, - boolean system=false ) { + boolean system=false, + boolean hideUpToDate=false + ) { if( arguments.JSON ) { arguments.verbose = false; @@ -53,16 +55,20 @@ component aliases="outdated" { // echo output if( !arguments.JSON ) { - print.yellowLine( "Resolving Dependencies, please wait..." ).toConsole(); + print.yellowLine( "Checking for outdated #( system ? 'system ' : '' )#dependencies, please wait..." ).toConsole(); } // build dependency tree var aAllDependencies = packageService.getOutdatedDependencies( directory=directory, print=print, verbose=arguments.verbose ); var aOutdatedDependencies = aAllDependencies.filter( (d)=>d.isOutdated ); + if( hideUpToDate ) { + aAllDependencies = aAllDependencies.filter( (d)=>d.isOutdated || !d.isLatest ); + } + // JSON output if( arguments.JSON ) { - print.line( aAllDependencies.filter( (d)=>d.isOutdated ) ); + print.line( aAllDependencies ); return; } From 56c6a9fbdffda6c810f15662d559fbb84e330636 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 19 Oct 2021 12:24:55 -0500 Subject: [PATCH 004/118] COMMANDBOX-1392 --- src/cfml/system/Shell.cfc | 19 ++++++++++++------- src/cfml/system/services/CommandService.cfc | 14 +++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index f7033e8e..08a1cc11 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -749,17 +749,19 @@ 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. - * @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 recursively call new commands via this method, this flags the first in the chain so exceptions can bubble all the way back to the beginning. + * @command Either a string containing a text command, or an array of tokens representing the command and parameters. + * @returnOutput 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 Any text being piped into the command. This will overwrite the first parameter (pushing any positional params back) + * @initialCommand Since commands can recursively call new commands via this method, this flags the first in the chain so exceptions can bubble all the way back to the beginning. + * @line If passing an array of tokens, this is the original, unparsed line typed by the user * 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( required any command, returnOutput=false, string piped, - boolean initialCommand=false ) { + boolean initialCommand=false, + string line ) { var job = wirebox.getInstance( 'interactiveJob' ); var ConsolePainter = wirebox.getInstance( 'ConsolePainter' ); @@ -778,10 +780,13 @@ component accessors="true" singleton { try{ if( isArray( command ) ) { + if( isNull( arguments.line ) ) { + arguments.line = command.toList( ' ' ); + } if( structKeyExists( arguments, 'piped' ) ) { - var result = variables.commandService.runCommandTokens( arguments.command, piped, returnOutput ); + var result = variables.commandService.runCommandTokens( arguments.command, piped, returnOutput, line ); } else { - var result = variables.commandService.runCommandTokens( tokens=arguments.command, captureOutput=returnOutput ); + var result = variables.commandService.runCommandTokens( tokens=arguments.command, captureOutput=returnOutput, line=line ); } } else { var result = variables.commandService.runCommandLine( arguments.command, returnOutput ); diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index c328c37c..8ada6301 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -123,7 +123,7 @@ component accessors="true" singleton { /** * run a command line - * @line.hint line to run + * @line line to run * @captureOutput Temp workaround to allow capture of run command **/ function runCommandline( required string line, boolean captureOutput=false ){ @@ -141,21 +141,22 @@ component accessors="true" singleton { /** * run a command tokens - * @tokens.hint tokens to run - * @piped.hint Data to pipe in to the first command + * @tokens tokens to run + * @piped Data to pipe in to the first command * @captureOutput Temp workaround to allow capture of run command + * @line This is the original, unparsed line typed by the user **/ - function runCommandTokens( required array tokens, string piped, boolean captureOutput=false ){ + function runCommandTokens( required array tokens, string piped, boolean captureOutput=false, required string line ){ // Resolve the command they are wanting to run var commandChain = resolveCommandTokens( tokens ); // If there was piped input if( structKeyExists( arguments, 'piped' ) ) { - return runCommand( commandChain, tokens.toList( ' ' ), arguments.piped, captureOutput ); + return runCommand( commandChain, line, arguments.piped, captureOutput ); } - return runCommand( commandChain=commandChain, line=tokens.toList( ' ' ), captureOutput=captureOutput ); + return runCommand( commandChain=commandChain, line=line, captureOutput=captureOutput ); } @@ -626,7 +627,6 @@ component accessors="true" singleton { * run "cmd /c dir" */ if( tokens.len() > 1 && tokens.first() == 'run' ) { - var tokens2 = tokens[ 2 ]; // Escape any regex metacharacters in the pattern tokens2 = replace( tokens2, '\', '\\', 'all' ); From 2d3801b98eaa167edba0132f40876fd7d8589148 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 19 Oct 2021 12:49:44 -0500 Subject: [PATCH 005/118] COMMANDBOX-1392 --- src/cfml/system/services/CommandService.cfc | 2 +- src/cfml/system/util/CommandDSL.cfc | 22 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 8ada6301..57049c45 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -149,7 +149,7 @@ component accessors="true" singleton { function runCommandTokens( required array tokens, string piped, boolean captureOutput=false, required string line ){ // Resolve the command they are wanting to run - var commandChain = resolveCommandTokens( tokens ); + var commandChain = resolveCommandTokens( tokens, line ); // If there was piped input if( structKeyExists( arguments, 'piped' ) ) { diff --git a/src/cfml/system/util/CommandDSL.cfc b/src/cfml/system/util/CommandDSL.cfc index 79fb05cb..d531ea6b 100644 --- a/src/cfml/system/util/CommandDSL.cfc +++ b/src/cfml/system/util/CommandDSL.cfc @@ -222,7 +222,23 @@ component accessors=true { * Turn this CFC into a string representation **/ string function getCommandString() { - return getTokens().toList( ' ' ); + var tokens = getCommand(); + tokens &= ' ' & processParams().toList( ' ' ); + tokens &= ' '& getFlags().toList( ' ' ); + + if( len( getOverwrite() ) ) { + tokens &= ' > ' & getOverwrite(); + } + + if( len( getAppend() ) ) { + tokens &= ' >> ' & getAppend(); + } + + for( var piperton in getPiped() ) { + tokens &= ' | ' & piperton.getCommandString(); + } + + return tokens; } /** @@ -246,9 +262,9 @@ component accessors=true { try { if( !isNull( getPipedInput() ) ) { - var result = shell.callCommand( getTokens(), getReturnOutput(), getPipedInput() ); + var result = shell.callCommand( getTokens(), getReturnOutput(), getPipedInput(), getCommandString() ); } else { - var result = shell.callCommand( getTokens(), getReturnOutput() ); + var result = shell.callCommand( command=getTokens(), returnOutput=getReturnOutput(), line=getCommandString() ); } // If the previous command chain failed From 9ce0a5965ec5981cdb9d8a61dbe30d478baae32c Mon Sep 17 00:00:00 2001 From: Pete Freitag Date: Fri, 22 Oct 2021 11:39:00 -0400 Subject: [PATCH 006/118] Add COMMANDBOX_HOME environment var to server start (#300) There is no easy and reliable way to know the `COMMANDBOX_HOME` from a server start, so this change will create an environment variable in the new process for the server if the environment var is not already specified. --- src/cfml/system/services/ServerService.cfc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 6a9bd811..88b77ce8 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1568,6 +1568,11 @@ component accessors="true" singleton { } } + // Add COMMANDBOX_HOME env var to the server if not already there + if ( !currentEnv.containsKey( 'COMMANDBOX_HOME' ) ) { + currentEnv.put( 'COMMANDBOX_HOME', expandPath( '/commandbox-home' ) ); + } + // Conjoin standard error and output for convenience. processBuilder.redirectErrorStream( true ); // Kick off actual process From 7734f0c8fbe0487cb233de3fc5322ef610146764 Mon Sep 17 00:00:00 2001 From: Pete Freitag Date: Fri, 22 Oct 2021 12:21:06 -0400 Subject: [PATCH 007/118] Add COMMANDBOX_VERSION env var to server start (#301) This change will allow servers to know what version of commandbox started them. --- src/cfml/system/services/ServerService.cfc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 88b77ce8..05e98b2e 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1572,6 +1572,12 @@ component accessors="true" singleton { if ( !currentEnv.containsKey( 'COMMANDBOX_HOME' ) ) { currentEnv.put( 'COMMANDBOX_HOME', expandPath( '/commandbox-home' ) ); } + + // Add COMMANDBOX_VERSION env var to the server if not already there + if ( !currentEnv.containsKey( 'COMMANDBOX_VERSION' ) ) { + currentEnv.put( 'COMMANDBOX_VERSION', shell.getVersion() ); + } + // Conjoin standard error and output for convenience. processBuilder.redirectErrorStream( true ); From c2155208557316a7bb99bfd5ad92f385c2cdc2c7 Mon Sep 17 00:00:00 2001 From: Kai Koenig Date: Wed, 27 Oct 2021 12:32:34 +1300 Subject: [PATCH 008/118] Move Java endpoint to Adoptium (#302) --- src/cfml/system/endpoints/Java.cfc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cfml/system/endpoints/Java.cfc b/src/cfml/system/endpoints/Java.cfc index 4879d925..3fcd20d8 100644 --- a/src/cfml/system/endpoints/Java.cfc +++ b/src/cfml/system/endpoints/Java.cfc @@ -61,12 +61,12 @@ component accessors=true implements="IEndpoint" singleton { // Turn it into the maven-style semver range [11,12) which is the equiv of >= 11 && < 12 thus getting 11.x var thisVersionNum = replaceNoCase( javaDetails.version, 'openjdk', '' ); var thisVersion = '[#thisVersionNum#,#thisVersionNum+1#)'; - var APIURLInfo = 'https://api.adoptopenjdk.net/v3/assets/version/#encodeForURL( thisVersion )#?page_size=1000&release_type=ga&vendor=adoptopenjdk&project=jdk&heap_size=normal&jvm_impl=#encodeForURL( javaDetails['jvm-implementation'] )#&os=#encodeForURL( javaDetails.os )#&architecture=#encodeForURL( javaDetails.arch )#&image_type=#encodeForURL( javaDetails.type )#'; + var APIURLInfo = 'https://api.adoptium.net/v3/assets/version/#encodeForURL( thisVersion )#?page_size=1000&release_type=ga&vendor=eclipse&project=jdk&heap_size=normal&jvm_impl=#encodeForURL( javaDetails['jvm-implementation'] )#&os=#encodeForURL( javaDetails.os )#&architecture=#encodeForURL( javaDetails.arch )#&image_type=#encodeForURL( javaDetails.type )#'; if( javaDetails.release.len() && javaDetails.release != 'latest' ) { - var APIURL = 'https://api.adoptopenjdk.net/v3/binary/version/#encodeForURL( javaDetails.release )#/#encodeForURL( javaDetails.os )#/#encodeForURL( javaDetails.arch )#/#encodeForURL( javaDetails.type )#/#encodeForURL( javaDetails['jvm-implementation'] )#/normal/adoptopenjdk'; + var APIURL = 'https://api.adoptium.net/v3/binary/version/#encodeForURL( javaDetails.release )#/#encodeForURL( javaDetails.os )#/#encodeForURL( javaDetails.arch )#/#encodeForURL( javaDetails.type )#/#encodeForURL( javaDetails['jvm-implementation'] )#/normal/eclipse'; } else { - var APIURL = 'https://api.adoptopenjdk.net/v3/binary/latest/#thisVersionNum#/ga/#encodeForURL( javaDetails.os )#/#encodeForURL( javaDetails.arch )#/#encodeForURL( javaDetails.type )#/#encodeForURL( javaDetails['jvm-implementation'] )#/normal/adoptopenjdk'; + var APIURL = 'https://api.adoptium.net/v3/binary/latest/#thisVersionNum#/ga/#encodeForURL( javaDetails.os )#/#encodeForURL( javaDetails.arch )#/#encodeForURL( javaDetails.type )#/#encodeForURL( javaDetails['jvm-implementation'] )#/normal/eclipse'; } job.addLog( "Installing [#package#]" ); @@ -82,7 +82,7 @@ component accessors=true implements="IEndpoint" singleton { return serveFromArtifacts( package, packageFullName, lockVersion ); } - job.addLog( 'Hitting the AdoptOpenJDK API to find your download.' ); + job.addLog( 'Hitting the Adoptium API to find your download.' ); job.addLog( APIURLInfo ); @@ -124,7 +124,7 @@ component accessors=true implements="IEndpoint" singleton { // which is the equiv of >= 11 && < 12 thus getting 11.x var thisVersion = '[#thisVersionNum#,#thisVersionNum+1#)'; - var APIURLCheck = 'https://api.adoptopenjdk.net/v3/assets/version/#encodeForURL(thisVersion )#?release_type=ga&vendor=adoptopenjdk&project=jdk&heap_size=normal&jvm_impl=#encodeForURL( javaDetails['jvm-implementation'] )#&os=#encodeForURL( javaDetails.os )#&architecture=#encodeForURL( javaDetails.arch )#&image_type=#encodeForURL( javaDetails.type )#'; + var APIURLCheck = 'https://api.adoptium.net/v3/assets/version/#encodeForURL(thisVersion )#?release_type=ga&vendor=eclipse&project=jdk&heap_size=normal&jvm_impl=#encodeForURL( javaDetails['jvm-implementation'] )#&os=#encodeForURL( javaDetails.os )#&architecture=#encodeForURL( javaDetails.arch )#&image_type=#encodeForURL( javaDetails.type )#'; http url="#APIURLCheck#" @@ -155,7 +155,7 @@ component accessors=true implements="IEndpoint" singleton { job.addErrorLog( message ); // Before we give up, check artifacts for a downloaded version that might work - // Ideally I'd only do this for catastrophic errors, but the AdoptOpenJDK API doesn't really allow me to + // Ideally I'd only do this for catastrophic errors, but the Adoptium API doesn't really allow me to // tell the difference since it pretty much just pukes non-JSON if it can't find what I was looking for var artifactJDKs = artifactService.listArtifacts( 'OpenJDK' ); if( artifactJDKs.keyExists( 'OpenJDK' ) ) { @@ -250,8 +250,8 @@ component accessors=true implements="IEndpoint" singleton { 'type' : 'projects', 'java' : artifactJSON.binaries[ 1 ], 'author' : 'AdoptOpenJDK', - 'projectURL' : 'https://adoptopenjdk.net/', - 'homepage' : 'https://adoptopenjdk.net/' + 'projectURL' : 'https://adoptium.net/', + 'homepage' : 'https://adoptium.net/' }; JSONService.writeJSONFile( fullBoxJSONPath, boxJSON ); From 12984b767d9e4b040f847f76a41a544e65958b64 Mon Sep 17 00:00:00 2001 From: Kai Koenig Date: Wed, 27 Oct 2021 12:32:57 +1300 Subject: [PATCH 009/118] Move java search command to Adoptium (#303) --- .../server-commands/commands/server/java/search.cfc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc b/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc index 696215a1..8e8b6765 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc @@ -64,7 +64,7 @@ component aliases='java search' { // If there is no version and no release, hit the API to get the latest LTS version } else if( isNull( version ) ) { http - url="https://api.adoptopenjdk.net/v3/info/available_releases" + url="https://api.adoptium.net/v3/info/available_releases" throwOnError=false timeout=5 proxyServer="#ConfigService.getSetting( 'proxy.server', '' )#" @@ -101,7 +101,7 @@ component aliases='java search' { } } - var APIURLCheck = 'https://api.adoptopenjdk.net/v3/assets/version/#encodeForURL(version)#?page_size=100&release_type=ga&vendor=adoptopenjdk&project=jdk&heap_size=normal'; + var APIURLCheck = 'https://api.adoptium.net/v3/assets/version/#encodeForURL(version)#?page_size=100&release_type=ga&vendor=eclipse&project=jdk&heap_size=normal'; if( jvm.len() ) { APIURLCheck &= '&jvm_impl=#encodeForURL( jvm )#'; @@ -197,7 +197,7 @@ component aliases='java search' { function versionComplete() { http - url="https://api.adoptopenjdk.net/v3/info/available_releases" + url="https://api.adoptium.net/v3/info/available_releases" throwOnError=false timeout=5 proxyServer="#ConfigService.getSetting( 'proxy.server', '' )#" @@ -214,4 +214,4 @@ component aliases='java search' { return []; } -} \ No newline at end of file +} From 488ec838e99cbec8bac37cb135d73501d7db463a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 26 Oct 2021 19:01:12 -0500 Subject: [PATCH 010/118] COMMANDBOX-1397 --- .../commands/server/java/search.cfc | 112 +++++++++++------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc b/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc index 8e8b6765..90ee77d8 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/java/search.cfc @@ -21,6 +21,13 @@ * server java search jvm= arch= type= os= * {code} * + * Or get the raw JSON as it was returned from the API + * {code:bash} + * server java search --JSON + * {code} + * + * If a failing HTTP status code is received from the API, this command will return an exit code of 1 + * **/ component aliases='java search' { @@ -42,6 +49,7 @@ component aliases='java search' { * @type.options jdk,jre * @release A specific release name or the word "latest" * @release.options latest + * @release.JSON Output the RAW JSON received from the remote API */ function run( version, @@ -49,7 +57,8 @@ component aliases='java search' { os, arch = server.java.archModel contains 32 ? 'x32' : 'x64', type = 'jre', - release = 'latest' + release = 'latest', + boolean JSON = false ){ // If there is no version passed but we have a release, default the version based on the release. @@ -63,6 +72,9 @@ component aliases='java search' { } // If there is no version and no release, hit the API to get the latest LTS version } else if( isNull( version ) ) { + // Until Adobe and Lucee support Java 17, we'll keep this defaulting to Java 11-- the current LTS release supported by CF engines. + version = 11; + /* http url="https://api.adoptium.net/v3/info/available_releases" throwOnError=false @@ -81,6 +93,7 @@ component aliases='java search' { } else { version = 11; } + */ } // Backwards compat so 8 so the same as openjdk8 @@ -116,13 +129,6 @@ component aliases='java search' { APIURLCheck &= '&image_type=#encodeForURL( type )#'; } - print - .line() - .line( 'Hitting API URL:' ) - .indentedline( APIURLCheck ) - .line() - .line(); - http url="#APIURLCheck#" timeout=20 @@ -134,51 +140,69 @@ component aliases='java search' { result="local.artifactResult"; var fileContent = toString( local.artifactResult.fileContent ); - if( local.artifactResult.status_code == 200 && isJSON( fileContent ) ) { + if( local.artifactResult.status_code == 404 ) { + var artifactJSON = []; + } else if( local.artifactResult.status_code == 200 && isJSON( fileContent ) ) { var artifactJSON = deserializeJSON( fileContent ); - // If we have a release, we need to filter it now if( release.len() && release != 'latest' ) { artifactJSON = artifactJSON.filter( (thisRelease)=>thisRelease.release_name==release ); - } + } + } else { + print.redLine( fileContent.left( 100 ) ); + error( 'There was an error hitting the API. [#local.artifactResult.status_code#]' ); + } + + // Sometimes the API gives me back a struct, sometimes I get an array of structs. ¯\_(ツ)_/¯ + if( isStruct( artifactJSON ) ) { + artifactJSON = [ artifactJSON ]; + } - // Sometimes the API gives me back a struct, sometimes I get an array of structs. ¯\_(ツ)_/¯ - if( isStruct( artifactJSON ) ) { - artifactJSON = [ artifactJSON ]; - } + if( JSON ) { + print.line( artifactJSON ); + return; + } else { + print + .line() + .line( 'Hitting API URL:' ) + .indentedline( APIURLCheck ) + .line() + .line(); + } + + if( !artifactJSON.len() ) { + print.redLine( 'No matching Java versions found for your search criteria' ); + return; + } - for( var javaVer in artifactJSON ) { - var headerWidth = ('Release Name: ' & javaVer.release_name & ' Release Date: ' & dateFormat( javaVer.timestamp )).len()+4; - var colWidth = int( ( headerWidth/4 )-1 ); - var lastColWidth = headerWidth - ( (colWidth*4)+5 ) + colWidth; + for( var javaVer in artifactJSON ) { + var headerWidth = ('Release Name: ' & javaVer.release_name & ' Release Date: ' & dateFormat( javaVer.timestamp )).len()+4; + var colWidth = int( ( headerWidth/4 )-1 ); + var lastColWidth = headerWidth - ( (colWidth*4)+5 ) + colWidth; + print + .boldLine( repeatString( '-', headerWidth ) ) + .boldText( '| Release Name: ' ).boldCyanText( javaVer.release_name ).boldtext( ' Release Date: ' ).boldCyanText( dateFormat( javaVer.timestamp ) ).boldLine( ' |' ) + .boldLine( repeatString( '-', headerWidth ) ) + .bold( '|' ).boldCyan( printColumnValue( 'JVM', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'OS', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'Arch', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'Type', lastColWidth ) ).boldLine( '|' ) + .boldLine( repeatString( '-', headerWidth ) ); + + javaVer.binaries = javaVer.binaries.sort( function( a, b ) { + return compareNoCase( a.jvm_impl & a.os & a.architecture & a.image_type, b.jvm_impl & b.os & b.architecture & b.image_type ) + } ); + for( var binary in javaVer.binaries ) { print - .boldLine( repeatString( '-', headerWidth ) ) - .boldText( '| Release Name: ' ).boldCyanText( javaVer.release_name ).boldtext( ' Release Date: ' ).boldCyanText( dateFormat( javaVer.timestamp ) ).boldLine( ' |' ) - .boldLine( repeatString( '-', headerWidth ) ) - .bold( '|' ).boldCyan( printColumnValue( 'JVM', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'OS', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'Arch', colWidth ) ).bold( '|' ).boldCyan( printColumnValue( 'Type', lastColWidth ) ).boldLine( '|' ) - .boldLine( repeatString( '-', headerWidth ) ); - - javaVer.binaries = javaVer.binaries.sort( function( a, b ) { - return compareNoCase( a.jvm_impl & a.os & a.architecture & a.image_type, b.jvm_impl & b.os & b.architecture & b.image_type ) - } ); - for( var binary in javaVer.binaries ) { - print - .line( '|' & printColumnValue( binary.jvm_impl, colWidth ) - & '|' & printColumnValue( binary.os, colWidth ) - & '|' & printColumnValue( binary.architecture, colWidth ) - & '|' & printColumnValue( binary.image_type, lastColWidth ) & '|' ) - .text( '|' ).yellowText( printColumnValue( 'ID: ' & java.getDefaultNameFromStruct( { version : 'openjdk'&javaVer.version_data.major, type : binary.image_type, arch : binary.architecture, os : binary.os, 'jvm-implementation' : binary.jvm_impl, release : javaVer.release_name } ), headerWidth-2 ) ).line( '|' ) - .line( repeatString( '-', headerWidth ) ); - } - print.line(); - if( release == 'latest' ) { - break; - } + .line( '|' & printColumnValue( binary.jvm_impl, colWidth ) + & '|' & printColumnValue( binary.os, colWidth ) + & '|' & printColumnValue( binary.architecture, colWidth ) + & '|' & printColumnValue( binary.image_type, lastColWidth ) & '|' ) + .text( '|' ).yellowText( printColumnValue( 'ID: ' & java.getDefaultNameFromStruct( { version : 'openjdk'&javaVer.version_data.major, type : binary.image_type, arch : binary.architecture, os : binary.os, 'jvm-implementation' : binary.jvm_impl, release : javaVer.release_name } ), headerWidth-2 ) ).line( '|' ) + .line( repeatString( '-', headerWidth ) ); + } + print.line(); + if( release == 'latest' ) { + break; } - } else { - print.boldRedLine( 'There was an error hitting the API. [#local.artifactResult.status_code#]' ); - print.redLine( fileContent.left( 100 ) ); } } From 768a203c0e5243d362bbe0e6425b60bfee877f65 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 26 Oct 2021 19:04:24 -0500 Subject: [PATCH 011/118] bump loader version --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 59d70a7d..283c9830 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,7 +12,7 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.8.206 cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.5 +cfml.loader.version=2.6.6 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org From 997774f3d7fcb47e932b407ef787645ccbbf0f85 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 3 Nov 2021 14:39:04 -0500 Subject: [PATCH 012/118] COMMANDBOX-1398 --- src/cfml/system/services/CommandService.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 57049c45..8769f59f 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -671,7 +671,7 @@ component accessors="true" singleton { tokens[1] = right( tokens[1], len( tokens[1] ) - 1 ); // If it looks like we have named params, convert the "name" to be named - if( tokens.len() > 1 && tokens[2] contains '=' ) { + if( tokens.len() > 1 && parser.parseParameters( [ tokens[2] ], [] ).namedParameters.count() ) { tokens[1] = 'name=' & tokens[1]; } From 2d15e34c8e4fe23577bf0b65367df064a2de5ceb Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 10 Nov 2021 11:11:55 -0600 Subject: [PATCH 013/118] COMMANDBOX-1399 --- src/cfml/system/util/SystemSettings.cfc | 42 ++++++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index 5060222d..e10d75f2 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -50,13 +50,13 @@ component singleton { } // Now check Java system props - var value = system.getProperty( arguments.key ); + var value = getSystemProperty( key=arguments.key, throwWhenNotFound=false ); if ( ! isNull( value ) ) { return value; } // Finally check OS env vars. - value = system.getEnv( arguments.key ); + value = getEnv( key=arguments.key, throwWhenNotFound=false ); if ( ! isNull( value ) ) { return value; } @@ -79,21 +79,30 @@ component singleton { * @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 ) { + function getSystemProperty( required string key, defaultValue, throwWhenNotFound=true ) { var value = system.getProperty( arguments.key ); if ( ! isNull( value ) ) { return value; } + // Second case-insensitive attempt + for( var propKey in system.getProperties() ) { + if( arguments.key == propKey ) { + return system.getProperty( propKey ); + } + } + if ( ! isNull( arguments.defaultValue ) ) { return arguments.defaultValue; } - throw( - type = "SystemSettingNotFound", - message = "Could not find a Java System property with key [#arguments.key#]." - ); + if( throwWhenNotFound ) { + throw( + type = "SystemSettingNotFound", + message = "Could not find a Java System property with key [#arguments.key#]." + ); + } } /** @@ -124,21 +133,30 @@ component singleton { * @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 ) { + function getEnv( required string key, defaultValue, throwWhenNotFound=true ) { var value = system.getEnv( arguments.key ); if ( ! isNull( value ) ) { return value; } + // Second case-insensitive attempt + for( var envKey in system.getEnv() ) { + if( arguments.key == envKey ) { + return system.getEnv( envKey ); + } + } + if ( ! isNull( arguments.defaultValue ) ) { return arguments.defaultValue; } - throw( - type = "SystemSettingNotFound", - message = "Could not find a env property with key [#arguments.key#]." - ); + if( throwWhenNotFound ) { + throw( + type = "SystemSettingNotFound", + message = "Could not find a env property with key [#arguments.key#]." + ); + } } From e8dcbd84100b049fb5055b49ceba97dcad5b2bb5 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 17 Nov 2021 15:37:11 -0600 Subject: [PATCH 014/118] COMMANDBOX-1406 --- src/cfml/system/services/ServerService.cfc | 122 +++++++++++---------- 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 05e98b2e..e0497cac 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -280,21 +280,31 @@ component accessors="true" singleton { // Look up the server that we're starting var serverDetails = resolveServerDetails( arguments.serverProps ); - // This will allow settings in the "env" object to also refernce env vars which are already set - systemSettings.expandDeepSystemSettings( serverDetails.serverJSON.env ?: {} ); - // Load up our fully-realized server.json-specific env vars into CommandBox's environment - systemSettings.setDeepSystemSettings( serverDetails.serverJSON.env ?: {}, '' ); // Get defaults var defaults = getDefaultServerJSON(); - - interceptorService.announceInterception( 'preServerStart', { serverDetails=serverDetails, serverProps=serverProps, serverInfo=serverDetails.serverInfo, serverJSON=serverDetails.serverJSON, defaults=defaults } ); - var defaultName = serverDetails.defaultName; var defaultwebroot = serverDetails.defaultwebroot; var defaultServerConfigFile = serverDetails.defaultServerConfigFile; var defaultServerConfigFileDirectory = getDirectoryFromPath( defaultServerConfigFile ); var serverJSON = serverDetails.serverJSON; + var serverJSONToSave = duplicate( serverJSON ); var serverInfo = serverDetails.serverinfo; + + systemSettings.expandDeepSystemSettings( serverJSON ); + systemSettings.expandDeepSystemSettings( defaults ); + // Mix in environment variable overrides like BOX_SERVER_PROFILE + loadOverrides( serverJSON, serverInfo, serverProps.verbose ?: serverJSON.verbose ?: defaults.verbose ?: false ); + + // Load up our fully-realized server.json-specific env vars into CommandBox's environment + systemSettings.setDeepSystemSettings( serverDetails.serverJSON.env ?: {}, '' ); + + interceptorService.announceInterception( 'preServerStart', { serverDetails=serverDetails, serverProps=serverProps, serverInfo=serverDetails.serverInfo, serverJSON=serverDetails.serverJSON, defaults=defaults } ); + + // In case the interceptor changed them + defaultName = serverDetails.defaultName; + defaultwebroot = serverDetails.defaultwebroot; + defaultServerConfigFile = serverDetails.defaultServerConfigFile; + defaultServerConfigFileDirectory = getDirectoryFromPath( defaultServerConfigFile ); // If the server is already running, make sure the user really wants to do this. if( isServerRunning( serverInfo ) && !(serverProps.force ?: false ) && !(serverProps.dryRun ?: false ) ) { @@ -359,10 +369,10 @@ component accessors="true" singleton { // Only need switch cases for properties that are nested or use different name switch(prop) { case "port": - serverJSON[ 'web' ][ 'http' ][ 'port' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'http' ][ 'port' ] = serverProps[ prop ]; break; case "host": - serverJSON[ 'web' ][ 'host' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'host' ] = serverProps[ prop ]; break; case "directory": // This path is canonical already. @@ -371,10 +381,10 @@ component accessors="true" singleton { if( thisDirectory contains configPath ) { thisDirectory = replaceNoCase( thisDirectory, configPath, '' ); } - serverJSON[ 'web' ][ 'webroot' ] = thisDirectory; + serverJSONToSave[ 'web' ][ 'webroot' ] = thisDirectory; break; case "trayEnable": - serverJSON[ 'trayEnable' ] = serverProps[ prop ]; + serverJSONToSave[ 'trayEnable' ] = serverProps[ prop ]; break; case "trayIcon": // This path is canonical already. @@ -383,10 +393,10 @@ component accessors="true" singleton { if( thisFile contains configPath ) { thisFile = replaceNoCase( thisFile, configPath, '' ); } - serverJSON[ 'trayIcon' ] = thisFile; + serverJSONToSave[ 'trayIcon' ] = thisFile; break; case "stopPort": - serverJSON[ 'stopsocket' ] = serverProps[ prop ]; + serverJSONToSave[ 'stopsocket' ] = serverProps[ prop ]; break; case "webConfigDir": // This path is canonical already. @@ -395,7 +405,7 @@ component accessors="true" singleton { if( thisDirectory contains configPath ) { thisDirectory = replaceNoCase( thisDirectory, configPath, '' ); } - serverJSON[ 'app' ][ 'webConfigDir' ] = thisDirectory; + serverJSONToSave[ 'app' ][ 'webConfigDir' ] = thisDirectory; break; case "serverConfigDir": // This path is canonical already. @@ -404,10 +414,10 @@ component accessors="true" singleton { if( thisDirectory contains configPath ) { thisDirectory = replaceNoCase( thisDirectory, configPath, '' ); } - serverJSON[ 'app' ][ 'serverConfigDir' ] = thisDirectory; + serverJSONToSave[ 'app' ][ 'serverConfigDir' ] = thisDirectory; break; case "libDirs": - serverJSON[ 'app' ][ 'libDirs' ] = serverProps[ 'libDirs' ] + serverJSONToSave[ 'app' ][ 'libDirs' ] = serverProps[ 'libDirs' ] .listMap( function( thisLibDir ) { // This path is canonical already. var thisLibDir = replace( thisLibDir, '\', '/', 'all' ); @@ -421,10 +431,10 @@ component accessors="true" singleton { break; case "cfengine": - serverJSON[ 'app' ][ 'cfengine' ] = serverProps[ prop ]; + serverJSONToSave[ 'app' ][ 'cfengine' ] = serverProps[ prop ]; break; case "restMappings": - serverJSON[ 'app' ][ 'restMappings' ] = serverProps[ prop ]; + serverJSONToSave[ 'app' ][ 'restMappings' ] = serverProps[ prop ]; break; case "WARPath": // This path is canonical already. @@ -433,7 +443,7 @@ component accessors="true" singleton { if( thisFile contains configPath ) { thisFile = replaceNoCase( thisFile, configPath, '' ); } - serverJSON[ 'app' ][ 'WARPath' ] = thisFile; + serverJSONToSave[ 'app' ][ 'WARPath' ] = thisFile; break; case "serverHomeDirectory": // This path is canonical already. @@ -442,37 +452,37 @@ component accessors="true" singleton { if( thisDirectory contains configPath ) { thisDirectory = replaceNoCase( thisDirectory, configPath, '' ); } - serverJSON[ 'app' ][ 'serverHomeDirectory' ] = thisDirectory; + serverJSONToSave[ 'app' ][ 'serverHomeDirectory' ] = thisDirectory; break; case "HTTPEnable": - serverJSON[ 'web' ][ 'HTTP' ][ 'enable' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'HTTP' ][ 'enable' ] = serverProps[ prop ]; break; case "SSLEnable": - serverJSON[ 'web' ][ 'SSL' ][ 'enable' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'SSL' ][ 'enable' ] = serverProps[ prop ]; break; case "SSLPort": - serverJSON[ 'web' ][ 'SSL' ][ 'port' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'SSL' ][ 'port' ] = serverProps[ prop ]; break; case "AJPEnable": - serverJSON[ 'web' ][ 'AJP' ][ 'enable' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'AJP' ][ 'enable' ] = serverProps[ prop ]; break; case "AJPPort": - serverJSON[ 'web' ][ 'AJP' ][ 'port' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'AJP' ][ 'port' ] = serverProps[ prop ]; break; case "SSLCertFile": - serverJSON[ 'web' ][ 'SSL' ][ 'certFile' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'SSL' ][ 'certFile' ] = serverProps[ prop ]; break; case "SSLKeyFile": - serverJSON[ 'web' ][ 'SSL' ][ 'keyFile' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'SSL' ][ 'keyFile' ] = serverProps[ prop ]; break; case "SSLKeyPass": - serverJSON[ 'web' ][ 'SSL' ][ 'keyPass' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'SSL' ][ 'keyPass' ] = serverProps[ prop ]; break; case "welcomeFiles": - serverJSON[ 'web' ][ 'welcomeFiles' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'welcomeFiles' ] = serverProps[ prop ]; break; case "rewritesEnable": - serverJSON[ 'web' ][ 'rewrites' ][ 'enable' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'rewrites' ][ 'enable' ] = serverProps[ prop ]; break; case "rewritesConfig": // This path is canonical already. @@ -481,46 +491,41 @@ component accessors="true" singleton { if( thisFile contains configPath ) { thisFile = replaceNoCase( thisFile, configPath, '' ); } - serverJSON[ 'web' ][ 'rewrites' ][ 'config' ] = thisFile; + serverJSONToSave[ 'web' ][ 'rewrites' ][ 'config' ] = thisFile; break; case "blockCFAdmin": - serverJSON[ 'web' ][ 'blockCFAdmin' ] = serverProps[ prop ]; + serverJSONToSave[ 'web' ][ 'blockCFAdmin' ] = serverProps[ prop ]; break; case "heapSize": - serverJSON[ 'JVM' ][ 'heapSize' ] = serverProps[ prop ]; + serverJSONToSave[ 'JVM' ][ 'heapSize' ] = serverProps[ prop ]; break; case "minHeapSize": - serverJSON[ 'JVM' ][ 'minHeapSize' ] = serverProps[ prop ]; + serverJSONToSave[ 'JVM' ][ 'minHeapSize' ] = serverProps[ prop ]; break; case "JVMArgs": - serverJSON[ 'JVM' ][ 'args' ] = serverProps[ prop ]; + serverJSONToSave[ 'JVM' ][ 'args' ] = serverProps[ prop ]; break; case "javaHomeDirectory": - serverJSON[ 'JVM' ][ 'javaHome' ] = serverProps[ prop ]; + serverJSONToSave[ 'JVM' ][ 'javaHome' ] = serverProps[ prop ]; break; case "javaVersion": - serverJSON[ 'JVM' ][ 'javaVersion' ] = serverProps[ prop ]; + serverJSONToSave[ 'JVM' ][ 'javaVersion' ] = serverProps[ prop ]; break; case "runwarJarPath": - serverJSON[ 'runwar' ][ 'jarPath' ] = serverProps[ prop ]; + serverJSONToSave[ 'runwar' ][ 'jarPath' ] = serverProps[ prop ]; break; case "runwarArgs": - serverJSON[ 'runwar' ][ 'args' ] = serverProps[ prop ]; + serverJSONToSave[ 'runwar' ][ 'args' ] = serverProps[ prop ]; break; default: - serverJSON[ prop ] = serverProps[ prop ]; + serverJSONToSave[ prop ] = serverProps[ prop ]; } // end switch } // for loop - if( !serverJSON.isEmpty() && serverProps.saveSettings ) { - saveServerJSON( defaultServerConfigFile, serverJSON ); + if( !serverJSONToSave.isEmpty() && serverProps.saveSettings ) { + saveServerJSON( defaultServerConfigFile, serverJSONToSave ); } - systemSettings.expandDeepSystemSettings( serverJSON ); - systemSettings.expandDeepSystemSettings( defaults ); - // Mix in environment variable overrides like BOX_SERVER_PROFILE - loadOverrides( serverJSON, serverInfo ); - // These are already hammered out above, so no need to go through all the defaults. serverInfo.serverConfigFile = defaultServerConfigFile; serverInfo.name = defaultName; @@ -1045,9 +1050,7 @@ component accessors="true" singleton { serverInfo.engineName = installDetails.engineName; serverInfo.engineVersion = installDetails.version; serverInfo.appFileSystemPath = serverInfo.webroot; - - // 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, serverJSON=serverJSON, defaults=defaults, serverProps=serverProps, serverDetails=serverDetails } ); @@ -2694,16 +2697,19 @@ component accessors="true" singleton { /** * Loads config settings from env vars or Java system properties */ - function loadOverrides( serverJSON, serverInfo ){ + function loadOverrides( serverJSON, serverInfo, boolean verbose=false ){ + var debugMessages = []; + var job = wirebox.getInstance( 'interactiveJob' ); var overrides={}; // Look for individual BOX settings to import. - var processVarsUDF = function( envVar, value ) { + var processVarsUDF = function( envVar, value, string source ) { // Loop over any that look like box_server_xxx if( envVar.len() > 11 && reFindNoCase( 'box[_\.]server[_\.]', left( envVar, 11 ) ) ) { // proxy_host gets turned into proxy.host // Note, the asssumption is made that no config setting will ever have a legitimate underscore in the name var name = right( envVar, len( envVar ) - 11 ).replace( '_', '.', 'all' ); + debugMessages.append( 'Overridding [#name#] with #source# [#envVar#]' ); JSONService.set( JSON=overrides, properties={ '#name#' : value }, thisAppend=true ); } }; @@ -2711,25 +2717,31 @@ component accessors="true" singleton { // Get all OS env vars var envVars = system.getenv(); for( var envVar in envVars ) { - processVarsUDF( envVar, envVars[ envVar ] ); + processVarsUDF( envVar, envVars[ envVar ], 'OS environment variable' ); } // Get all System Properties var props = system.getProperties(); for( var prop in props ) { - processVarsUDF( prop, props[ prop ] ); + processVarsUDF( prop, props[ prop ], 'system property' ); } // Get all box environemnt variable var envVars = systemSettings.getAllEnvironmentsFlattened(); for( var envVar in envVars ) { - processVarsUDF( envVar, envVars[ envVar ] ); + processVarsUDF( envVar, envVars[ envVar ], 'box environment variable' ); } if( overrides.keyExists( 'profile' ) ) { serverInfo.envVarHasProfile=true } + if( verbose && debugMessages.len() ) { + job.start( 'Overriding server.json values from env vars' ); + debugMessages.each( (l)=>job.addLog( l ) ); + job.complete( verbose ); + } + JSONService.mergeData( serverJSON, overrides ); } From 02084d1482312af44ae65f91bf189556b26f23bd Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 7 Dec 2021 15:34:50 -0600 Subject: [PATCH 015/118] COMMANDBOX-1411 --- build/build.properties | 2 +- .../system/services/ServerEngineService.cfc | 6 +++ src/cfml/system/services/ServerService.cfc | 45 ++++++++++++++++--- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/build/build.properties b/build/build.properties index 283c9830..db0dde82 100644 --- a/build/build.properties +++ b/build/build.properties @@ -19,7 +19,7 @@ lucee.version=${cfml.version} lucee.config.version=5.2.4.37 jre.version=jdk-11.0.12+7 launch4j.version=3.14 -runwar.version=4.5.2 +runwar.version=4.6.1-SNAPSHOT jline.version=3.19.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index 84676482..6d1b8f41 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -398,6 +398,12 @@ component accessors="true" singleton="true" { var updateMade = false; var package = lcase( cfengine ); + // if we're in multi-context mode, we need to deal with more than one web context, so the path MUST be dynamic + // If the user wants the default Lucee behavior, they can set this to "{web-root-directory}/WEB-INF/lucee/" + // If the path doesn't look to already be dynamic, we'll make it so + if( serverInfo.multiContext && not fullWebConfigDir contains '{web-root-directory}' && not fullWebConfigDir contains '{web-context-hash}' ) { + fullWebConfigDir &= '-{web-context-hash}' + } updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.CFMLServlet', "#package#-web-directory", fullWebConfigDir ); updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.CFMLServlet', "#package#-server-directory", fullServerConfigDir ) || updateMade; diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index e0497cac..e3567657 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -217,6 +217,12 @@ component accessors="true" singleton { 'XNIOOptions' : duplicate( d.runwar.XNIOOptions ?: {} ), // Duplicate so onServerStart interceptors don't actually change config settings via reference. 'undertowOptions' : duplicate( d.runwar.undertowOptions ?: {} ) + }, + 'ModCFML' : { + 'enable' : d.ModCFML.enable ?: false, + 'maxContexts' : d.ModCFML.maxContexts ?: 200, + 'sharedKey' : d.ModCFML.sharedKey ?: '', + 'requireSharedKey' : d.ModCFML.requireSharedKey ?: true } }; } @@ -884,7 +890,7 @@ component accessors="true" singleton { if( serverJSON.keyExists( 'web' ) && serverJSON.web.keyExists( 'rules' ) ) { if( !isArray( serverJSON.web.rules ) ) { - throw( message="'rules' key in your box.json must be an array of strings.", type="commandException" ); + throw( message="'rules' key in your server.json must be an array of strings.", type="commandException" ); } serverInfo.webRules.append( serverJSON.web.rules, true); } @@ -980,7 +986,7 @@ component accessors="true" singleton { 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 ); } serverInfo.serverHomeDirectory = serverProps.serverHomeDirectory ?: serverJSON.app.serverHomeDirectory ?: defaults.app.serverHomeDirectory; - serverInfo.singleServerHome = serverJSON.app.singleServerHome ?: defaults.app.singleServerHome; + serverInfo.singleServerHome = serverJSON.app.singleServerHome ?: defaults.app.singleServerHome; if( len( serverJSON.app.webXMLOverride ?: '' ) ){ serverJSON.app.webXMLOverride = fileSystemUtil.resolvePath( serverJSON.app.webXMLOverride, defaultServerConfigFileDirectory ); } if( len( defaults.app.webXMLOverride ?: '' ) ){ defaults.app.webXMLOverride = fileSystemUtil.resolvePath( defaults.app.webXMLOverride, defaultwebroot ); } @@ -993,8 +999,16 @@ component accessors="true" singleton { serverInfo.webXMLOverrideForce = serverJSON.app.webXMLOverrideForce ?: defaults.app.webXMLOverrideForce; serverInfo.sessionCookieSecure = serverJSON.app.sessionCookieSecure ?: defaults.app.sessionCookieSecure; - serverInfo.sessionCookieHTTPOnly = serverJSON.app.sessionCookieHTTPOnly ?: defaults.app.sessionCookieHTTPOnly; - + serverInfo.sessionCookieHTTPOnly = serverJSON.app.sessionCookieHTTPOnly ?: defaults.app.sessionCookieHTTPOnly; + + serverInfo.ModCFMLenable = serverJSON.ModCFML.enable ?: defaults.ModCFML.enable; + serverInfo.ModCFMLMaxContexts = serverJSON.ModCFML.maxContexts ?: defaults.ModCFML.maxContexts; + serverInfo.ModCFMLSharedKey = serverJSON.ModCFML.sharedKey ?: defaults.ModCFML.sharedKey; + serverInfo.ModCFMLRequireSharedKey = serverJSON.ModCFML.requireSharedKey ?: defaults.ModCFML.requireSharedKey; + + // When we add native support for multiple contexts in the server.json, that will also set this to true + serverInfo.multiContext = serverInfo.ModCFMLenable; + if( serverInfo.verbose ) { job.addLog( "start server in - " & serverInfo.webroot ); job.addLog( "server name - " & serverInfo.name ); @@ -1050,7 +1064,9 @@ component accessors="true" singleton { serverInfo.engineName = installDetails.engineName; serverInfo.engineVersion = installDetails.version; serverInfo.appFileSystemPath = serverInfo.webroot; - + + // 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, serverJSON=serverJSON, defaults=defaults, serverProps=serverProps, serverDetails=serverDetails } ); @@ -1319,7 +1335,11 @@ component accessors="true" singleton { args.append( '--preferred-browser' ).append( ConfigService.getSetting( 'preferredBrowser' ) ); } - args.append( serverInfo.runwarArgs.listToArray( ' ' ), true ); + args.append( parser.tokenizeInput( serverInfo.runwarArgs.replace( ';', '\;', 'all' ) ) + .map( function( i ){ + // unwrap quotes, and unescape any special chars like \" inside the string + return parser.replaceEscapedChars( parser.removeEscapedChars( parser.unwrapQuotes( i ) ) ); + }), true ); if( serverInfo.trayEnable ) { args @@ -1505,6 +1525,19 @@ component accessors="true" singleton { args.append( '--predicate-file' ).append( serverInfo.predicateFile ); } + if( serverInfo.ModCFMLenable ){ + args.append( '--auto-create-contexts' ).append( serverInfo.ModCFMLenable ); + if( len( serverInfo.ModCFMLMaxContexts ) && isNumeric( serverInfo.ModCFMLMaxContexts ) && serverInfo.ModCFMLMaxContexts > 0 ) { + args.append( '--auto-create-contexts-max' ).append( serverInfo.ModCFMLMaxContexts ); + } + if( !len( serverInfo.ModCFMLSharedKey ) && serverInfo.ModCFMLRequireSharedKey ) { + throw( message='Since ModeCFML support is enabled, [ModCFML.sharedKey] is required for security.', detail='Disable IN DEVELOPMENT ONLY with [ModCFML.RequireSharedKey=false].', type="commandException" ); + } + if( len( serverInfo.ModCFMLSharedKey ) ) { + args.append( '--auto-create-contexts-secret' ).append( serverInfo.ModCFMLSharedKey ); + } + } + // change status to starting + persist serverInfo.dateLastStarted = now(); serverInfo.status = "starting"; From 4c4a0534d078c310746ee7bb1b7d72ebaa618f4c Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 7 Dec 2021 15:36:50 -0600 Subject: [PATCH 016/118] COMMANDBOX-1401 --- src/cfml/system/services/CommandService.cfc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 8769f59f..94c9c932 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -193,16 +193,17 @@ component accessors="true" singleton { previousCommandSeparator = commandInfo.originalLine; continue; } - + if( previousCommandSeparator == '&&' && lastCommandErrored ) { + continue; return result ?: ''; } if( previousCommandSeparator == '||' && !lastCommandErrored ) { + continue; return result ?: ''; } - // If nothing was found, bail out here. if( !commandInfo.found ){ var detail = generateListOfSimilarCommands( commandInfo ); @@ -1134,7 +1135,19 @@ component accessors="true" singleton { // Overwrite it with an actual Globber instance seeded with the original canonical path as the pattern. var originalPath = parameterInfo.namedParameters[ paramName ]; - var newPath = originalPath.listMap( (p) => fileSystemUtil.resolvePath( p ) ); + var newPath = originalPath.listMap( (p) => { + p = fileSystemUtil.resolvePath( p ); + // The globber won't match a dir if you include the trailing slash, so pull them off + // This allows + // > rm tests/ + // or + // > touch tests + // to affect the "tests" folder itself + if( p.endsWith( '/' ) || p.endsWith( '\' ) ) { + p = p.left(-1); + } + return p; + } ); parameterInfo.namedParameters[ paramName ] = wirebox.getInstance( 'Globber' ) .setPattern( newPath ); From a9659a255f068dc1607ed686e79950c6b9127a48 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 7 Dec 2021 15:39:01 -0600 Subject: [PATCH 017/118] COMMANDBOX-1413 --- src/java/cliloader/LoaderCLIMain.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/cliloader/LoaderCLIMain.java b/src/java/cliloader/LoaderCLIMain.java index e27e31c1..cd5592b5 100644 --- a/src/java/cliloader/LoaderCLIMain.java +++ b/src/java/cliloader/LoaderCLIMain.java @@ -528,7 +528,8 @@ public static boolean listContains( ArrayList< String > argList, String text ){ public static int listIndexOf( ArrayList< String > argList, String text ){ int index = 0; for( String item : argList) { - if( item.startsWith( text ) || item.startsWith( "-" + text ) ) { + if( item.toLowerCase().startsWith( text.toLowerCase() ) + || item.toLowerCase().startsWith( "-" + text.toLowerCase() ) ) { return index; } index++; From 8f8ca8ca006df1753e44efbbf4d82e45cdc67935 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 7 Dec 2021 15:39:23 -0600 Subject: [PATCH 018/118] COMMANDBOX-1413 --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index db0dde82..fee65b4e 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,7 +12,7 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.8.206 cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.6 +cfml.loader.version=2.6.7 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org From fafaa2d407fbf2a19d8dd54874e6f8861ed20fb9 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 7 Dec 2021 15:41:44 -0600 Subject: [PATCH 019/118] COMMANDBOX-1414 --- src/cfml/system/services/PackageService.cfc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index f0d15266..9a5db0dd 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -622,10 +622,7 @@ component accessors="true" singleton { if( shellWillReload && artifactDescriptor.createPackageDirectory && fileExists( installDirectory & '/ModuleConfig.cfc' ) ) { consoleLogger.warn( 'Activating your new module for instant use...' ); - moduleService.registerAndActivateModule( installDirectory.listLast( '/\' ), fileSystemUtil.makePathRelative( installDirectory ) ); - //shell.reload( clear=false ); - //consoleLogger.warn( '.' ); - //consoleLogger.warn( 'Please sit tight while your shell reloads...' ); + moduleService.registerAndActivateModule( installDirectory.listLast( '/\' ), fileSystemUtil.makePathRelative( installDirectory ).listToArray( '/\' ).slice( 1, -1 ).toList( '.' ) ); } interceptorService.announceInterception( 'postInstall', { installArgs=arguments, installDirectory=installDirectory } ); From de3f4819742a6c645944f870e24bec065857781d Mon Sep 17 00:00:00 2001 From: Balbino Aylagas Date: Thu, 9 Dec 2021 11:16:47 -0600 Subject: [PATCH 020/118] moved modification to ServerEngiveService, removed previous modif --- .../system/services/ServerEngineService.cfc | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index 6d1b8f41..f1abe9d0 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -79,7 +79,7 @@ component accessors="true" singleton="true" { } } - // Users won't be able to create datasources if this file isn't created. + // Users won't be able to create datasources if this file isn't created. // It needs to be different for every install, which is why we're creating it on the fly. var seedPropertiesPath = installDetails.installDir & "/WEB-INF/cfusion/lib/seed.properties"; ensureSeedProperties( seedPropertiesPath ); @@ -96,6 +96,8 @@ component accessors="true" singleton="true" { if( len( serverInfo.webXMLOverride ) ){ serverInfo.webXMLOverrideActual = serverInfo.webXML.replace( 'web.xml', 'web-override.xml' ); configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXMLOverride, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); + } else { + serverInfo.webXMLOverrideActual = ''; } return installDetails; } @@ -109,6 +111,8 @@ component accessors="true" singleton="true" { if( len( serverInfo.webXMLOverride ) ){ serverInfo.webXMLOverrideActual = serverInfo.webXML.replace( 'web.xml', 'web-override.xml' ); configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXMLOverride, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); + } else { + serverInfo.webXMLOverrideActual = ''; } return installDetails; } @@ -206,7 +210,7 @@ component accessors="true" singleton="true" { if( serverInfo.singleServerHome ) { installDetails.installDir = destination & engineName; } else { - installDetails.installDir = destination & engineName & "-" & replace( satisfyingVersion, '+', '.', 'all' ); + installDetails.installDir = destination & engineName & "-" & replace( satisfyingVersion, '+', '.', 'all' ); } } installDetails.version = satisfyingVersion; @@ -277,7 +281,7 @@ component accessors="true" singleton="true" { unpackLuceeJar( thislib, installDetails.version ); if( !fileExists( thisWebinf & '/web.xml' ) ) { - fileCopy( expandPath( '/commandbox/system/config/web.xml' ), thisWebinf & '/web.xml'); + fileCopy( expandPath( '/commandbox/system/config/web.xml' ), thisWebinf & '/web.xml'); } // Mark this WAR as being exploded already @@ -397,7 +401,7 @@ component accessors="true" singleton="true" { var webXML = XMLParse( source ); var updateMade = false; var package = lcase( cfengine ); - + // if we're in multi-context mode, we need to deal with more than one web context, so the path MUST be dynamic // If the user wants the default Lucee behavior, they can set this to "{web-root-directory}/WEB-INF/lucee/" // If the path doesn't look to already be dynamic, we'll make it so @@ -406,18 +410,18 @@ component accessors="true" singleton="true" { } updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.CFMLServlet', "#package#-web-directory", fullWebConfigDir ); updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.CFMLServlet', "#package#-server-directory", fullServerConfigDir ) || updateMade; - + // 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 ) { updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.LuceeServlet', "#package#-web-directory", fullWebConfigDir ) || updateMade; updateMade = ensurePropertServletInitParam( webXML, '#package#.loader.servlet.LuceeServlet', "#package#-server-directory", fullServerConfigDir ) || updateMade; } if( updateMade || !fileExists( destination ) || forceUpdate ) { - writeXMLFile( webXML, destination ); + writeXMLFile( webXML, destination ); } return true; } - + /** * Ensure a given servlet has a specific init param value @@ -426,7 +430,7 @@ component accessors="true" singleton="true" { * @servletClass Name of servlet to check * @initParamName Name of init param to ensure exists * @initParamValue Value init param needs to have - * + * * @returns true if changes were made, false if nothing was updated. **/ function ensurePropertServletInitParam( webXML, string servletClass, string initParamName, string initParamValue ) { @@ -437,7 +441,7 @@ component accessors="true" singleton="true" { if( !servlets.len() ) { return false; } - + // If this servlet already has an init-param of this name, ensure the value is correct for( var initParam in servlets[1].XMLParent.XMLChildren.filter( (x)=>x.XMLName=='init-param' ) ) { if( !isNull( initParam[ 'param-name' ].XMLText ) && initParam[ 'param-name' ].XMLText == initParamName ) { @@ -449,7 +453,7 @@ component accessors="true" singleton="true" { } } } - + // if we didn't find a matching init-param above then add it now var initParam = xmlElemnew(webXML,"http://java.sun.com/xml/ns/javaee","init-param"); initParam.XmlChildren[1] = xmlElemnew(webXML,"param-name"); From 72fd361b22c45c9f212c9238d99fc6370f6ba218 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 9 Dec 2021 12:29:32 -0600 Subject: [PATCH 021/118] Update to new property file module --- src/cfml/system/modules/propertyFile/box.json | 6 +-- .../propertyFile/models/PropertyFile.cfc | 43 +++++++++++-------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/cfml/system/modules/propertyFile/box.json b/src/cfml/system/modules/propertyFile/box.json index 7c2184fa..f27f839f 100644 --- a/src/cfml/system/modules/propertyFile/box.json +++ b/src/cfml/system/modules/propertyFile/box.json @@ -1,8 +1,8 @@ { "name":"PropertyFile Util", - "version":"1.2.0", + "version":"1.3.1", "author":"Brad Wood", - "location":"bdw429s/PropertyFile#v1.2.0", + "location":"forgeboxStorage", "homepage":"https://github.com/bdw429s/PropertyFile/", "documentation":"https://github.com/bdw429s/PropertyFile/blob/master/readme.md", "repository":{ @@ -16,7 +16,7 @@ "keywords":"java,property,files", "projectURL":"https://github.com/bdw429s/PropertyFile/", "scripts":{ - "postVersion":"package set location='bdw429s/PropertyFile#v`package version`'", + "postVersion":"publish", "postPublish":"!git push --follow-tags" }, "ignore":[ diff --git a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc index 30c8fb97..5a07da86 100644 --- a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc +++ b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc @@ -2,13 +2,13 @@ * I am a new Model Object */ component accessors="true"{ - + // Properties property name='javaPropertyFile'; // A fully qualified path to a property file property name='path'; property name='syncedNames'; - + /** * Constructor @@ -18,7 +18,7 @@ component accessors="true"{ setJavaPropertyFile( createObject( 'java', 'java.util.Properties' ).init() ); return this; } - + /** * @load A fully qualified path to a property file */ @@ -29,17 +29,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; } @@ -48,16 +48,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( arguments.path ); getJavaPropertyFile().store( fos, '' ); fos.close(); - + return this; } @@ -66,7 +66,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 { @@ -79,14 +79,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; } @@ -96,7 +96,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 ) ); @@ -124,6 +124,15 @@ component accessors="true"{ return result; } + /** + * mergeStruct + */ + function mergeStruct( struct incomingStruct ){ + structAppend( this, incomingStruct ); + syncProperties(); + return this; + } + /** * Keeps public properties in sync with Java object */ @@ -131,7 +140,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 @@ -139,7 +148,7 @@ component accessors="true"{ set( prop, this[ prop ] ); } } - + // All the properties in the Java object var props = propertyFile.propertyNames(); while( props.hasMoreElements() ) { @@ -149,7 +158,7 @@ component accessors="true"{ remove( prop ); } } - + } } \ No newline at end of file From 47db451c1db143afe0e5d5d0e77da75c5bae2a56 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 9 Dec 2021 18:29:04 -0600 Subject: [PATCH 022/118] COMMANDBOX-1411 --- src/cfml/system/services/ServerService.cfc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index e3567657..f1e2832b 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -222,7 +222,8 @@ component accessors="true" singleton { 'enable' : d.ModCFML.enable ?: false, 'maxContexts' : d.ModCFML.maxContexts ?: 200, 'sharedKey' : d.ModCFML.sharedKey ?: '', - 'requireSharedKey' : d.ModCFML.requireSharedKey ?: true + 'requireSharedKey' : d.ModCFML.requireSharedKey ?: true, + 'createVirtualDirectories' : d.ModCFML.createVirtualDirectories ?: true } }; } @@ -1005,6 +1006,7 @@ component accessors="true" singleton { serverInfo.ModCFMLMaxContexts = serverJSON.ModCFML.maxContexts ?: defaults.ModCFML.maxContexts; serverInfo.ModCFMLSharedKey = serverJSON.ModCFML.sharedKey ?: defaults.ModCFML.sharedKey; serverInfo.ModCFMLRequireSharedKey = serverJSON.ModCFML.requireSharedKey ?: defaults.ModCFML.requireSharedKey; + serverInfo.ModCFMLcreateVDirs = serverJSON.ModCFML.createVirtualDirectories ?: defaults.ModCFML.createVirtualDirectories; // When we add native support for multiple contexts in the server.json, that will also set this to true serverInfo.multiContext = serverInfo.ModCFMLenable; @@ -1536,6 +1538,9 @@ component accessors="true" singleton { if( len( serverInfo.ModCFMLSharedKey ) ) { args.append( '--auto-create-contexts-secret' ).append( serverInfo.ModCFMLSharedKey ); } + if( serverInfo.ModCFMLcreateVDirs ) { + args.append( '--auto-create-contexts-vdirs' ).append( serverInfo.ModCFMLcreateVDirs ); + } } // change status to starting + persist From 059541ff3274f29860d35e94b5b9193722cbb995 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 10 Dec 2021 15:09:58 -0600 Subject: [PATCH 023/118] Patch update for propertyFile --- src/cfml/system/modules/propertyFile/box.json | 2 +- src/cfml/system/modules/propertyFile/models/PropertyFile.cfc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/modules/propertyFile/box.json b/src/cfml/system/modules/propertyFile/box.json index f27f839f..2afa2d60 100644 --- a/src/cfml/system/modules/propertyFile/box.json +++ b/src/cfml/system/modules/propertyFile/box.json @@ -1,6 +1,6 @@ { "name":"PropertyFile Util", - "version":"1.3.1", + "version":"1.3.2", "author":"Brad Wood", "location":"forgeboxStorage", "homepage":"https://github.com/bdw429s/PropertyFile/", diff --git a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc index 5a07da86..3ef11c40 100644 --- a/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc +++ b/src/cfml/system/modules/propertyFile/models/PropertyFile.cfc @@ -138,7 +138,7 @@ component accessors="true"{ */ private function syncProperties() { var syncedNames = getSyncedNames(); - var ignore = listToArray( 'init,load,store,get,set,exists,remove,exists,getAsStruct,$mixed' ); + var ignore = listToArray( 'init,load,store,get,set,exists,remove,exists,getAsStruct,$mixed,mergeStruct' ); var propertyFile = getJavaPropertyFile(); // This CFC's public properties From 4439cf7b8bc42ae96fcc25ec92deee3689c6b4ba Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 20 Dec 2021 12:56:42 -0600 Subject: [PATCH 024/118] COMMANDBOX-1416 --- .../system/services/ServerEngineService.cfc | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cfml/system/services/ServerEngineService.cfc b/src/cfml/system/services/ServerEngineService.cfc index f1abe9d0..a80f4327 100644 --- a/src/cfml/system/services/ServerEngineService.cfc +++ b/src/cfml/system/services/ServerEngineService.cfc @@ -36,6 +36,13 @@ component accessors="true" singleton="true" { var installDetails = installEngineArchive( cfengine, arguments.baseDirectory, serverInfo, serverHomeDirectory ); + if( len( serverInfo.webXMLOverride ) ){ + serverInfo.webXMLOverrideActual = serverInfo.webXML.replace( 'web.xml', 'web-override.xml' ); + fileCopy( serverInfo.webXMLOverride, serverInfo.webXMLOverrideActual ); + } else { + serverInfo.webXMLOverrideActual = ''; + } + if( installDetails.engineName contains "adobe" ) { return installAdobe( installDetails, serverInfo ); } else if ( installDetails.engineName contains "railo" ) { @@ -93,11 +100,8 @@ component accessors="true" singleton="true" { **/ public function installLucee( installDetails, serverInfo ) { configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXML, destination=serverInfo.webXML, serverInfo=serverInfo, installDetails=installDetails ); - if( len( serverInfo.webXMLOverride ) ){ - serverInfo.webXMLOverrideActual = serverInfo.webXML.replace( 'web.xml', 'web-override.xml' ); - configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXMLOverride, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); - } else { - serverInfo.webXMLOverrideActual = ''; + if( len( serverInfo.webXMLOverrideActual ) ){ + configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXMLOverrideActual, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); } return installDetails; } @@ -108,11 +112,8 @@ component accessors="true" singleton="true" { **/ public function installRailo( installDetails, serverInfo ) { configureWebXML( cfengine="railo", version=installDetails.version, source=serverInfo.webXML, destination=serverInfo.webXML, serverInfo=serverInfo, installDetails=installDetails ); - if( len( serverInfo.webXMLOverride ) ){ - serverInfo.webXMLOverrideActual = serverInfo.webXML.replace( 'web.xml', 'web-override.xml' ); - configureWebXML( cfengine="lucee", version=installDetails.version, source=serverInfo.webXMLOverride, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); - } else { - serverInfo.webXMLOverrideActual = ''; + if( len( serverInfo.webXMLOverrideActual ) ){ + configureWebXML( cfengine="railo", version=installDetails.version, source=serverInfo.webXMLOverrideActual, destination=serverInfo.webXMLOverrideActual, serverInfo=serverInfo, installDetails=installDetails, forceUpdate=true ); } return installDetails; } From b352be04906b7f97d7eab522890a169fa95705b7 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 21 Dec 2021 13:09:10 -0600 Subject: [PATCH 025/118] bump runwar --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index fee65b4e..7a7a92c6 100644 --- a/build/build.properties +++ b/build/build.properties @@ -19,7 +19,7 @@ lucee.version=${cfml.version} lucee.config.version=5.2.4.37 jre.version=jdk-11.0.12+7 launch4j.version=3.14 -runwar.version=4.6.1-SNAPSHOT +runwar.version=4.6.2-SNAPSHOT jline.version=3.19.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r From 64ac3be0d01fd3cd6b11858dde8468f2ec9d19ad Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 21 Dec 2021 13:44:12 -0600 Subject: [PATCH 026/118] Bump loader --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 7a7a92c6..a3814207 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,7 +12,7 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.8.206 cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.7 +cfml.loader.version=2.6.8 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org From 4d705c3690be051c91e51f51a95f0fd001914538 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 10:26:55 -0600 Subject: [PATCH 027/118] COMMANDBOX-1410 --- src/cfml/system/services/InterceptorService.cfc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/InterceptorService.cfc b/src/cfml/system/services/InterceptorService.cfc index 9ac1eb6b..b1e539ab 100644 --- a/src/cfml/system/services/InterceptorService.cfc +++ b/src/cfml/system/services/InterceptorService.cfc @@ -53,12 +53,16 @@ component accessors=true singleton { return this; } - function announceInterception( required string state, struct interceptData={} ) { + function announce( required string state, struct interceptData={} ) { getEventPoolManager().announce( state, interceptData ); } + function announceInterception( required string state, struct interceptData={} ) { + announce( state, interceptData ); + } + function processState( required string state, struct interceptData={} ) { - announceInterception( state, interceptData ); + announce( state, interceptData ); } /** From bbd6d9fab32c4a0ba76a3b108dc99d968f59eeef Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 11:13:20 -0600 Subject: [PATCH 028/118] COMMANDBOX-1409 --- .../modules_app/server-commands/commands/server/cfpm.cfc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc b/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc index d8d77d0d..00732564 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc @@ -43,6 +43,11 @@ component aliases='cfpm' { while( !isNull( arguments[++i] ) ) { cmd &= ' #arguments[i]#'; } + + // The user's OS may not have a JAVA_HOME set up + if( systemSettings.getSystemSetting( 'JAVA_HOME', '___NOT_SET___' ) == '___NOT_SET___' ) { + systemSettings.setSystemSetting( 'JAVA_HOME', fileSystemUtil.getJREExecutable().reReplaceNoCase( '(/|\\)bin(/|\\)java(.exe)?', '' ) ); + } command( 'run' ) .params( cmd ) From 46c190e5669a64c6f246b47540db08a26d17427c Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 12:45:02 -0600 Subject: [PATCH 029/118] COMMANDBOX-1405 --- .../server-commands/commands/server/cfpm.cfc | 86 ++++++++++++++++--- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc b/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc index 00732564..a4a67bc7 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/cfpm.cfc @@ -1,5 +1,7 @@ /** - * Run cfpm for an Adobe ColdFuson 2021+ server + * Run cfpm for an Adobe ColdFuson 2021+ server. If there is more than one server started in the current working + * directory, this command will search for the first Adobe 2021+ server and use that. + * If this command is run as part of a server package script, it will applly to the server being started. * . * Open the cfpm shell * . @@ -12,22 +14,73 @@ * {code:bash} * cfpm install feed * {code} - **/ + * . + * If there is more than one Adobe 2021+ server started in a given directory, you can specific the server you want + * by setting the server name into the CFPM_SERVER environment variable. Note this works from any directory. + * Make sure to clear the env var afterwards so it doesn't surprise you on later usage of this command in the same shell. + * . + * {code:bash} + * set CFPM_SERVER=myTestServer + * cfpm install feed + * env clear CFPM_SERVER + * {code} +**/ component aliases='cfpm' { property name='serverService' inject='ServerService'; function run(){ - // Since any args passed in are sent on to cfpm, we can't allow the user to send us details of what server they want. - // Therefore, this command only works in the web root of the server and if the Adobe server is the default one. - var serverDetails = serverService.resolveServerDetails( {} ); - - if( serverDetails.serverIsNew ) { - error( 'No Server found in [#getCWD()#]' ); + var serverInfo = {}; + var cfpm_server = systemSettings.getSystemSetting( 'CFPM_SERVER', '' ); + var interceptData_serverInfo_name = systemSettings.getSystemSetting( 'interceptData.SERVERINFO.name', '' ); + + if( configService.getSetting( 'server.singleServerMode', false ) && serverService.getServers().count() ){ + serverInfo = serverService.getFirstServer().serverInfo; + // If we're running inside of a server-related package script, use that server + } else if( interceptData_serverInfo_name != '' ) { + print.yellowLine( 'Using interceptData to load server [#interceptData_serverInfo_name#]' ); + serverInfo = serverService.resolveServerDetails( { name=interceptData_serverInfo_name } ).serverInfo; + if( !(serverInfo.engineName contains 'adobe' && val( listFirst( serverInfo.engineVersion, '.' ) ) >= 2021 ) ){ + print.redLine( 'Server [#interceptData_serverInfo_name#] is of type [#serverInfo.cfengine#] and not an Adobe 2021+ server. Ignoring.' ); + return; + } + // Allow an env var hint to tell us what server to use + // CFPM_SERVER=servername + } else if( cfpm_server != '' ) { + print.yellowLine( 'Using CFPM_SERVER environment variable to load server [#cfpm_server#]' ); + var serverDetails = serverService.resolveServerDetails( { name=cfpm_server } ); + if( serverDetails.serverIsNew ) { + error( 'Server [#cfpm_server#] specified in CFPM_SERVER environment variable does not exist.' ); + return; + } + serverInfo = serverDetails.serverInfo; + if( !(serverInfo.engineName contains 'adobe' && val( listFirst( serverInfo.engineVersion, '.' ) ) >= 2021 ) ){ + print.redLine( 'Server [#cfpm_server#] is of type [#serverInfo.cfengine#] and not an Adobe 2021+ server. Ignoring.' ); + return; + } + } else { + // Fallback is to look for the first Adobe 2021+ server using the current working directory as its web root + var webroot = fileSystemUtil.resolvePath( getCWD() ); + var servers = serverService.getServers(); + for( var serverID in servers ){ + var thisServerInfo = servers[ serverID ]; + if( fileSystemUtil.resolvePath( path=thisServerInfo.webroot, forceDirectory=true ) == webroot + && thisServerInfo.engineName contains 'adobe' + && val( listFirst( thisServerInfo.engineVersion, '.' ) ) >= 2021 ){ + serverInfo = thisServerInfo; + print.yellowLine( 'Found server [#serverInfo.name#] in current directory.' ); + break; + } + } + if( !serverInfo.count() ) { + print.redLine( 'No Adobe 2021+ server found in [#getCWD()#]', 'Specify the server you want by setting the name of your server into the CFPM_SERVER environment variable.' ); + return; + } } - - var serverInfo = serverDetails.serverInfo; + + // ASSERT: At this point, we've found a specific Adobe 2021 server via env var, intercept data, or web root convention. + var cfpmPath = resolvePath( serverInfo.serverHomeDirectory ) & 'WEB-INF/cfusion/bin/cfpm'; if( !fileExists( cfpmPath & '.bat' ) ) { @@ -45,13 +98,18 @@ component aliases='cfpm' { } // The user's OS may not have a JAVA_HOME set up - if( systemSettings.getSystemSetting( 'JAVA_HOME', '___NOT_SET___' ) == '___NOT_SET___' ) { + if( systemSettings.getSystemSetting( 'JAVA_HOME', '' ) == '' ) { systemSettings.setSystemSetting( 'JAVA_HOME', fileSystemUtil.getJREExecutable().reReplaceNoCase( '(/|\\)bin(/|\\)java(.exe)?', '' ) ); } - - command( 'run' ) + print.toConsole(); + var output = command( 'run' ) .params( cmd ) - .run( echo=true ); + // Try to contain the output if we're in an interactive job and there are arguments (no args opens the cfpm shell) + .run( echo=true, returnOutput=( job.isActive() && arguments.count() ) ); + + if( job.isActive() && arguments.count() ) { + print.line( output ); + } } From 08e3b857e8148844e8419dbe5801b13b830f8db6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 12:46:44 -0600 Subject: [PATCH 030/118] COMMANDBOX-1418 --- src/cfml/system/services/CommandService.cfc | 8 +++++++- src/cfml/system/util/PrintBuffer.cfc | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 94c9c932..b7d77726 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -284,7 +284,13 @@ component accessors="true" singleton { // This will prevent the output from showing up out of order if one command nests a call to another. if( instance.callStack.len() && !captureOutput ){ // Print anything in the buffer - shell.printString( instance.callStack[1].commandInfo.commandReference.CFC.getResult() ); + var job = wirebox.getInstance( 'interactiveJob' ); + // If there is an active job, print our output through it + if( job.getActive() ) { + job.addLog( instance.callStack[1].commandInfo.commandReference.CFC.getResult() ); + } else { + shell.printString( instance.callStack[1].commandInfo.commandReference.CFC.getResult() ); + } // And reset it now that it's been printed. // This command can add more to the buffer once it's executing again. instance.callStack[1].commandInfo.commandReference.CFC.reset(); diff --git a/src/cfml/system/util/PrintBuffer.cfc b/src/cfml/system/util/PrintBuffer.cfc index 7b709db2..399dbee0 100644 --- a/src/cfml/system/util/PrintBuffer.cfc +++ b/src/cfml/system/util/PrintBuffer.cfc @@ -13,6 +13,7 @@ component accessors="true" extends="Print"{ // DI property name="shell" inject="shell"; + property name="job" inject="interactiveJob"; property name="objectID"; @@ -36,8 +37,13 @@ component accessors="true" extends="Print"{ clear(); } - // Once we get the text to print above, we can release the lock while we actually print it. - variables.shell.printString( thingToPrint ); + // Once we get the text to print above, we can release the lock while we actually print it. + // If there is an active job, print our output through it + if( job.getActive() ) { + job.addLog( thingToPrint ); + } else { + variables.shell.printString( thingToPrint ); + } } // Reset the result From 16504695559d1a475a4af6f434dae95e8113e658 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 12:57:42 -0600 Subject: [PATCH 031/118] COMMANDBOX-1403 --- .../system-commands/commands/assertFalse.cfc | 24 +++++++++++++++++++ .../system-commands/commands/assertTrue.cfc | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/cfml/system/modules_app/system-commands/commands/assertFalse.cfc diff --git a/src/cfml/system/modules_app/system-commands/commands/assertFalse.cfc b/src/cfml/system/modules_app/system-commands/commands/assertFalse.cfc new file mode 100644 index 00000000..7809390a --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/assertFalse.cfc @@ -0,0 +1,24 @@ +/** + * Returns a passing (0) or failing (1) exit code if a falsey parameter passed. Command outputs nothing. + * Falsey values are arenything OTHER than "yes", "true" and positive integers. + * . + * {code:bash} + * assertFalse `package show private` && run-script foo + * assertFalse ${GOOD_THINGS} && run-doom + * assertFalse `#fileExists foo.txt` && echo "it's not there!" + * {code} +**/ +component { + + /** + * @predicate A value that is truthy or falsy. + **/ + function run( required string predicate ) { + + if( isBoolean( predicate ) && predicate ) { + setExitCode( 1 ); + } + + } + +} diff --git a/src/cfml/system/modules_app/system-commands/commands/assertTrue.cfc b/src/cfml/system/modules_app/system-commands/commands/assertTrue.cfc index 446fdcb3..c3a0d4db 100644 --- a/src/cfml/system/modules_app/system-commands/commands/assertTrue.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/assertTrue.cfc @@ -1,7 +1,7 @@ /** - * Returns a passing (0) or failing (1) exit code whether truthy parameter passed. Command outputs nothing. + * Returns a passing (0) or failing (1) exit code if truthy parameter passed. Command outputs nothing. * Truthy values are "yes", "true" and positive integers. - * All other values are considered falsy + * All other values are considered falsey * . * {code:bash} * assertTrue `package show private` && run-script foo From f5242db1389b428a2b18bb29c9316792c061f81f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 13:00:55 -0600 Subject: [PATCH 032/118] COMMANDBOX-1402 --- .../system-commands/commands/assertEqual.cfc | 2 +- .../commands/assertNotEqual.cfc | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/cfml/system/modules_app/system-commands/commands/assertNotEqual.cfc diff --git a/src/cfml/system/modules_app/system-commands/commands/assertEqual.cfc b/src/cfml/system/modules_app/system-commands/commands/assertEqual.cfc index 2e764ddc..aba922bd 100644 --- a/src/cfml/system/modules_app/system-commands/commands/assertEqual.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/assertEqual.cfc @@ -1,5 +1,5 @@ /** - * Returns a passing (0) or failing (1) exit code whether both parameters match. Command outputs nothing. + * Returns a passing (0) or failing (1) exit code if both parameters match. Command outputs nothing. * Comparison is case insensitive. * . * {code:bash} diff --git a/src/cfml/system/modules_app/system-commands/commands/assertNotEqual.cfc b/src/cfml/system/modules_app/system-commands/commands/assertNotEqual.cfc new file mode 100644 index 00000000..5ef9653b --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/assertNotEqual.cfc @@ -0,0 +1,25 @@ +/** + * Returns a passing (0) or failing (1) exit code if parameters do not match. Command outputs nothing. + * Comparison is case insensitive. + * . + * {code:bash} + * assertNotEqual `package show name` "My Package" && package set name="My Package" + * assertNotEqual ${ENVIRONMENT} development && install --production + * {code} + * +**/ +component { + + /** + * @value1 A value to be compared to value2 + * @value2 A value to be compared to value1 + **/ + function run( required string value1, required string value2 ) { + + if( value1 == value2 ) { + setExitCode( 1 ); + } + + } + +} From 21195c049604fdd3d79fd4cae8137048b20a4ee1 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 13:16:34 -0600 Subject: [PATCH 033/118] COMMANDBOX-1407 --- .../system-commands/commands/head.cfc | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/cfml/system/modules_app/system-commands/commands/head.cfc diff --git a/src/cfml/system/modules_app/system-commands/commands/head.cfc b/src/cfml/system/modules_app/system-commands/commands/head.cfc new file mode 100644 index 00000000..f694d2a4 --- /dev/null +++ b/src/cfml/system/modules_app/system-commands/commands/head.cfc @@ -0,0 +1,66 @@ +/** + * Show the first x lines of a file. Path may be absolute or relative to the current working directory. + * . + * {code:bash} + * head file.txt + * {code} + * Displays the contents of a file to standard CommandBox output according to the number of lines argument. + * . + * Use the "lines" param to specify the number of lines to display, or it defaults to 15 lines. + * . + * {code:bash} + * head file.txt 100 + * {code} + **/ + component { + property name="printUtil" inject="print"; + property name='ansiFormatter' inject='AnsiFormatter'; + + /** + * @path file or directory to tail or raw input to process + * @lines number of lines to display. + **/ + function run( required path, numeric lines = 15 ){ + var rawText = false; + var inputAsArray = listToArray( arguments.path, chr(13) & chr(10) ); + + // If there is a line break in the input, then it's raw text + if( inputAsArray.len() > 1 ) { + var rawText = true; + } + var filePath = resolvePath( arguments.path ); + + if( !fileExists( filePath ) ){ + var rawText = true; + } + + // If we're piping raw text and not a file + if( rawText ) { + // Only show the first X lines + var i = 1; + while( i <= inputAsArray.len() && i <= lines ) { + print.line( inputAsArray[ i++ ] ); + } + + return; + } + + try { + var fileObject = fileObject = fileOpen( filePath ); + // Only show the first X lines + var i = 1; + while( i++ <= lines ) { + print.line( fileReadLine( fileObject ) ); + if( fileIsEOF( fileObject ) ) { + return; + } + } + } finally { + if( !isNull( fileObject ) ) { + fileClose( fileObject ); + } + } + + + } +} From a39b2b38346817f010855cd3b9ef100c87c9cd3d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 15:52:47 -0600 Subject: [PATCH 034/118] COMMANDBOX-1404 --- .../package-commands/ModuleConfig.cfc | 2 +- .../server-commands/ModuleConfig.cfc | 1 + .../commands/server/run-script.cfc | 92 +++++++++++++++++++ .../interceptors/ServerScripts.cfc | 35 +++++++ src/cfml/system/services/ServerService.cfc | 84 +++++++++++++++++ 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc create mode 100644 src/cfml/system/modules_app/server-commands/interceptors/ServerScripts.cfc diff --git a/src/cfml/system/modules_app/package-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/package-commands/ModuleConfig.cfc index b56ae79d..e2ca007b 100644 --- a/src/cfml/system/modules_app/package-commands/ModuleConfig.cfc +++ b/src/cfml/system/modules_app/package-commands/ModuleConfig.cfc @@ -8,7 +8,7 @@ component { function configure() { interceptors = [ - { class="#moduleMapping#.interceptors.packageScripts" }, + { class="#moduleMapping#.interceptors.PackageScripts" }, { class="#moduleMapping#.interceptors.PackageSystemSettingExpansions" } ]; } diff --git a/src/cfml/system/modules_app/server-commands/ModuleConfig.cfc b/src/cfml/system/modules_app/server-commands/ModuleConfig.cfc index f212d78b..626b709d 100644 --- a/src/cfml/system/modules_app/server-commands/ModuleConfig.cfc +++ b/src/cfml/system/modules_app/server-commands/ModuleConfig.cfc @@ -8,6 +8,7 @@ component { function configure() { interceptors = [ + { class="#moduleMapping#.interceptors.ServerScripts" }, { class="#moduleMapping#.interceptors.ServerCommandLine" }, { class="#moduleMapping#.interceptors.ServerSystemSettingExpansions" } ]; diff --git a/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc new file mode 100644 index 00000000..a8775d8d --- /dev/null +++ b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc @@ -0,0 +1,92 @@ +/** + * Runs a server script, by name. Scripts are stored in server.json. + * . + * {code:bash} + * server run-script myScript + * {code} + * . + * Positional parameters can be passed and will be available as environment variables inside the script as ${1}, ${2}, etc + * . + * {code:bash} + * server run-script myScript param1 param2 + * {code} + * . + * Named parameters can be passed and will be available as environment variables inside the script as ${name1}, ${name2}, etc + * Note in this case, ALL parameters much be named including the scriptName param to the command. + * . + * {code:bash} + * server run-script scriptName=myScript name1=value1 name2=value2 + * {code} + **/ +component aliases="run-script" { + + property name="serverService" inject="ServerService"; + + /** + * @scriptName Name of the script to run + * @scriptName.optionsUDF scriptNameComplete + * @name.hint the short name of the server + * @name.optionsUDF serverNameComplete + * @directory.hint web root for the server + * @serverConfigFile The path to the server's JSON file. + **/ + function run( + required string scriptname, + string name, + string directory, + string serverConfigFile ){ + + if( !isNull( arguments.directory ) ) { + arguments.directory = resolvePath( arguments.directory ); + } + if( !isNull( arguments.serverConfigFile ) ) { + arguments.serverConfigFile = resolvePath( arguments.serverConfigFile ); + } + var serverDetails = serverService.resolveServerDetails( arguments ); + + // package check + if( serverDetails.serverIsNew ) { + error( "No servers found." ); + } + + // Add any additional arguments as env vars for the script to access + arguments + .filter( ( k, v ) => !'scriptName,name,directory,serverConfigFile'.listFindNoCase( k ) ) + .each( ( k, v ) => { + // Decrement positional params so they start at 1 + if( isNumeric( k ) && k > 4 ) { + k -= 4; + } + systemSettings.setSystemSetting( k, v ); + } ); + + serverService.runScript( scriptName=arguments.scriptName, ignoreMissing=false, interceptData={ serverJSON : serverDetails.serverJSON } ); + + } + + function scriptNameComplete( string paramSoFar, struct passedNamedParameters ) { + + if( !isNull( passedNamedParameters.directory ) ) { + passedNamedParameters.directory = resolvePath( passedNamedParameters.directory ); + } + if( !isNull( passedNamedParameters.serverConfigFile ) ) { + passedNamedParameters.serverConfigFile = resolvePath( passedNamedParameters.serverConfigFile ); + } + + var serverDetails = serverService.resolveServerDetails( passedNamedParameters ); + + // package check + if( !serverDetails.serverIsNew ) { + return ( serverDetails.serverJSON.scripts ?: {} ).keyArray(); + } + return []; + } + + /** + * Complete server names + */ + function serverNameComplete() { + return serverService.serverNameComplete(); + } + +} diff --git a/src/cfml/system/modules_app/server-commands/interceptors/ServerScripts.cfc b/src/cfml/system/modules_app/server-commands/interceptors/ServerScripts.cfc new file mode 100644 index 00000000..09cb818e --- /dev/null +++ b/src/cfml/system/modules_app/server-commands/interceptors/ServerScripts.cfc @@ -0,0 +1,35 @@ +/** +********************************************************************************* +* Copyright Since 2014 CommandBox by Ortus Solutions, Corp +* www.coldbox.org | www.ortussolutions.com +******************************************************************************** +* @author Brad Wood +* +* I am an interceptor that listens to all the server interception points and runs server scripts for them if they exist. +* +*/ +component { + property name="serverService" inject="ServerService"; + property name="shell" inject="shell"; + + function init() { + variables.inScript=false; + } + + function preServerStart() { processScripts( 'preServerStart', shell.pwd(), interceptData ); } + function onServerInstall() { processScripts( 'onServerInstall', interceptData.serverinfo.webroot, interceptData ); } + function onServerStart() { processScripts( 'onServerStart', interceptData.serverinfo.webroot, interceptData ); } + function onServerStop() { processScripts( 'onServerStop', interceptData.serverinfo.webroot, interceptData ); } + function preServerForget() { processScripts( 'preServerForget', interceptData.serverinfo.webroot, interceptData ); } + function postServerForget() { processScripts( 'postServerForget', interceptData.serverinfo.webroot, interceptData ); } + + function processScripts( required string interceptionPoint, string directory=shell.pwd(), interceptData={} ) { + inScript=true; + try { + serverService.runScript( arguments.interceptionPoint, arguments.directory, true, interceptData ); + } finally { + inScript=false; + } + } + +} diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index f1e2832b..4f1f026f 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -224,6 +224,8 @@ component accessors="true" singleton { 'sharedKey' : d.ModCFML.sharedKey ?: '', 'requireSharedKey' : d.ModCFML.requireSharedKey ?: true, 'createVirtualDirectories' : d.ModCFML.createVirtualDirectories ?: true + }, + 'scripts' : { } }; } @@ -2706,6 +2708,17 @@ component accessors="true" singleton { } } } ); + // Suggest server scripts + props = JSONService.addProp( props, '', '', { + 'scripts' : { + 'preServerStart' : '', + 'onServerInstall' : '', + 'onServerStart' : '', + 'onServerStop' : '', + 'preServerForget' : '', + 'postServerForget' : '' + } + } ); } if( asSet ) { props = props.map( function( i ){ return i &= '='; } ); @@ -2782,6 +2795,77 @@ component accessors="true" singleton { JSONService.mergeData( serverJSON, overrides ); } + + + + /** + * Nice wrapper to run a server script + * + * @scriptName Name of the server script to run + * @directory The web root + * @ignoreMissing Set true to ignore missing server scripts, false to throw an exception + * @interceptData An optional struct of data if this server script is being fired as part of an interceptor announcement. Will be loaded into env vars + */ + function runScript( required string scriptName, string directory=shell.pwd(), boolean ignoreMissing=true, interceptData={} ) { + if( !isNull( interceptData.serverJSON ) ){ + var serverJSON = interceptData.serverJSON; + } else if( !isNull( interceptData.serverInfo.name ) && len( interceptData.serverInfo.name ) ){ + var serverDetails = serverService.resolveServerDetails( { name=interceptData.serverInfo.name } ); + if( serverDetails.serverIsNew ) { + return; + } + var serverJSON = serverDetails.serverJSON; + systemSettings.expandDeepSystemSettings( serverJSON ); + loadOverrides( serverJSON, serverDetails.serverInfo, serverDetails.serverInfo.verbose ?: false ); + } else { + consoleLogger.warn( 'Could not find server for script [#arguments.scriptName#].' ); + return; + } + + // If there is a scripts object with a matching key for this interceptor.... + if( serverJSON.keyExists( 'scripts' ) && isStruct( serverJSON.scripts ) && serverJSON.scripts.keyExists( arguments.scriptName ) ) { + + // Skip this if we're not in a command so we don't litter the default env var namespace + if( systemSettings.getAllEnvironments().len() > 1 ) { + systemSettings.setDeepSystemSettings( interceptData ); + } + + // Run preXXX package script + runScript( 'pre#arguments.scriptName#', arguments.directory, true, interceptData ); + + var thisScript = serverJSON.scripts[ arguments.scriptName ]; + consoleLogger.debug( '.' ); + consoleLogger.warn( 'Running server script [#arguments.scriptName#].' ); + consoleLogger.debug( '> ' & thisScript ); + + // Normally the shell retains the previous exit code, but in this case + // it's important for us to know if the scripts return a failing exit code without throwing an exception + shell.setExitCode( 0 ); + + // ... 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 ); + + // If the script ran "exit" + if( !shell.getKeepRunning() ) { + // Just kidding, the shell can stay.... + shell.setKeepRunning( true ); + } + + if( shell.getExitCode() != 0 ) { + throw( message='Server script returned failing exit code (#shell.getExitCode()#)', detail='Failing script: #arguments.scriptName#', type="commandException", errorCode=shell.getExitCode() ); + } + + // Run postXXX package script + runScript( 'post#arguments.scriptName#', arguments.directory, true, interceptData ); + + } else if( !arguments.ignoreMissing ) { + consoleLogger.error( 'The script [#arguments.scriptName#] does not exist in this server.' ); + } + } + } From 9dbc6d2e5840a71997d100d0f28f3a7aa9aa027d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 15:54:20 -0600 Subject: [PATCH 035/118] force windowes case --- .../interceptors/{packageScripts.cfc => _PackageScripts.cfc} | 0 .../{serverCommandLine.cfc => _ServerCommandLine.cfc} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/cfml/system/modules_app/package-commands/interceptors/{packageScripts.cfc => _PackageScripts.cfc} (100%) rename src/cfml/system/modules_app/server-commands/interceptors/{serverCommandLine.cfc => _ServerCommandLine.cfc} (100%) diff --git a/src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc b/src/cfml/system/modules_app/package-commands/interceptors/_PackageScripts.cfc similarity index 100% rename from src/cfml/system/modules_app/package-commands/interceptors/packageScripts.cfc rename to src/cfml/system/modules_app/package-commands/interceptors/_PackageScripts.cfc diff --git a/src/cfml/system/modules_app/server-commands/interceptors/serverCommandLine.cfc b/src/cfml/system/modules_app/server-commands/interceptors/_ServerCommandLine.cfc similarity index 100% rename from src/cfml/system/modules_app/server-commands/interceptors/serverCommandLine.cfc rename to src/cfml/system/modules_app/server-commands/interceptors/_ServerCommandLine.cfc From 1b9ebdcc4c2c959d12abf857bf928c41190c0654 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 15:54:58 -0600 Subject: [PATCH 036/118] force case 2 --- src/cfml/system/endpoints/ForgeBox.cfc | 17 ++++++----------- .../{_PackageScripts.cfc => PackageScripts.cfc} | 0 ...verCommandLine.cfc => ServerCommandLine.cfc} | 0 3 files changed, 6 insertions(+), 11 deletions(-) rename src/cfml/system/modules_app/package-commands/interceptors/{_PackageScripts.cfc => PackageScripts.cfc} (100%) rename src/cfml/system/modules_app/server-commands/interceptors/{_ServerCommandLine.cfc => ServerCommandLine.cfc} (100%) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 18eaf523..9fe46fd8 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -616,17 +616,12 @@ component accessors="true" implements="IEndpointInteractive" { directoryDelete( tmpPath, true ); } directoryCreate( tmpPath ); - directoryCopy( arguments.path, tmpPath, true, function( directoryPath ){ - // This will normalize the slashes to match - directoryPath = fileSystemUtil.resolvePath( directoryPath ); - - // cleanup path so we just get from the archive down - var thisPath = replacenocase( directoryPath, path, "" ); - // Ignore paths that match one of our ignore patterns - var ignored = pathPatternMatcher.matchPatterns( ignorePatterns, thisPath ); - // What do we do with this file/directory - return ! ignored; - }); + wirebox.getInstance( 'globber' ) + .inDirectory( arguments.path ) + .setExcludePattern( ignorePatterns ) + .loose() + .copyTo( tmpPath ); + var zipFileName = tmpPath & ".zip"; cfzip( action = "zip", diff --git a/src/cfml/system/modules_app/package-commands/interceptors/_PackageScripts.cfc b/src/cfml/system/modules_app/package-commands/interceptors/PackageScripts.cfc similarity index 100% rename from src/cfml/system/modules_app/package-commands/interceptors/_PackageScripts.cfc rename to src/cfml/system/modules_app/package-commands/interceptors/PackageScripts.cfc diff --git a/src/cfml/system/modules_app/server-commands/interceptors/_ServerCommandLine.cfc b/src/cfml/system/modules_app/server-commands/interceptors/ServerCommandLine.cfc similarity index 100% rename from src/cfml/system/modules_app/server-commands/interceptors/_ServerCommandLine.cfc rename to src/cfml/system/modules_app/server-commands/interceptors/ServerCommandLine.cfc From 6b897302e262d1b3302909ddba248b910999eb62 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 16:16:29 -0600 Subject: [PATCH 037/118] COMMANDBOX-1404 --- .../commands/server/run-script.cfc | 6 +++--- src/cfml/system/services/ServerService.cfc | 21 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc index a8775d8d..7554422b 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc @@ -74,12 +74,12 @@ component aliases="run-script" { } var serverDetails = serverService.resolveServerDetails( passedNamedParameters ); - + var results = []; // package check if( !serverDetails.serverIsNew ) { - return ( serverDetails.serverJSON.scripts ?: {} ).keyArray(); + results = ( serverDetails.serverJSON.scripts ?: {} ).keyArray(); } - return []; + return ( serverService.getDefaultServerJSON().scripts ?: {} ).keyArray().append( results, true ); } /** diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 4f1f026f..0775f0e3 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -136,7 +136,8 @@ component accessors="true" singleton { 'minHeapSize' : d.jvm.minHeapSize ?: '', 'args' : d.jvm.args ?: '', 'javaHome' : d.jvm.javaHome ?: '', - 'javaVersion' : d.jvm.javaVersion ?: '' + 'javaVersion' : d.jvm.javaVersion ?: '', + 'properties' : d.jvm.javaVersion ?: '' }, 'web' : { 'host' : d.web.host ?: '127.0.0.1', @@ -225,8 +226,7 @@ component accessors="true" singleton { 'requireSharedKey' : d.ModCFML.requireSharedKey ?: true, 'createVirtualDirectories' : d.ModCFML.createVirtualDirectories ?: true }, - 'scripts' : { - } + 'scripts' : d.scripts ?: {} }; } @@ -2821,9 +2821,18 @@ component accessors="true" singleton { consoleLogger.warn( 'Could not find server for script [#arguments.scriptName#].' ); return; } - + var serverJSONScripts = duplicate( serverJSON.scripts ?: {} ); + getDefaultServerJSON().scripts.each( (k,v)=>{ + // Append existing scripts + if( serverJSONScripts.keyExists( k ) ) { + serverJSONScripts[ k ] &= '; ' & v + // Merge missing ones + } else { + serverJSONScripts[ k ] = v; + } + } ); // If there is a scripts object with a matching key for this interceptor.... - if( serverJSON.keyExists( 'scripts' ) && isStruct( serverJSON.scripts ) && serverJSON.scripts.keyExists( arguments.scriptName ) ) { + if( serverJSONScripts.keyExists( arguments.scriptName ) ) { // Skip this if we're not in a command so we don't litter the default env var namespace if( systemSettings.getAllEnvironments().len() > 1 ) { @@ -2833,7 +2842,7 @@ component accessors="true" singleton { // Run preXXX package script runScript( 'pre#arguments.scriptName#', arguments.directory, true, interceptData ); - var thisScript = serverJSON.scripts[ arguments.scriptName ]; + var thisScript = serverJSONScripts[ arguments.scriptName ]; consoleLogger.debug( '.' ); consoleLogger.warn( 'Running server script [#arguments.scriptName#].' ); consoleLogger.debug( '> ' & thisScript ); From 449e88aec8a69b23616e93d7891b88d2879fa645 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 16:25:51 -0600 Subject: [PATCH 038/118] COMMANDBOX-1394 --- src/cfml/system/services/ServerService.cfc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 0775f0e3..23cd13b0 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -137,7 +137,7 @@ component accessors="true" singleton { 'args' : d.jvm.args ?: '', 'javaHome' : d.jvm.javaHome ?: '', 'javaVersion' : d.jvm.javaVersion ?: '', - 'properties' : d.jvm.javaVersion ?: '' + 'properties' : d.jvm.properties ?: {} }, 'web' : { 'host' : d.web.host ?: '127.0.0.1', @@ -842,6 +842,9 @@ component accessors="true" singleton { // Server startup timeout serverInfo.startTimeout = serverProps.startTimeout ?: serverJSON.startTimeout ?: defaults.startTimeout; + + serverInfo.JVMProperties = serverJSON.JVM.properties ?: {}; + serverInfo.JVMProperties.append( defaults.jvm.properties, false ); // relative lib dirs in server.json are resolved relative to the server.json if( serverJSON.keyExists( 'app' ) && serverJSON.app.keyExists( 'libDirs' ) ) { @@ -1315,6 +1318,8 @@ component accessors="true" singleton { argTokens.append( '-Xms#serverInfo.minHeapSize#' ); } + serverInfo.JVMProperties.each( (k,v)=>argTokens.append( '-D#k#=#v#' ) ); + // Add java agent if( len( trim( javaAgent ) ) ) { argTokens.append( javaagent ); } From 951265a643b2c18ca952b28c584a6cbb6e7e5f75 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 23 Dec 2021 17:05:38 -0600 Subject: [PATCH 039/118] COMMANDBOX-1395 --- src/cfml/system/services/ServerService.cfc | 33 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 23cd13b0..d9f901a6 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -826,13 +826,37 @@ component accessors="true" singleton { serverInfo.rewriteslogEnable = serverJSON.web.rewrites.logEnable ?: defaults.web.rewrites.logEnable; // Global defaults 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; + serverInfo.JVMargsArray = []; + serverInfo.JVMargs = serverProps.JVMargs ?: ''; + if( !isNull( serverJSON.JVM.args ) && isArray( serverJSON.JVM.args ) ) { + serverInfo.JVMargsArray.append( serverJSON.JVM.args, true ); + } else if( !isNull( serverJSON.JVM.args ) && isSimpleValue( serverJSON.JVM.args ) && len( serverJSON.JVM.args ) ) { + serverInfo.JVMargs &= ' ' & serverJSON.JVM.args; + } + if( !isNull( defaults.JVM.args ) && isArray( defaults.JVM.args ) ) { + serverInfo.JVMargsArray.append( defaults.JVM.args, true ); + } else if( !isNull( defaults.JVM.args ) && isSimpleValue( defaults.JVM.args ) && len( defaults.JVM.args ) ) { + serverInfo.JVMargs &= ' ' & defaults.JVM.args; + } + // Global defaults are always added on top of whatever is specified by the user or server.json serverInfo.runwarJarPath = serverProps.runwarJarPath ?: serverJSON.runwar.jarPath ?: defaults.runwar.jarPath; // Global defaults 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; + serverInfo.runwarArgsArray = []; + serverInfo.runwarArgs = serverProps.runwarArgs ?: ''; + if( !isNull( serverJSON.runwar.args ) && isArray( serverJSON.runwar.args ) ) { + serverInfo.runwarArgsArray.append( serverJSON.runwar.args, true ); + } else if( !isNull( serverJSON.runwar.args ) && isSimpleValue( serverJSON.runwar.args ) && len( serverJSON.runwar.args ) ) { + serverInfo.runwarArgs &= ' ' & serverJSON.runwar.args; + } + if( !isNull( defaults.runwar.args ) && isArray( defaults.runwar.args ) ) { + serverInfo.runwarArgsArray.append( defaults.runwar.args, true ); + } else if( !isNull( defaults.runwar.args ) && isSimpleValue( defaults.runwar.args ) && len( defaults.runwar.args ) ) { + serverInfo.runwarArgs &= ' ' & defaults.runwar.args; + } + // Global defaults are always added on top of whatever is specified by the user or server.json serverInfo.runwarXNIOOptions = ( serverJSON.runwar.XNIOOptions ?: {} ).append( defaults.runwar.XNIOOptions, true ); @@ -1303,6 +1327,7 @@ component accessors="true" singleton { return parser.replaceEscapedChars( parser.removeEscapedChars( parser.unwrapQuotes( i ) ) ); }); + argTokens.append( serverInfo.JVMargsArray, true ); // Add in max heap size if( len( serverInfo.heapSize ) ) { @@ -1350,6 +1375,8 @@ component accessors="true" singleton { return parser.replaceEscapedChars( parser.removeEscapedChars( parser.unwrapQuotes( i ) ) ); }), true ); + args.append( serverInfo.runwarArgsArray, true ); + if( serverInfo.trayEnable ) { args .append( '--tray-icon' ).append( serverInfo.trayIcon ) @@ -2620,7 +2647,9 @@ component accessors="true" singleton { 'javaVersion' : '', 'directoryBrowsing' : false, 'JVMargs' : "", + 'JVMargsArray' : [], 'runwarArgs' : "", + 'runwarArgsArray' : [], 'runwarXNIOOptions' : {}, 'runwarUndertowOptions' : {}, 'cfengine' : "", From 1ac84eee46da51022195a28082788f4eed026122 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 27 Dec 2021 14:44:11 -0600 Subject: [PATCH 040/118] Remove alias to avoid collision --- .../modules_app/server-commands/commands/server/run-script.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc index 7554422b..50c0bc55 100644 --- a/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc +++ b/src/cfml/system/modules_app/server-commands/commands/server/run-script.cfc @@ -18,7 +18,7 @@ * server run-script scriptName=myScript name1=value1 name2=value2 * {code} **/ -component aliases="run-script" { +component { property name="serverService" inject="ServerService"; From 2d7163aae3bf535bd679617757822bec559d57c1 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 28 Dec 2021 18:40:57 -0600 Subject: [PATCH 041/118] Typo as this code is inside the service --- 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 d9f901a6..f1530088 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -2844,7 +2844,7 @@ component accessors="true" singleton { if( !isNull( interceptData.serverJSON ) ){ var serverJSON = interceptData.serverJSON; } else if( !isNull( interceptData.serverInfo.name ) && len( interceptData.serverInfo.name ) ){ - var serverDetails = serverService.resolveServerDetails( { name=interceptData.serverInfo.name } ); + var serverDetails = resolveServerDetails( { name=interceptData.serverInfo.name } ); if( serverDetails.serverIsNew ) { return; } From 0d27acca5d47315470707b1e4d294fe4977efe05 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 28 Dec 2021 18:52:49 -0600 Subject: [PATCH 042/118] Bump runwar --- build/build.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build.properties b/build/build.properties index a3814207..f024594e 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,14 +12,14 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.8.206 cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.8 +cfml.loader.version=2.6.9 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org lucee.config.version=5.2.4.37 jre.version=jdk-11.0.12+7 launch4j.version=3.14 -runwar.version=4.6.2-SNAPSHOT +runwar.version=4.7.0-SNAPSHOT jline.version=3.19.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r From 9eae2ae2c9e89fab48e4e599fa7cb765831c25bf Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Sun, 2 Jan 2022 23:59:11 -0600 Subject: [PATCH 043/118] COMMANDBOX-1326 --- src/cfml/system/services/ServerService.cfc | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index f1530088..6fd0cee8 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -188,6 +188,11 @@ component accessors="true" singleton { 'enable' : d.web.basicAuth.enable ?: true, 'users' : d.web.basicAuth.users ?: {} }, + 'fileCache' : { + 'enable' : d.web.fileCache.enable ?: '', + 'totalSizeMB' : d.web.fileCache.totalSizeMB ?: 50, + 'maxFileSizeKB' : d.web.fileCache.maxFileSizeKB ?: 50 + }, 'rules' : duplicate( d.web.rules ?: [] ), 'rulesFile' : duplicate( d.web.rulesFile ?: [] ), 'blockCFAdmin' : d.web.blockCFAdmin ?: '', @@ -650,6 +655,19 @@ component accessors="true" singleton { } serverInfo.directoryBrowsing = serverProps.directoryBrowsing ?: serverJSON.web.directoryBrowsing ?: defaults.web.directoryBrowsing; + // If there isn't a default for this already + if( !isBoolean( defaults.web.fileCache.enable ) ) { + if( serverInfo.profile == 'production' ) { + defaults.web.fileCache.enable = true; + } else { + defaults.web.fileCache.enable = false; + } + } + + serverInfo.fileCacheEnable = serverJSON.web.fileCache.enable ?: defaults.web.fileCache.enable; + serverInfo.fileCacheTotalSizeMB = serverJSON.web.fileCache.totalSizeMB ?: defaults.web.fileCache.totalSizeMB; + serverInfo.fileCacheMaxFileSizeKB = serverJSON.web.fileCache.maxFileSizeKB ?: defaults.web.fileCache.maxFileSizeKB; + job.start( 'Setting Server Profile to [#serverInfo.profile#]' ); job.addLog( 'Profile set from #profileReason#' ); if( serverInfo.blockCFAdmin == 'external' ) { @@ -665,6 +683,7 @@ component accessors="true" singleton { job.addLog( 'Allowed Extensions: [#serverInfo.allowedExt#]' ); } job[ 'add#( !serverInfo.directoryBrowsing ? 'Success' : 'Error' )#Log' ]( 'Directory Browsing #( serverInfo.directoryBrowsing ? 'en' : 'dis' )#abled' ); + job[ 'add#( serverInfo.fileCacheEnable ? 'Success' : '' )#Log' ]( 'File Caching #( serverInfo.fileCacheEnable ? 'en' : 'dis' )#abled' ); job.complete( serverInfo.verbose ); // Double check that the port in the user params or server.json isn't in use @@ -738,7 +757,7 @@ component accessors="true" singleton { serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; serverInfo.maxRequests = serverJSON.web.maxRequests ?: defaults.web.maxRequests; - + serverInfo.trayEnable = serverProps.trayEnable ?: serverJSON.trayEnable ?: defaults.trayEnable; serverInfo.dockEnable = serverJSON.dockEnable ?: defaults.dockEnable; serverInfo.defaultBaseURL = serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#'; @@ -1449,7 +1468,11 @@ component accessors="true" singleton { if( len( CLIAliases ) ) { args.append( '--dirs' ).append( CLIAliases ); } - + if( serverInfo.fileCacheEnable ) { + args.append( '--cache-servlet-paths' ).append( true ); + args.append( '--file-cache-total-size-mb' ).append( val( serverInfo.fileCacheTotalSizeMB ) ); + args.append( '--file-cache-max-file-size-kb' ).append( val( serverInfo.fileCacheMaxFileSizeKB ) ); + } // If background, wrap up JVM args to pass through to background servers. "Real" JVM args must come before Runwar args if( background ) { From a73e823344a59bebc3430b649e46a009f99eb0c7 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 5 Jan 2022 15:35:27 -0600 Subject: [PATCH 044/118] COMMANDBOX-1420 --- src/cfml/system/services/ServerService.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 6fd0cee8..76ccdce9 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -985,7 +985,7 @@ component accessors="true" singleton { // track and trace verbs can leak data in XSS attacks "disallowed-methods( methods={trace,track} )", // Common config files and sensitive paths that should never be accessed, even on development - "regex( pattern='.*/(box.json|server.json|web.config|urlrewrite.xml|package.json|package-lock.json|Gulpfile.js)', case-sensitive=false ) -> { set-error(404); done }", + "regex( pattern='.*/(box\.json|server\.json|web\.config|urlrewrite\.xml|package\.json|package-lock\.json|Gulpfile\.js)', case-sensitive=false ) -> { set-error(404); done }", // Any file or folder starting with a period "regex('/\.') -> { set-error( 404 ); done }", // Additional serlvlet mappings in Adobe CF's web.xml @@ -997,7 +997,7 @@ component accessors="true" singleton { if( serverInfo.profile == 'production' ) { serverInfo.webRules.append( [ // Common config files and sensitive paths in ACF and TestBox that may be ok for dev, but not for production - "regex( pattern='.*/(CFIDE/multiservermonitor-access-policy.xml|CFIDE/probe.cfm|CFIDE/main/ide.cfm|tests/runner.cfm|testbox/system/runners/HTMLRunner.cfm)', case-sensitive=false ) -> { set-error(404); done }", + "regex( pattern='.*/(CFIDE/multiservermonitor-access-policy\.xml|CFIDE/probe\.cfm|CFIDE/main/ide\.cfm|tests/runner\.cfm|testbox/system/runners/HTMLRunner\.cfm)', case-sensitive=false ) -> { set-error(404); done }", ], true ); } @@ -1486,7 +1486,7 @@ component accessors="true" singleton { } // If foreground, just stick them in. } else { - argTokens.each( function(i) { args.prepend( i ); } ); + argTokens.reverse().each( function(i) { args.prepend( i ); } ); } // Webroot for normal server, and war home for a standard war From 52735fcd71e6cc59082c651f98eb12351870457d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 11 Jan 2022 18:05:23 -0600 Subject: [PATCH 045/118] COMMANDBOX-1415 --- build/build.properties | 4 ++-- src/cfml/system/util/AnsiFormatter.cfc | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build/build.properties b/build/build.properties index f024594e..bc71f400 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,14 +12,14 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.8.206 cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.9 +cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org lucee.config.version=5.2.4.37 jre.version=jdk-11.0.12+7 launch4j.version=3.14 -runwar.version=4.7.0-SNAPSHOT +runwar.version=4.7.1-SNAPSHOT jline.version=3.19.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r diff --git a/src/cfml/system/util/AnsiFormatter.cfc b/src/cfml/system/util/AnsiFormatter.cfc index ed709832..ce87f156 100644 --- a/src/cfml/system/util/AnsiFormatter.cfc +++ b/src/cfml/system/util/AnsiFormatter.cfc @@ -33,6 +33,14 @@ component accessors=true { // [TRACE] io.undertow.predicate: Path(s) [/CFIDE/main/ide.cfm] MATCH input [/CFIDE/main/ide.cfm] for HttpServerExchange{ GET /CFIDE/main/ide.cfm}. line = reReplaceNoCase( line, '^(\[[^]]*])( io\.undertow\.request\.dump: )(.*)', 'Request Dump: \3' ); + // Log messages from Tuckey Rewrite engine "Rewrite UrlRewriter:" + // Ex: + // [DEBUG] org.tuckey.web.filters.urlrewrite.UrlRewriter: processing request for /services/training + // [DEBUG] org.tuckey.web.filters.urlrewrite.RuleExecutionOutput: needs to be forwarded to /index.cfm/services/training + line = reReplaceNoCase( line, '^(\[[^]]*])( org\.tuckey\.web\.filters\.urlrewrite\.UrlRewriter: )(.*)', '\1 Rewrite: \3' ); + line = reReplaceNoCase( line, '^(\[[^]]*])( org\.tuckey\.web\.filters\.urlrewrite\.RuleExecutionOutput: )(.*)', '\1 Rewrite Output: \3' ); + line = reReplaceNoCase( line, '^(\[[^]]*])( org\.tuckey\.web\.filters\.urlrewrite\.+)([^:]*: )(.*)', '\1 Rewrite \3\4' ); + // Strip off redundant severities that come from wrapping LogBox appenders in Log4j appenders // [INFO ] DEBUG my.logger.name This rain in spain stays mainly in the plains line = reReplaceNoCase( line, '^(\[(INFO |ERROR|DEBUG|WARN )] )(INFO|ERROR|DEBUG|WARN)( .*)', '[\3]\4' ); From 09b9742e5faf6f83a8743e951b100424eac69c81 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Thu, 13 Jan 2022 15:00:18 +0100 Subject: [PATCH 046/118] Create FUNDING.YML --- .github/FUNDING.YML | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.YML diff --git a/.github/FUNDING.YML b/.github/FUNDING.YML new file mode 100644 index 00000000..7e59d133 --- /dev/null +++ b/.github/FUNDING.YML @@ -0,0 +1 @@ +patreon: ortussolutions From 53eb351dabfe76e91f60c0ade588632464f8b68c Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 20 Jan 2022 16:30:30 -0600 Subject: [PATCH 047/118] COMMANDBOX-1421 --- .../package-commands/commands/package/outdated.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ddf70cfd..09f84b71 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 @@ -95,13 +95,13 @@ component aliases="outdated" { print.line() .green( 'Found ' ) .boldGreen( '(#aOutdatedDependencies.len()#)' ) - .green( ' Outdated Dependenc#( aOutdatedDependencies.len() == 1 ? 'y' : 'ies' )# ' ) + .green( ' Outdated #( system ? ' system' : '' )#Dependenc#( aOutdatedDependencies.len() == 1 ? 'y' : 'ies' )# ' ) .line(); printDependencies( data=aOutdatedDependencies, verbose=arguments.verbose ); print .line() - .cyanLine( "Run the 'update' command to update all the outdated dependencies to their latest version." ) - .cyanLine( "Or use 'update {slug}' to update a specific dependency" ); + .cyanLine( "Run the 'update#( system ? ' --system' : '' )#' command to update all the outdated dependencies to their latest version." ) + .cyanLine( "Or use 'update {slug}#( system ? ' --system' : '' )#' to update a specific dependency" ); } else { print.blueLine( 'There are no outdated dependencies!' ); } From cc47615a06405ca2423bb347efc67070333af90b Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 27 Jan 2022 09:28:21 -0600 Subject: [PATCH 048/118] COMMANDBOX-1423 --- src/cfml/system/services/ServerService.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 76ccdce9..8aa6fae4 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -986,8 +986,8 @@ component accessors="true" singleton { "disallowed-methods( methods={trace,track} )", // Common config files and sensitive paths that should never be accessed, even on development "regex( pattern='.*/(box\.json|server\.json|web\.config|urlrewrite\.xml|package\.json|package-lock\.json|Gulpfile\.js)', case-sensitive=false ) -> { set-error(404); done }", - // Any file or folder starting with a period - "regex('/\.') -> { set-error( 404 ); done }", + // Any file or folder starting with a period, unless it's called + "regex('/\.') and not path-prefix(.well-known) -> { set-error( 404 ); done }", // Additional serlvlet mappings in Adobe CF's web.xml "path-prefix( { '/JSDebugServlet','/securityanalyzer','/WSRPProducer' } ) -> { set-error( 404 ); done }", // java web service (Axis) files From 605501099ecf7814814f3169f8431c74f1f91201 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 27 Jan 2022 11:58:35 -0600 Subject: [PATCH 049/118] COMMANDBOX-1424 --- src/cfml/system/services/ServerService.cfc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 8aa6fae4..f5dd0c9b 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -198,7 +198,8 @@ component accessors="true" singleton { 'blockCFAdmin' : d.web.blockCFAdmin ?: '', 'blockSensitivePaths' : d.web.blockSensitivePaths ?: '', 'blockFlashRemoting' : d.web.blockFlashRemoting ?: '', - 'allowedExt' : d.web.allowedExt ?: '' + 'allowedExt' : d.web.allowedExt ?: '', + 'useProxyForwardedIP' : d.web.useProxyForwardedIP ?: false }, 'app' : { 'logDir' : d.app.logDir ?: '', @@ -638,10 +639,12 @@ component accessors="true" singleton { } } - serverInfo.blockCFAdmin = serverProps.blockCFAdmin ?: serverJSON.web.blockCFAdmin ?: defaults.web.blockCFAdmin; + serverInfo.blockCFAdmin = serverProps.blockCFAdmin ?: serverJSON.web.blockCFAdmin ?: defaults.web.blockCFAdmin; serverInfo.blockSensitivePaths = serverJSON.web.blockSensitivePaths ?: defaults.web.blockSensitivePaths; serverInfo.blockFlashRemoting = serverJSON.web.blockFlashRemoting ?: defaults.web.blockFlashRemoting; - serverInfo.allowedExt = serverJSON.web.allowedExt ?: defaults.web.allowedExt; + serverInfo.allowedExt = serverJSON.web.allowedExt ?: defaults.web.allowedExt; + serverInfo.useProxyForwardedIP = serverJSON.web.useProxyForwardedIP ?: defaults.web.useProxyForwardedIP; + // If there isn't a default for this already if( !isBoolean( defaults.web.directoryBrowsing ) ) { @@ -1379,7 +1382,7 @@ component accessors="true" singleton { .append( '--dock-enable' ).append( serverInfo.dockEnable ) .append( '--directoryindex' ).append( serverInfo.directoryBrowsing ) .append( '--timeout' ).append( serverInfo.startTimeout ) - .append( '--proxy-peeraddress' ).append( 'true' ) + .append( '--proxy-peeraddress' ).append( serverInfo.useProxyForwardedIP ) .append( '--cookie-secure' ).append( serverInfo.sessionCookieSecure ) .append( '--cookie-httponly' ).append( serverInfo.sessionCookieHTTPOnly ) .append( '--pid-file').append( serverInfo.pidfile ); From 10769bdc7fb06eb8bf512427e7bef4d37bf31c8a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 28 Jan 2022 11:55:41 -0600 Subject: [PATCH 050/118] COMMANDBOX-1425 --- 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 bc71f400..542d5bf3 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.8.206 +cfml.version=5.3.9.61-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} diff --git a/build/build.xml b/build/build.xml index 47ff10b5..5807b78e 100644 --- a/build/build.xml +++ b/build/build.xml @@ -1077,7 +1077,7 @@ External Dependencies: - + From 50201ba1516198aa26fb390ab805aa4c2836db18 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 31 Jan 2022 15:14:29 -0600 Subject: [PATCH 051/118] New Lucee snapshot --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 542d5bf3..06f8a7c4 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.61-SNAPSHOT +cfml.version=5.3.9.62-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} From f121fffebfd08517b5f4ac9a94c99358975e7432 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 31 Jan 2022 15:29:23 -0600 Subject: [PATCH 052/118] Bump bundled JRE --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 06f8a7c4..69a58082 100644 --- a/build/build.properties +++ b/build/build.properties @@ -17,7 +17,7 @@ cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org lucee.config.version=5.2.4.37 -jre.version=jdk-11.0.12+7 +jre.version=jdk-11.0.14+9 launch4j.version=3.14 runwar.version=4.7.1-SNAPSHOT jline.version=3.19.0 From 860c4120fb70437680099e4b2b66311c2dad9b26 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 1 Feb 2022 13:01:45 -0600 Subject: [PATCH 053/118] Last log4j removal --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 69a58082..f222762b 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.62-SNAPSHOT +cfml.version=5.3.9.65-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} From 51180e3f5f6ed0e86c5b5e5636e9cf39002f41cc Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 2 Feb 2022 13:31:58 -0600 Subject: [PATCH 054/118] WILL IT BUILD? --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index f222762b..c851c707 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.65-SNAPSHOT +cfml.version=5.3.9.66-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} From 16a7a17d25d6df1538e46d6c17e01f883dd6256f Mon Sep 17 00:00:00 2001 From: Scott Steinbeck Date: Thu, 3 Feb 2022 09:40:46 -0800 Subject: [PATCH 055/118] Server Service changes (#305) * Add stop --local to commandbox, similar to list command * change logic for detecting if server is running, switch to PID check with cleanup task for any invalid PID files found in stopped server directories * remove debugging * remove debugging and cleaned up logic * updated wizard process for creating a coldbox app --- .../commands/coldbox/create/app-wizard.cfc | 69 +++++++++- .../server-commands/commands/server/stop.cfc | 11 +- src/cfml/system/services/ServerService.cfc | 125 ++++++++++-------- src/cfml/system/util/MultiSelect.cfc | 12 +- 4 files changed, 151 insertions(+), 66 deletions(-) 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 1ebc5760..eb26b6aa 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 @@ -6,19 +6,78 @@ component extends="app" aliases="" { /** * @name The name of the app you want to create * @skeleton The application skeleton you want to use (AdvancedScript, rest, rest-hmvc, Simple, SuperSimple) - * @skeleton.optionsUDF skeletonComplete - * @init Init this as a CommandBox Package + * @init Init this as a package **/ function run( required name, - required skeleton, - required boolean init + skeleton ){ + + arguments.directory = getCWD(); + if( !confirm( 'Are you currently inside the "/#name#" folder (if "No" we will create it)? [y/n]' ) ) { + arguments.directory = getCWD() & name & '/'; + if ( !directoryExists( arguments.directory ) ) { + directoryCreate( arguments.directory ); + } + shell.cd(arguments.directory); + } + + print.boldgreenline( '------------------------------------------------------------------------------------------' ); + print.boldgreenline("Files will be installed in the " & arguments.directory & " directory" ); + print.boldgreenline( '------------------------------------------------------------------------------------------' ); + + if( confirm( 'Are you creating an API? [y/n]' ) ) { + print.boldgreenline( '------------------------------------------------------------------------------------------' ); + print.boldgreenline( 'We have 2 different API template options' ); + print.boldgreenline( 'Both include the modules: cbsecurity, cbvalidation, mementifier, relax, & route-visualizer' ); + print.boldgreenline( '------------------------------------------------------------------------------------------'); + + arguments.skeleton = multiselect( 'Which template would you like to use?' ) + .options( [ + {accessKey=1, display='Modular (API/REST) Template - provide an "api" module with a "v1" sub-module within it', value='cbtemplate-rest-hmvc', selected=true }, + {accessKey=2, display='Simple (API/REST) Template - proivdes api endpoints via the handlers/ folder', value='cbtemplate-rest' }, + ] ) + .required() + .ask(); + + } else { + print.boldgreenline( '------------------------------------------------------------------------------------------',true); + print.greenline( 'We have a few different Non-API template options' ); + print.greenline( 'No default modules are installed for these templates' ); + print.boldgreenline( '------------------------------------------------------------------------------------------'); + + arguments.skeleton = multiselect( 'Which template would you like to use?') + .options( [ + {accessKey=1, value="cbtemplate-simple", display="Simple Script - Script based Coldbox App WITHOUT cfconfig & .env settings"}, + {accessKey=2, value="cbtemplate-advanced-script", display="Advanced Script - Script based Coldbox App which uses cfconfig & .env settings", selected=true}, + {accessKey=3, value="cbtemplate-elixir", display="Elixir Template - Advanced Script + ColdBox Elixir: Enable Webpack tasks for your ColdBox applications"}, + {accessKey=4, value="cbtemplate-elixir-vuejs", display="Elixir + Vuejs Template - Elixir Template + pre-installed & configured VueJS"}, + ] ) + .required() + .ask(); + + if(arguments.skeleton != 'cbtemplate-simple'){ + print.boldgreenline( ''); + print.boldgreenline( 'This Coldbox Template uses cfconfig & .env "dotenv" ' ); + print.boldgreenline( '----------------------------------------------------------------------------------------'); + print.boldgreenline( 'CFConfig is a module that creates a local settings file' ); + print.greenline( 'in your project directory of all of the ColdFusion Admin Settings' ); + print.greenline( 'Check out more details in the docs: https://cfconfig.ortusbooks.com/' ); + print.boldgreenline( '----------------------------------------------------------------------------------------'); + print.boldgreenline( '.env is a module that creates a local variables that can be' ); + print.greenline( 'used in many places such as .cfconfig.json, box.json, Coldbox.cfc, etc.' ); + print.greenline( 'You will see these used in the template in some of the files above' ); + print.greenline( 'ex. "${DB_DATABASE}" or getSystemSetting( "APPNAME", "Your app name here" )' ); + print.greenline( 'More info at https://github.com/commandbox-modules/commandbox-dotenv' ); + print.boldgreenline( '----------------------------------------------------------------------------------------'); + } + } + print.line('Creating your site...').toConsole(); + var skeletons = skeletonComplete(); // turn off wizard arguments.wizard = false; arguments.initWizard = true; - arguments.directory = getCWD(); if ( !arguments.skeleton.len() ) { // Remove if empty so it can default correctly 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 2064898e..ce2d0f88 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 @@ -21,6 +21,7 @@ component aliases="stop" { * @forget Remove the directory information from disk * @all Stop ALL running servers * @verbose Show raw output of stop command + * @local Stop servers with webroot matching the current directory **/ function run( string name, @@ -28,11 +29,15 @@ component aliases="stop" { String serverConfigFile, boolean forget=false, boolean all=false, - boolean verbose=false ){ - - + boolean verbose=false, + boolean local=false + ){ if( arguments.all ) { var servers = serverService.getServers(); + } else if (arguments.local) { + var servers = serverService.getServers().filter( ( serverName, thisServerInfo ) => { + return getCanonicalPath( getCWD() ) == getCanonicalPath( thisServerInfo.webroot ); + }, true ); } else { if( !isNull( arguments.directory ) ) { diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index f5dd0c9b..af6ff448 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -3,7 +3,7 @@ * Copyright Since 2014 CommandBox by Ortus Solutions, Corp * www.coldbox.org | www.ortussolutions.com ******************************************************************************** -* @author Brad Wood, Luis Majano, Denny Valliant +* @author Brad Wood, Luis Majano, Denny Valliant, Scott Steinbeck * * I manage servers * @@ -304,15 +304,15 @@ component accessors="true" singleton { var serverJSON = serverDetails.serverJSON; var serverJSONToSave = duplicate( serverJSON ); var serverInfo = serverDetails.serverinfo; - + systemSettings.expandDeepSystemSettings( serverJSON ); systemSettings.expandDeepSystemSettings( defaults ); // Mix in environment variable overrides like BOX_SERVER_PROFILE loadOverrides( serverJSON, serverInfo, serverProps.verbose ?: serverJSON.verbose ?: defaults.verbose ?: false ); - + // Load up our fully-realized server.json-specific env vars into CommandBox's environment systemSettings.setDeepSystemSettings( serverDetails.serverJSON.env ?: {}, '' ); - + interceptorService.announceInterception( 'preServerStart', { serverDetails=serverDetails, serverProps=serverProps, serverInfo=serverDetails.serverInfo, serverJSON=serverDetails.serverJSON, defaults=defaults } ); // In case the interceptor changed them @@ -607,7 +607,7 @@ component accessors="true" singleton { if( serverInfo.envVarHasProfile ?: false ) { profileReason = 'profile property in in "box_server_profile" env var'; } else { - profileReason = 'profile property in server.json'; + profileReason = 'profile property in server.json'; } } if( !isNull( serverProps.profile ) ) { @@ -644,7 +644,7 @@ component accessors="true" singleton { serverInfo.blockFlashRemoting = serverJSON.web.blockFlashRemoting ?: defaults.web.blockFlashRemoting; serverInfo.allowedExt = serverJSON.web.allowedExt ?: defaults.web.allowedExt; serverInfo.useProxyForwardedIP = serverJSON.web.useProxyForwardedIP ?: defaults.web.useProxyForwardedIP; - + // If there isn't a default for this already if( !isBoolean( defaults.web.directoryBrowsing ) ) { @@ -666,7 +666,7 @@ component accessors="true" singleton { defaults.web.fileCache.enable = false; } } - + serverInfo.fileCacheEnable = serverJSON.web.fileCache.enable ?: defaults.web.fileCache.enable; serverInfo.fileCacheTotalSizeMB = serverJSON.web.fileCache.totalSizeMB ?: defaults.web.fileCache.totalSizeMB; serverInfo.fileCacheMaxFileSizeKB = serverJSON.web.fileCache.maxFileSizeKB ?: defaults.web.fileCache.maxFileSizeKB; @@ -760,7 +760,7 @@ component accessors="true" singleton { serverInfo.basicAuthUsers = serverJSON.web.basicAuth.users ?: defaults.web.basicAuth.users; serverInfo.welcomeFiles = serverProps.welcomeFiles ?: serverJSON.web.welcomeFiles ?: defaults.web.welcomeFiles; serverInfo.maxRequests = serverJSON.web.maxRequests ?: defaults.web.maxRequests; - + serverInfo.trayEnable = serverProps.trayEnable ?: serverJSON.trayEnable ?: defaults.trayEnable; serverInfo.dockEnable = serverJSON.dockEnable ?: defaults.dockEnable; serverInfo.defaultBaseURL = serverInfo.SSLEnable ? 'https://#serverInfo.host#:#serverInfo.SSLPort#' : 'http://#serverInfo.host#:#serverInfo.port#'; @@ -833,7 +833,7 @@ component accessors="true" singleton { if( directoryExists( possiblePath ) ) { return possiblePath; } - return fileSystemUtil.resolvePath( p, defaultServerConfigFileDirectory ); + return fileSystemUtil.resolvePath( p, defaultServerConfigFileDirectory ); } ) ); // Global errorPages are always added on top of server.json (but don't overwrite the full struct) @@ -860,7 +860,7 @@ component accessors="true" singleton { } else if( !isNull( defaults.JVM.args ) && isSimpleValue( defaults.JVM.args ) && len( defaults.JVM.args ) ) { serverInfo.JVMargs &= ' ' & defaults.JVM.args; } - + // Global defaults are always added on top of whatever is specified by the user or server.json serverInfo.runwarJarPath = serverProps.runwarJarPath ?: serverJSON.runwar.jarPath ?: defaults.runwar.jarPath; @@ -878,7 +878,7 @@ component accessors="true" singleton { } else if( !isNull( defaults.runwar.args ) && isSimpleValue( defaults.runwar.args ) && len( defaults.runwar.args ) ) { serverInfo.runwarArgs &= ' ' & defaults.runwar.args; } - + // Global defaults are always added on top of whatever is specified by the user or server.json serverInfo.runwarXNIOOptions = ( serverJSON.runwar.XNIOOptions ?: {} ).append( defaults.runwar.XNIOOptions, true ); @@ -888,7 +888,7 @@ component accessors="true" singleton { // Server startup timeout serverInfo.startTimeout = serverProps.startTimeout ?: serverJSON.startTimeout ?: defaults.startTimeout; - + serverInfo.JVMProperties = serverJSON.JVM.properties ?: {}; serverInfo.JVMProperties.append( defaults.jvm.properties, false ); @@ -989,7 +989,7 @@ component accessors="true" singleton { "disallowed-methods( methods={trace,track} )", // Common config files and sensitive paths that should never be accessed, even on development "regex( pattern='.*/(box\.json|server\.json|web\.config|urlrewrite\.xml|package\.json|package-lock\.json|Gulpfile\.js)', case-sensitive=false ) -> { set-error(404); done }", - // Any file or folder starting with a period, unless it's called + // Any file or folder starting with a period, unless it's called "regex('/\.') and not path-prefix(.well-known) -> { set-error( 404 ); done }", // Additional serlvlet mappings in Adobe CF's web.xml "path-prefix( { '/JSDebugServlet','/securityanalyzer','/WSRPProducer' } ) -> { set-error( 404 ); done }", @@ -1049,19 +1049,19 @@ component accessors="true" singleton { } serverInfo.webXMLOverrideForce = serverJSON.app.webXMLOverrideForce ?: defaults.app.webXMLOverrideForce; - + serverInfo.sessionCookieSecure = serverJSON.app.sessionCookieSecure ?: defaults.app.sessionCookieSecure; serverInfo.sessionCookieHTTPOnly = serverJSON.app.sessionCookieHTTPOnly ?: defaults.app.sessionCookieHTTPOnly; - + serverInfo.ModCFMLenable = serverJSON.ModCFML.enable ?: defaults.ModCFML.enable; serverInfo.ModCFMLMaxContexts = serverJSON.ModCFML.maxContexts ?: defaults.ModCFML.maxContexts; serverInfo.ModCFMLSharedKey = serverJSON.ModCFML.sharedKey ?: defaults.ModCFML.sharedKey; serverInfo.ModCFMLRequireSharedKey = serverJSON.ModCFML.requireSharedKey ?: defaults.ModCFML.requireSharedKey; serverInfo.ModCFMLcreateVDirs = serverJSON.ModCFML.createVirtualDirectories ?: defaults.ModCFML.createVirtualDirectories; - + // When we add native support for multiple contexts in the server.json, that will also set this to true serverInfo.multiContext = serverInfo.ModCFMLenable; - + if( serverInfo.verbose ) { job.addLog( "start server in - " & serverInfo.webroot ); job.addLog( "server name - " & serverInfo.name ); @@ -1197,7 +1197,7 @@ component accessors="true" singleton { serverInfo.consolelogPath = serverInfo.logdir & '/server.out.txt'; serverInfo.accessLogPath = serverInfo.logDir & '/access.txt'; serverInfo.rewritesLogPath = serverInfo.logDir & '/rewrites.txt'; - + // Find the correct tray icon for this server if( !len( serverInfo.trayIcon ) ) { @@ -1596,10 +1596,10 @@ component accessors="true" singleton { throw( message='Since ModeCFML support is enabled, [ModCFML.sharedKey] is required for security.', detail='Disable IN DEVELOPMENT ONLY with [ModCFML.RequireSharedKey=false].', type="commandException" ); } if( len( serverInfo.ModCFMLSharedKey ) ) { - args.append( '--auto-create-contexts-secret' ).append( serverInfo.ModCFMLSharedKey ); + args.append( '--auto-create-contexts-secret' ).append( serverInfo.ModCFMLSharedKey ); } if( serverInfo.ModCFMLcreateVDirs ) { - args.append( '--auto-create-contexts-vdirs' ).append( serverInfo.ModCFMLcreateVDirs ); + args.append( '--auto-create-contexts-vdirs' ).append( serverInfo.ModCFMLcreateVDirs ); } } @@ -1673,12 +1673,12 @@ component accessors="true" singleton { if ( !currentEnv.containsKey( 'COMMANDBOX_HOME' ) ) { currentEnv.put( 'COMMANDBOX_HOME', expandPath( '/commandbox-home' ) ); } - + // Add COMMANDBOX_VERSION env var to the server if not already there if ( !currentEnv.containsKey( 'COMMANDBOX_VERSION' ) ) { currentEnv.put( 'COMMANDBOX_VERSION', shell.getVersion() ); } - + // Conjoin standard error and output for convenience. processBuilder.redirectErrorStream( true ); @@ -2183,20 +2183,20 @@ component accessors="true" singleton { try{ // Try to stop and set status back - + var processBuilder = createObject( "java", "java.lang.ProcessBuilder" ); processBuilder.init( args ); processBuilder.redirectErrorStream( true ); var process = processBuilder.start(); var inputStream = process.getInputStream(); var exitCode = process.waitFor(); - + var processOutput = toString( inputStream ); - + if( exitCode > 0 ) { throw( message='Error stopping server', detail=processOutput ); } - + //execute name=variables.javaCommand arguments=args timeout="50" variable="results.messages" errorVariable="errorVar"; serverInfo.status = "stopped"; serverInfo.statusInfo = { @@ -2220,7 +2220,7 @@ component accessors="true" singleton { if( !isNull( process ) ) { process.destroy(); } - } + } } /** @@ -2314,6 +2314,7 @@ component accessors="true" singleton { } catch( java.net.UnknownHostException var e ) { // In this case, the host name doesn't exist, so we really don't know about the port, but we'll say it's available // otherwise, old, stopped servers who's host entries no longer exist will show up as running. + consoleLogger.debug("port check in #millisecond(now()) - timeStart#ms") return true; } catch( java.net.BindException var e ) { // Same as above-- the IP address/host isn't bound to any local adapters. Probably a host file entry went missing. @@ -2326,6 +2327,7 @@ component accessors="true" singleton { } // We're assuming that any other error means the address was in use. // Java doesn't provide a specific message or exception type for this unfortunately. + consoleLogger.debug("port check in #millisecond(now()) - timeStart#ms") return false; } } @@ -2339,7 +2341,7 @@ component accessors="true" singleton { return java.InetAddress.getByName( arguments.host ); } catch( java.net.UnknownHostException var e ) { // It's possible to have "fake" hosts such as mytest.localhost which aren't in DNS - // or your hosts file. Browsers will resolve them to localhost, but the call above + // or your hosts file. Browsers will resolve them to localhost, but the call above // will fail with a UnknownHostException since they aren't real if( host.listLast( '.' ) == 'localhost' ) { return java.InetAddress.getByName( '127.0.0.1' ); @@ -2348,24 +2350,39 @@ component accessors="true" singleton { } } + /** + * Find out if a given Process ID (PID) is a running java service + * @pidStr.hint PID to test on + **/ + function isProcessAlive(required pidStr) { + var result = ""; + var timeStart = millisecond(now()); + try{ + if (fileSystemUtil.isWindows() ) { + cfexecute(name='cmd', arguments='/c tasklist /FI "PID eq #pidStr#"', variable="result" timeout="10"); + } else if (fileSystemUtil.isMac() || fileSystemUtil.isLinux() ) { + cfexecute(name='ps', arguments='-p #pidStr#', variable="result" , timeout="10"); + } + if (findNoCase("java", result) > 0 && findNoCase(pidStr, result) > 0) return true; + } catch ( any e ){ + consoleLogger.debug(e.message); + } + return false; + } /** * Logic to tell if a server is running * @serverInfo.hint Struct of server information **/ function isServerRunning( required struct serverInfo ){ - var portToCheck = serverInfo.stopSocket; - if( serverInfo.HTTPEnable ) { - portToCheck = serverInfo.port; - } else if( serverInfo.SSLEnable ) { - portToCheck = serverInfo.SSLPort; - } else if( serverInfo.AJPEnable ) { - portToCheck = serverInfo.AJPPort; - } - - lock name="server-status-check-#portToCheck#" type="exclusive"{ - return !isPortAvailable( serverInfo.host, portToCheck ); + if(fileExists(serverInfo.pidFile)){ + var getPID = fileRead(serverInfo.pidFile); + thread action="run" name="check_#getPID##getTickCount()#" { + if(!isProcessAlive(getPID)) fileDelete(serverInfo.pidFile) + } + return true; } + return false; } /** @@ -2556,7 +2573,7 @@ component accessors="true" singleton { return getServers() .valueArray() .map( (s)=>s.name ) - .sort( 'textNoCase' ); + .sort( 'textNoCase' ); } /** @@ -2776,7 +2793,7 @@ component accessors="true" singleton { 'onServerStart' : '', 'onServerStop' : '', 'preServerForget' : '', - 'postServerForget' : '' + 'postServerForget' : '' } } ); } @@ -2791,7 +2808,7 @@ component accessors="true" singleton { * Dynamic completion for server names, sorted by last started */ function serverNameComplete() { - + return getservers() .valueArray() .sort( (a,b)=>{ @@ -2803,8 +2820,8 @@ component accessors="true" singleton { } ) .map( (s,i)=>return { name : s.name, group : 'Server Names', sort : i } ); } - - + + /** * Loads config settings from env vars or Java system properties */ @@ -2812,8 +2829,8 @@ component accessors="true" singleton { var debugMessages = []; var job = wirebox.getInstance( 'interactiveJob' ); var overrides={}; - - // Look for individual BOX settings to import. + + // Look for individual BOX settings to import. var processVarsUDF = function( envVar, value, string source ) { // Loop over any that look like box_server_xxx if( envVar.len() > 11 && reFindNoCase( 'box[_\.]server[_\.]', left( envVar, 11 ) ) ) { @@ -2824,13 +2841,13 @@ component accessors="true" singleton { JSONService.set( JSON=overrides, properties={ '#name#' : value }, thisAppend=true ); } }; - + // Get all OS env vars var envVars = system.getenv(); for( var envVar in envVars ) { processVarsUDF( envVar, envVars[ envVar ], 'OS environment variable' ); } - + // Get all System Properties var props = system.getProperties(); for( var prop in props ) { @@ -2842,21 +2859,21 @@ component accessors="true" singleton { for( var envVar in envVars ) { processVarsUDF( envVar, envVars[ envVar ], 'box environment variable' ); } - + if( overrides.keyExists( 'profile' ) ) { serverInfo.envVarHasProfile=true } - + if( verbose && debugMessages.len() ) { job.start( 'Overriding server.json values from env vars' ); debugMessages.each( (l)=>job.addLog( l ) ); job.complete( verbose ); } - + JSONService.mergeData( serverJSON, overrides ); } - - + + /** * Nice wrapper to run a server script @@ -2876,7 +2893,7 @@ component accessors="true" singleton { } var serverJSON = serverDetails.serverJSON; systemSettings.expandDeepSystemSettings( serverJSON ); - loadOverrides( serverJSON, serverDetails.serverInfo, serverDetails.serverInfo.verbose ?: false ); + loadOverrides( serverJSON, serverDetails.serverInfo, serverDetails.serverInfo.verbose ?: false ); } else { consoleLogger.warn( 'Could not find server for script [#arguments.scriptName#].' ); return; diff --git a/src/cfml/system/util/MultiSelect.cfc b/src/cfml/system/util/MultiSelect.cfc index e72d9b54..87aacd18 100644 --- a/src/cfml/system/util/MultiSelect.cfc +++ b/src/cfml/system/util/MultiSelect.cfc @@ -191,10 +191,14 @@ component accessors=true { if( job.getActive() ) { job.addLog( getQuestion() & ': ' & response ); } else { - printBuffer - .line() - .text( getQuestion() ) - .line( response ) + var pb = printBuffer.line(); + + if(len(getQuestion() & response) > 80) { + pb.line( getQuestion() ); + } else { + pb.text( getQuestion() ); + } + pb.line( response ) .toConsole(); } From a43ed0ada9f72bc9b8e0e18fb074a59e800cc221 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 13:34:07 -0600 Subject: [PATCH 056/118] COMMANDBOX-1428 COMMANDBOX-1427 --- .../commands/server/status.cfc | 50 +++++++------------ src/cfml/system/services/ServerService.cfc | 18 ++++--- 2 files changed, 28 insertions(+), 40 deletions(-) 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 6b2436cc..ac984c1a 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 @@ -157,40 +157,26 @@ component aliases='status,server info' { print.indentedLine( 'ID: ' & thisServerInfo.id ); print.line().indentedLine( 'Server Home: ' & thisServerInfo.serverHome ); - - var portToCheck = 'stop socket'; - var portToCheckValue = thisServerInfo.stopSocket; - if( thisServerInfo.HTTPEnable ) { - portToCheck = 'HTTP port'; - portToCheckValue = thisServerInfo.port; - } else if( thisServerInfo.SSLEnable ) { - portToCheck = 'HTTPS port'; - portToCheckValue = thisServerInfo.SSLPort; - } else if( thisServerInfo.AJPEnable ) { - portToCheck = 'AJP port'; - portToCheckValue = thisServerInfo.AJPPort; - } - - print.line().indentedLine( 'Host/Port used for "running" check: #portToCheck# (#thisServerInfo.host#:#portToCheckValue#)'); - - var bindException = ''; - try { - var serverSocket = createObject( "java", "java.net.ServerSocket" ) - .init( - javaCast( "int", portToCheckValue ), - javaCast( "int", 1 ), - createObject( "java", "java.net.InetAddress" ).getByName( thisServerInfo.host ) ); - serverSocket.close(); - } catch( any var e ) { - bindException = e; - } - - if( !isSimpleValue( bindException ) ) { - print.indentedLine( 'Port bind result for "running" check: #bindException.type# #bindException.message# #bindException.detail#'); + + print.line().indentedLine( 'PID file used for "running" check: ' ) + .indentedIndentedLine( serverInfo.pidFile ); + + if( fileExists( serverInfo.pidFile ) ){ + print.indentedIndentedLine( 'PID file exists.' ); + try { + var serverPID = fileRead(serverInfo.pidFile); + if( serverService.isProcessAlive( serverPID, true ) ) { + print.indentedIndentedLine( 'PID [#serverPID#] is running' ); + } else { + print.indentedIndentedLine( 'PID [#serverPID#] is NOT running' ); + } + } catch( any var e ) { + print.indentedIndentedText( 'Error checking if server PID was running: [' ).redText( e.message & ' ' & e.detail ).line( '] Server is assumed running.' ); + } } else { - print.indentedLine( 'Port bind result for "running" check: successful bound, port not in use.'); + print.indentedIndentedLine( 'PID file does not exist. Server is assumed stopped.' ); } - + print.line().indentedLine( 'Last Command: ' ); // Put each --arg or -arg on a new line diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index af6ff448..cf18eb2a 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -38,6 +38,7 @@ component accessors="true" singleton { property name='packageService' inject='packageService'; property name='serverEngineService' inject='serverEngineService'; property name='consoleLogger' inject='logbox:logger:console'; + property name='rootLogger' inject='logbox:root'; property name='wirebox' inject='wirebox'; property name='CR' inject='CR@constants'; property name='parser' inject='parser'; @@ -2314,7 +2315,6 @@ component accessors="true" singleton { } catch( java.net.UnknownHostException var e ) { // In this case, the host name doesn't exist, so we really don't know about the port, but we'll say it's available // otherwise, old, stopped servers who's host entries no longer exist will show up as running. - consoleLogger.debug("port check in #millisecond(now()) - timeStart#ms") return true; } catch( java.net.BindException var e ) { // Same as above-- the IP address/host isn't bound to any local adapters. Probably a host file entry went missing. @@ -2327,7 +2327,6 @@ component accessors="true" singleton { } // We're assuming that any other error means the address was in use. // Java doesn't provide a specific message or exception type for this unfortunately. - consoleLogger.debug("port check in #millisecond(now()) - timeStart#ms") return false; } } @@ -2354,18 +2353,21 @@ component accessors="true" singleton { * Find out if a given Process ID (PID) is a running java service * @pidStr.hint PID to test on **/ - function isProcessAlive(required pidStr) { + function isProcessAlive( required pidStr, throwOnError=false ) { var result = ""; var timeStart = millisecond(now()); try{ - if (fileSystemUtil.isWindows() ) { + if (fileSysdfsdfsdfsdstemUtil.isWindows() ) { cfexecute(name='cmd', arguments='/c tasklist /FI "PID eq #pidStr#"', variable="result" timeout="10"); } else if (fileSystemUtil.isMac() || fileSystemUtil.isLinux() ) { cfexecute(name='ps', arguments='-p #pidStr#', variable="result" , timeout="10"); } if (findNoCase("java", result) > 0 && findNoCase(pidStr, result) > 0) return true; } catch ( any e ){ - consoleLogger.debug(e.message); + if( throwOnError ) { + rethrow; + } + rootLogger.error( 'Error checking if server PID was running: ' & e.message & ' ' & e.detail ); } return false; } @@ -2376,9 +2378,9 @@ component accessors="true" singleton { **/ function isServerRunning( required struct serverInfo ){ if(fileExists(serverInfo.pidFile)){ - var getPID = fileRead(serverInfo.pidFile); - thread action="run" name="check_#getPID##getTickCount()#" { - if(!isProcessAlive(getPID)) fileDelete(serverInfo.pidFile) + var serverPID = fileRead(serverInfo.pidFile); + thread action="run" name="check_#serverPID##getTickCount()#" serverPID=serverPID pidFile=serverInfo.pidFile { + if(!isProcessAlive(attributes.serverPID,true)) fileDelete(attributes.pidFile) } return true; } From ba47c223ee82f1abf7d8d769a05b20925717aa60 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 13:35:07 -0600 Subject: [PATCH 057/118] remove debugging force error --- 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 cf18eb2a..8c559222 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -2357,7 +2357,7 @@ component accessors="true" singleton { var result = ""; var timeStart = millisecond(now()); try{ - if (fileSysdfsdfsdfsdstemUtil.isWindows() ) { + if (fileSystemUtil.isWindows() ) { cfexecute(name='cmd', arguments='/c tasklist /FI "PID eq #pidStr#"', variable="result" timeout="10"); } else if (fileSystemUtil.isMac() || fileSystemUtil.isLinux() ) { cfexecute(name='ps', arguments='-p #pidStr#', variable="result" , timeout="10"); From a9318c1b850d0acbb6012ae06cc011c170330cee Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 13:36:53 -0600 Subject: [PATCH 058/118] soften tone of error message --- .../system/modules_app/server-commands/commands/server/open.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6ec0df3c..a47ca313 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 @@ -48,7 +48,7 @@ component { var serverInfo = serverDetails.serverInfo; if( serverDetails.serverIsNew ){ - print.boldRedLine( "No server configurations found so have no clue what to open buddy!" ); + print.boldRedLine( "No servers found." ); } else { // myPath/file.cfm is normalized to /myMapth/file.cfm if( !arguments.URI.startsWith( '/' ) ) { From f6691582be5b35f0bbc33c1674184a3122d3be8d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 13:45:31 -0600 Subject: [PATCH 059/118] COMMANDBOX-1429 --- src/cfml/system/endpoints/ForgeBox.cfc | 1 - .../system/modules/globber/models/Globber.cfc | 464 +++++++++++++----- .../globber/models/PathPatternMatcher.cfc | 14 +- .../system-commands/commands/dir.cfc | 4 +- .../system-commands/commands/edit.cfc | 6 +- 5 files changed, 357 insertions(+), 132 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 9fe46fd8..005b34a9 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -22,7 +22,6 @@ component accessors="true" implements="IEndpointInteractive" { property name="fileSystemUtil" inject="FileSystem"; property name="fileEndpoint" inject="commandbox.system.endpoints.File"; property name="lexEndpoint" inject="commandbox.system.endpoints.Lex"; - property name='pathPatternMatcher' inject='provider:pathPatternMatcher@globber'; property name='wirebox' inject='wirebox'; // Properties diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index e3567dd6..cf5ba968 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -19,10 +19,14 @@ component accessors="true" { property name='pattern'; /** The file globbing pattern NOT to match. */ property name='excludePattern'; + property name='notExcludePattern'; /** query of real file system resources that match the pattern */ property name='matchQuery'; + property name='matchQueryArray'; /** Return matches as a query instead of an array */ property name='format' default='array'; + /** Uses Gitignore rules that match pattern anywhere inside path, not requiring explicit * at the start or end of the pattern */ + property name='loose' default='false'; /** Sort to use */ property name='sort' default='type, name'; /** Directory the list was pulled from */ @@ -33,6 +37,26 @@ component accessors="true" { variables.format = 'array'; variables.pattern = []; variables.excludePattern = []; + variables.notExcludePattern = []; + variables.loose = false; + variables.matchQueryArray=[]; + return this; + } + + /** + * Enable loose matching + */ + function inDirectory( required string baseDirectory ) { + baseDirectory = pathPatternMatcher.normalizeSlashes( baseDirectory ); + setBaseDir( baseDirectory & ( baseDirectory.endsWith( '/' ) ? '' : '/' ) ); + return this; + } + + /** + * Enable loose matching + */ + function loose( boolean loose=true ) { + setLoose( loose ); return this; } @@ -65,16 +89,14 @@ component accessors="true" { * Can be list of patterns or array of patterns. * Empty patterns will be ignored */ - function setPattern( required any pattern ) { - if( isSimpleValue( arguments.pattern ) ) { - arguments.pattern = listToArray( arguments.pattern ); + function setPattern( required any thisPattern ) { + variables.pattern = []; + if( isSimpleValue( arguments.thisPattern ) ) { + arguments.thisPattern = listToArray( arguments.thisPattern ); } - arguments.pattern = arguments.pattern.map( function( p ) { - return pathPatternMatcher.normalizeSlashes( arguments.p ); - }).filter( function( p ){ - return len( arguments.p ); - } ); - variables.pattern = arguments.pattern; + arguments.thisPattern.each( function( p ) { + addPattern( arguments.p ); + }); return this; } @@ -83,6 +105,7 @@ component accessors="true" { */ function addPattern( required string pattern ) { if( len( arguments.pattern ) ) { + arguments.pattern = pathPatternMatcher.normalizeSlashes( arguments.pattern ); variables.pattern.append( arguments.pattern ); } return this; @@ -107,16 +130,14 @@ component accessors="true" { * Can be list of excludePatterns or array of excludePatterns. * Empty excludePatterns will be ignored */ - function setExcludePattern( required any excludePattern ) { - if( isSimpleValue( arguments.excludePattern ) ) { - arguments.excludePattern = listToArray( arguments.excludePattern ); + function setExcludePattern( required any thisExcludePattern ) { + variables.excludePattern = []; + if( isSimpleValue( arguments.thisExcludePattern ) ) { + arguments.thisExcludePattern = listToArray( arguments.thisExcludePattern ); } - arguments.excludePattern = arguments.excludePattern.map( function( p ) { - return pathPatternMatcher.normalizeSlashes( arguments.p ); - }).filter( function( p ){ - return len( arguments.p ); - } ); - variables.excludePattern = arguments.excludePattern; + arguments.thisExcludePattern.each( function( p ) { + addExcludePattern( p ); + }); return this; } @@ -125,11 +146,27 @@ component accessors="true" { */ function addExcludePattern( required string excludePattern ) { if( len( arguments.excludePattern ) ) { - variables.excludePattern.append( arguments.excludePattern ); + if ( arguments.excludePattern.startsWith( '!' ) ) { + addNotExcludePattern( mid( arguments.excludePattern, 2, len( arguments.excludePattern ) - 1 ) ); + } else { + arguments.excludePattern = pathPatternMatcher.normalizeSlashes( arguments.excludePattern ); + variables.excludePattern.append( arguments.excludePattern ); + } } return this; } + /** + * Add not excludePattern to process + */ + function addNotExcludePattern( required string notExcludePattern ) { + if( len( arguments.notExcludePattern ) ) { + arguments.notExcludePattern = pathPatternMatcher.normalizeSlashes( arguments.notExcludePattern ); + variables.notExcludePattern.append( arguments.notExcludePattern ); + } + return this; + } + /** * Always returns a string which is a list of excludePatterns */ @@ -148,11 +185,52 @@ component accessors="true" { * Pass a closure to this function to have it * applied to each paths matched by the pattern. */ - function apply( udf ) { + function apply( required udf ) { matches().each( udf ); return this; } + /** + * Copy all matched paths to a new folder + */ + function copyTo( required string targetPath ) { + targetPath = pathPatternMatcher.normalizeSlashes( targetPath ); + if( !targetPath.endsWith( '/' ) ) { + targetPath &= '/'; + } + ensureMatches(); + var paths = getMatchQuery(); + if( !directoryExists( targetPath ) ) { + directoryCreate( targetPath, true, true ); + } + // Create all folders first + paths + .filter( (p)=>p.type=='dir' ) + .sort( (a,b)=>len(a.directory&a.name )-len(b.directory&b.name ) ) + .each( (p)=>{ + var newDir = p.directory.listAppend( p.name, '/', false ); + newDir = pathPatternMatcher.normalizeSlashes( newDir ); + newDir = newDir.replace( getBaseDir(), '' ) + directoryCreate( targetPath & newDir, true, true ) + } ); + // Copy files asynch + paths + .filter( (p)=>p.type=='file' ) + .each( (p)=>{ + var oldFile = p.directory.listAppend( p.name, '/', false ); + var newFile = pathPatternMatcher.normalizeSlashes( oldFile ); + newFile = targetPath & newFile.replace( getBaseDir(), '' ); + // Just in case + newDirectory = getDirectoryFromPath( newFile ); + if( !directoryExists( newDirectory ) ) { + directoryCreate( newDirectory, true, true ); + } + fileCopy( oldFile, newFile ) + }, true ); + + return this; + } + /** * Get array of matched file system paths */ @@ -190,32 +268,25 @@ component accessors="true" { private function process() { var patterns = getPatternArray(); - if( !patterns.len() ) { - throw( 'Cannot glob empty pattern.' ); + if( !patterns.len() && !getBaseDir().len() ) { + throw( 'Cannot glob empty pattern with no base directory.' ); + } else if( !patterns.len() ) { + patterns = [ '**' ]; } + if( getLoose() && !len( getBaseDir() ) ) { + throw( 'You must use [inDirectory()] to set a base dir when using loose matching.' ); + } + for( var thisPattern in patterns ) { processPattern( thisPattern ); } var matchQuery = getMatchQuery(); + + combineMatchQueries(); - if( isNull( matchQuery ) ) { - setMatchQuery( queryNew( 'name,size,type,dateLastModified,attributes,mode,directory' ) ); - } else { - // UNION isn't removing dupes on Lucee so doing second select here for that purpose. - cfquery( dbtype="query" ,name="local.newMatchQuery" ) { - writeOutput( 'SELECT DISTINCT * FROM matchQuery ' ); - if( len( getSort() ) ) { - writeOutput( 'ORDER BY #getCleanSort()#' ); - } - } - - setMatchQuery( local.newMatchQuery ); - } - - - if( patterns.len() > 1 ) { + if( patterns.len() > 1 && !getLoose() ) { var dirs = queryColumnData( getMatchQuery(), 'directory' ); var lookups = {}; dirs.each( function( dir ) { @@ -241,109 +312,130 @@ component accessors="true" { } function appendMatchQuery( matchQuery ) { - // First one in just gets set - if( isNull( getMatchQuery() ) ) { - setMatchQuery( matchQuery ); - // merge remaining patterns - } else { - var previousMatch = getMatchQuery(); - - cfquery( dbtype="query" ,name="local.newMatchQuery" ) { - writeOutput( 'SELECT * FROM matchQuery UNION SELECT * FROM previousMatch ' ); - } - - setMatchQuery( local.newMatchQuery ); - } + matchQueryArray.append( matchQuery ); + return; } - private function processPattern( string pattern ) { - + private function processPattern( string pattern, baseDir, skipExcludes=false ) { local.thisPattern = pathPatternMatcher.normalizeSlashes( arguments.pattern ); - - // 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; - // 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 = '/'; - } - - var everythingAfterBaseDir = thisPattern.replace( baseDir, '' ); - - // If we have a partial directory next such as modules* optimize here - if( everythingAfterBaseDir.listLen( '/' ) > 1 && everythingAfterBaseDir.listFirst( '/' ).reFind( '[^\*^\?]' ) && !everythingAfterBaseDir.listFirst( '/' ).startsWith( '**' ) ) { - - thisPattern = baseDir & '/' & everythingAfterBaseDir.listFirst( '/' ) & '/'; - // Manually loop over the dirs at this level that match to narrow what we're looking at - directoryList ( - listInfo='query', - recurse=false, - path=baseDir, - type='dir', - sort=getSort(), - filter=( path )=>{ - var thisPath = path & '/'; - if( pathPatternMatcher.matchPattern( thisPattern, thisPath, true ) ) { - return true; + var exactPattern = thisPattern.startsWith('/'); + var fileFilter = ''; + var fullPatternPath = ( getLoose() ? getBaseDir().listAppend( thisPattern, '/', false ) : thisPattern ); + + // Optimization for exact file path + if( ( !getLoose() || exactPattern ) + && ( thisPattern does not contain '*' && thisPattern does not contain '?' && fileExists( fullPatternPath ) ) + ) { + arguments.baseDir = getDirectoryFromPath( fullPatternPath ); + fileFilter = '*' & listLast( fullPatternPath, '/' ) + } else { + if( isNull( arguments.baseDir ) ) { + // 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. + if( getLoose() ) { + if( exactPattern ) { + arguments.baseDir = calculateBaseDir( getBaseDir() & thisPattern.right( -1 ) ) + } else { + arguments.baseDir = calculateBaseDir( getBaseDir() ) } - return false; + } else { + arguments.baseDir = calculateBaseDir( thisPattern ); } - ).each( ( folder )=>processPattern( baseDir & '/' & folder.name & '/' & everythingAfterBaseDir.listRest( '/' ) ) ) - - return; - } - - var recurse = false; - if( thisPattern contains '**' ) { - recurse = true; - } - - var optimizeFilter = ''; - if( reFind( '\.[a-zA-Z0-9\?\*]{2,4}$', thisPattern ) ) { - optimizeFilter = '*.' & thisPattern.listLast( '.' ).replace( '?', '*', 'all' ); + } } + // Strip off the "not found" part + var remainingPattern = findUnmatchedPattern( thisPattern, baseDir ) + var dl = directoryList ( listInfo='query', - recurse=local.recurse, + recurse=false, path=baseDir, - sort=getSort(), - filter=optimizeFilter + filter=fileFilter ).filter( ( path )=>{ - if( path.directory.endsWith( '/' ) || path.directory.endsWith( '\' ) ) { - var thisPath = path.directory & path.name & ( path.type == 'dir' ? '/' : '' ); + // All of this nonsense is to build the full normalized path of this item WITH a trailing slash if it's a directory + if( arguments.path.directory.endsWith( '/' ) || arguments.path.directory.endsWith( '\' ) ) { + var thisPath = arguments.path.directory & arguments.path.name & ( arguments.path.type == 'dir' ? '/' : '' ); } else { - var thisPath = path.directory & '/' & path.name & ( path.type == 'dir' ? '/' : '' ); + var thisPath = arguments.path.directory & '/' & arguments.path.name & ( arguments.path.type == 'dir' ? '/' : '' ); } - if( pathPatternMatcher.matchPattern( thisPattern, thisPath, true ) ) { - if( getExcludePatternArray().len() && pathPatternMatcher.matchPatterns( getExcludePatternArray(), thisPath, true ) ) { - return false; + local.thisPath = pathPatternMatcher.normalizeSlashes( thisPath ); + + var pathToMatch = local.thisPath; + if( getLoose() ) { + pathToMatch = local.thisPath.replaceNoCase( getBaseDir(), '' ); + } + + // If we've hit an exclude pattern, we can bail now-- skipping all recursion and processing of files at this level. + var thisExcludePattern = this.getExcludePatternArray(); + if( !skipExcludes && thisExcludePattern.len() && pathPatternMatcher.matchPatterns( thisExcludePattern, pathToMatch, !getLoose() ) ) { + // UNLESS we have a negated ignore! + var possiblePatterns = pathMayNotBeExcluded( pathToMatch, path.type, baseDir ); + if( possiblePatterns.len() ) { + // If we're looking at a file, just check it. No need to recurse. + if( path.type == 'file' ) { + if( pathPatternMatcher.matchPatterns( possiblePatterns, pathToMatch, !getLoose() ) ) { + return true; + } + } else { + // For each of our possible patterns, let's recurse and check each of them. + // TODO: optimize this by recursing once and checking all patterns at a time, + // but that will require a major refactor of processPatterns() to accept more than one pattern. + for( var possiblePattern in possiblePatterns) { + if( getLoose() ) { + if( possiblePattern.startsWith( '/' ) ) { + // Exact patterns in loose mode like /foo/bar/baz.txt we want to zoom staright down to the + // deepest folder possible to reduce unnessary recursion. + possiblePattern = getBaseDir().listAppend( possiblePattern, '/', false ); + var thisBaseDir = calculateBaseDir( possiblePattern ); + possiblePattern = possiblePattern.replace( thisBaseDir, '' ); + processPattern( possiblePattern, thisBaseDir, true ); + } else { + // non-exact patters which can be in any sub directory such as foo.txt just recurse down from the current folder we're looking at + processPattern( possiblePattern, thisPath, true ) + } + } else { + // For non-loose mode just grab the deepest folder we can and start there. + var thisBaseDir = calculateBaseDir( possiblePattern ); + processPattern( possiblePattern, thisBaseDir, true ) + } + } + } + } + return false; + } + + // If we're inside a **, then we just blindly recurse forever + if( arguments.path.type == 'dir' && remainingPattern.startsWith( '**' ) ) { + processPattern( thisPattern, local.thisPath, skipExcludes ) + // If we're in loose mode, see if the next folder is a positive match + } else if( arguments.path.type == 'dir' && getLoose() ) { + if( exactPattern ) { + if( pathPatternMatcher.matchPattern( '/' & remainingPattern.listFirst( '/' ), pathToMatch, !getLoose() ) ) { + processPattern( '/' & remainingPattern.listRest( '/' ), local.thisPath, skipExcludes ); + } + } else { + processPattern( thisPattern, local.thisPath, skipExcludes ); + } + // For all other remaining patterns, only recurse if we've found a folder that matches the next part of the pattern + } if( arguments.path.type == 'dir' && remainingPattern.listLen( '/' ) > 1 ) { + if( pathPatternMatcher.matchPattern( baseDir & remainingPattern.listFirst( '/' ) & '/**', pathToMatch, !getLoose() ) ) { + processPattern( local.thisPath & remainingPattern.listRest( '/' ), local.thisPath, skipExcludes ); } + } + + // This check applies to files/folders that are immediate children of the current base dir. + // We've already recursed into all worthy subfolders above + if( pathPatternMatcher.matchPattern( thisPattern, local.pathToMatch, !getLoose() ) ) { return true; } return false; } ); appendMatchQuery( dl ); - setBaseDir( baseDir & ( baseDir.endsWith( '/' ) ? '' : '/' ) ); + if( !getLoose() ) { + setBaseDir( baseDir & ( baseDir.endsWith( '/' ) ? '' : '/' ) ); + } } @@ -372,4 +464,134 @@ component accessors="true" { return getSort(); } + private function calculateBaseDir( required string pattern ) { + var baseDir = ''; + var i = 0; + // Skip last token + while( ++i <= pattern.listLen( '/' ) ) { + var token = pattern.listGetAt( i, '/' ); + if( token contains '*' || token contains '?' ) { + break; + } + // If we have a partial name like /foo/bar we may still match /foo/barstool. + // Only if it's /foo/bar/ do we know we can trust that in the base path + if( i == pattern.listLen( '/' ) && !pattern.endsWith( '/' ) ) { + break; + } + baseDir = baseDir.listAppend( token, '/', false ); + } + + // Unix paths need the leading slash put back + if( pattern.startsWith( '/' ) ) { + baseDir = '/' & baseDir; + } + + baseDir &= '/'; + return baseDir; + } + + private function combineMatchQueries() { + if( !matchQueryArray.len() ) { + setMatchQuery( queryNew( 'name,size,type,dateLastModified,attributes,mode,directory' ) ); + } else { + var SQL = '' + var i = 0; + for( var thisQ in matchQueryArray ) { + i++; + local[ 'thisMatchQuery#i#' ] = thisQ; + SQL &= ' SELECT * FROM thisMatchQuery#i# '; + if( i < matchQueryArray.len() ) { + SQL &= ' UNION ALL' + } + } + + var newMatchQuery = queryExecute( + SQL, + [], + { dbtype="query" } + ); + + var newMatchQuery = queryExecute( + 'SELECT * FROM newMatchQuery + GROUP BY directory, name ' + & ( len( getSort() ) ? ' ORDER BY #getCleanSort()#' : '' ), + [], + { dbtype="query" } + ); + + setMatchQuery( local.newMatchQuery ); + } + } + + function pathMayNotBeExcluded( pathToMatch, type, currentBaseDir ) { + if( !getNotExcludePattern().len() ) { + return []; + } + var possiblePatterns=[]; + + for( notExclude in getNotExcludePattern() ) { + var exactPattern = notExclude.startsWith('/'); + var remainingPattern = findUnmatchedPattern( notExclude, currentBaseDir ) + + // Well, crumbs-- all bets are off! + // /temp/** + // !foo.txt + if( type == 'dir' && getLoose() && !exactPattern ) { + possiblePatterns.append( notExclude ); + continue; + } + + // If it's a file, just check it + if( type == 'file' ) { + if( pathPatternMatcher.matchPattern( notExclude, pathToMatch, false ) ) { + possiblePatterns.append( notExclude ); + } + // Even if we didn't find a match, all the checks below only apply to directories + continue; + } + + // These all apply to directories. The question is whether or not we MAY need to recurse into the dir + // based on whether there is a notexclude pattern that could possibly be inside the dir + + // If we're inside a **, then we just blindly recurse forever + if( remainingPattern.startsWith( '**' ) ) { + possiblePatterns.append( notExclude ); + continue; + // If we're in loose mode with an exact pattern, see if the next folder is a positive match + } else if( getLoose() && exactPattern && pathPatternMatcher.matchPattern( '/' & remainingPattern.listFirst( '/' ), pathToMatch, !getLoose() ) ) { + possiblePatterns.append( notExclude ); + continue; + // For all other remaining patterns, only recurse if we've found a folder that matches the next part of the pattern + } if( remainingPattern.listLen( '/' ) > 1 && pathPatternMatcher.matchPattern( currentBaseDir & remainingPattern.listFirst( '/' ) & '/**', pathToMatch, !getLoose() ) ) { + possiblePatterns.append( notExclude ); + continue; + } + + } + return possiblePatterns; + } + + function findUnmatchedPattern( thisPattern, currentBaseDir ) { + var exactPattern = thisPattern.startsWith('/'); + if( getLoose() ) { + if( exactPattern ) { + if( currentBaseDir == getBaseDir() ) { + var remainingPattern = thisPattern; + } else { + var remainingPattern = thisPattern.replaceNoCase( currentBaseDir.replaceNoCase( getBaseDir(), '' ), '' ); + } + } else { + // A loose pattern without a leading slash can be any levels deep + remainingPattern = '**'; + } + } else { + var remainingPattern = thisPattern.replaceNoCase( currentBaseDir, '' ); + // if our base path isn't contained inside the pattern, we have entered a ** portion and we can't short circuit anything now + if( remainingPattern == thisPattern ) { + remainingPattern = '**'; + } + } + return remainingPattern; + } + } diff --git a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc index 17e168d9..c1c9ba8a 100644 --- a/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc +++ b/src/cfml/system/modules/globber/models/PathPatternMatcher.cfc @@ -74,15 +74,23 @@ component accessors="true" singleton { regex = replace( regex, '/**/', '__zeroOrMoreDirs_', 'all' ); // Double ** matches anything regex = replace( regex, '**', '__anything_', 'all' ); - // Single * matches anything BUT slash - regex = replace( regex, '*', '__anythingButSlash__', 'all' ); + // Match a single dir + regex = replace( regex, '/*/', '/__anythingButSlashOneOrMore__/', 'all' ); + + // Single * matches anything BUT slash one or more chars + if( regex.endsWith( '/*' ) ) { + regex = regex.left( -1 ) & '__anythingButSlashOneOrMore__'; + } + // Single * matches anything BUT slash zero or more chars + regex = replace( regex, '*', '__anythingButSlashZeroOrMore__', '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, '__anything_', '.*', 'all' ); - regex = replace( regex, '__anythingButSlash__', '[^/]*', 'all' ); + regex = replace( regex, '__anythingButSlashOneOrMore__', '[^/]+', 'all' ); + regex = replace( regex, '__anythingButSlashZeroOrMore__', '[^/]*', 'all' ); regex = replace( regex, '__singleNonSlash__', '[^/]', 'all' ); // If the pattern doesn't come with an explicit ending slash, add an optional one 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 fbe023db..1cde7c19 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -53,7 +53,7 @@ component aliases="ls,ll,directory" { paths.setPattern( paths.getPatternArray().map( (p) => { if( directoryExists( p ) ){ - return p & '*' & ( recurse ? '*' : '' ); + return p.listAppend( '*', '/', false ) & ( recurse ? '*' : '' ); } return p; } ) @@ -62,7 +62,7 @@ component aliases="ls,ll,directory" { excludePaths = excludePaths.listMap( (p) => { p = fileSystemUtil.resolvePath( p ) if( directoryExists( p ) ){ - return p & '*' & ( recurse ? '*' : '' ); + return p.listAppend( '*', '/', false ) & ( recurse ? '*' : '' ); } return p; } ); 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 165c0083..527a2c25 100644 --- a/src/cfml/system/modules_app/system-commands/commands/edit.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/edit.cfc @@ -14,14 +14,10 @@ component aliases="open" { /** * @path.hint Path to open natively. **/ - function run( Globber path=globber( getCWD() ) ) { + function run( Globber path=globber( getCWD().left(-1) ) ) { 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 { From 8821418e63d4525b13c301fb3cde01cd24c0cc21 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 13:50:56 -0600 Subject: [PATCH 060/118] COMMANDBOX-1429 --- src/cfml/system/modules/globber/box.json | 12 +++++------- src/cfml/system/modules/globber/models/Globber.cfc | 7 ++++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/cfml/system/modules/globber/box.json b/src/cfml/system/modules/globber/box.json index 38724fee..412c1413 100644 --- a/src/cfml/system/modules/globber/box.json +++ b/src/cfml/system/modules/globber/box.json @@ -1,8 +1,7 @@ { "name":"Globber", - "version":"3.0.6", + "version":"3.1.1", "author":"Brad Wood", - "location":"Ortus-Solutions/globber#v3.0.6", "homepage":"https://github.com/Ortus-Solutions/globber/", "documentation":"https://github.com/Ortus-Solutions/globber/", "repository":{ @@ -15,15 +14,14 @@ "type":"modules", "dependencies":{}, "devDependencies":{ - "coldbox":"^4.3.0+188", - "testbox":"^2.4.0+80" + "testbox":"^4.4.0-snapshot", + "coldbox":"^4.3.0+188" }, "installPaths":{ - "testbox":"testbox", - "coldbox":"tests\\resources\\app\\coldbox" + "coldbox":"tests/resources/app/coldbox/", + "testbox":"testbox/" }, "scripts":{ - "postVersion":"package set location='Ortus-Solutions/globber#v`package version`'", "onRelease":"forgebox use ortus && publish", "postPublish":"!git push --follow-tags" }, diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index cf5ba968..c133e2b9 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -346,7 +346,7 @@ component accessors="true" { // Strip off the "not found" part var remainingPattern = findUnmatchedPattern( thisPattern, baseDir ) - + var dl = directoryList ( listInfo='query', recurse=false, @@ -486,6 +486,11 @@ component accessors="true" { baseDir = '/' & baseDir; } + // Windows drive letters need trailing slash. + if( baseDir.listLen( '/' ) == 1 && baseDir contains ':' ) { + baseDir = baseDir & '/'; + } + baseDir &= '/'; return baseDir; } From 36275189e371e2b89616d7f32eaddc16c8ecf8a4 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 14:02:45 -0600 Subject: [PATCH 061/118] COMMANDBOX-1430 --- src/cfml/system/Shell.cfc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index 08a1cc11..b1953576 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -485,6 +485,10 @@ component accessors="true" singleton { * @directory.hint directory to CD to. Please verify it exists before calling. **/ String function cd( directory="" ){ + // Ensure we have a trailing slash for our directory. + if( !(arguments.directory.endsWith( '/' ) || arguments.directory.endsWith( '\' ) ) ) { + arguments.directory &= '/'; + } variables.pwd = arguments.directory; request.lastCWD = arguments.directory; // Update prompt to reflect directory change From b6e4b37e0409db9ed29b141b6cd90783c8d6d21d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 14:35:06 -0600 Subject: [PATCH 062/118] COMMANDBOX-1335 --- build/build.properties | 2 +- src/cfml/system/util/jline/CommandCompletor.cfc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build.properties b/build/build.properties index c851c707..46f77188 100644 --- a/build/build.properties +++ b/build/build.properties @@ -20,7 +20,7 @@ lucee.config.version=5.2.4.37 jre.version=jdk-11.0.14+9 launch4j.version=3.14 runwar.version=4.7.1-SNAPSHOT -jline.version=3.19.0 +jline.version=3.21.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r diff --git a/src/cfml/system/util/jline/CommandCompletor.cfc b/src/cfml/system/util/jline/CommandCompletor.cfc index e846f984..8034d090 100644 --- a/src/cfml/system/util/jline/CommandCompletor.cfc +++ b/src/cfml/system/util/jline/CommandCompletor.cfc @@ -536,8 +536,8 @@ component singleton { description.len() ? description : nullValue(), // descr nullValue(), // suffix nullValue(), // key - complete//, // complete - //val( sort ) // sort + complete, // complete + val( sort ) // sort ) ); From bbf5619cd1063e9ae65725160e61065283af708f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 3 Feb 2022 15:01:49 -0600 Subject: [PATCH 063/118] Exclude new Log4j deps in Lucee's POM --- build/build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/build.xml b/build/build.xml index 5807b78e..326988b5 100644 --- a/build/build.xml +++ b/build/build.xml @@ -1086,6 +1086,8 @@ External Dependencies: + + From 1d1552ef4bd8d2f82ef457c804920e4b871e6235 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 16 Feb 2022 13:05:52 -0600 Subject: [PATCH 064/118] Lucee RC! --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 46f77188..ff54eb8e 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.66-SNAPSHOT +cfml.version=5.3.9.80-RC cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} From fd93b387ec1c06bb99e70c3e401f6ccd5c940eb0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 16 Feb 2022 14:38:01 -0600 Subject: [PATCH 065/118] RC's must be on maven --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 326988b5..114f6b6e 100644 --- a/build/build.xml +++ b/build/build.xml @@ -1077,7 +1077,7 @@ External Dependencies: - + From 89e49e2305652563c0e2ca2ddf9003f3ef14085d Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 16 Feb 2022 15:05:49 -0600 Subject: [PATCH 066/118] RC isn't avail, use SNAPSHOT --- 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 ff54eb8e..e3be6cc7 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.80-RC +cfml.version=5.3.9.80-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.10 cfml.cli.version=${cfml.loader.version}.${cfml.version} diff --git a/build/build.xml b/build/build.xml index 114f6b6e..326988b5 100644 --- a/build/build.xml +++ b/build/build.xml @@ -1077,7 +1077,7 @@ External Dependencies: - + From 3750a997efc39174c1d739d5478f6bac31391636 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 16 Feb 2022 17:41:37 -0600 Subject: [PATCH 067/118] COMMANDBOX-1431 --- .gitattributes | 1 + src/cfml/system/util/FileSystem.cfc | 24 ++---------------------- src/java/cliloader/LoaderCLIMain.java | 18 ++++++++---------- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/.gitattributes b/.gitattributes index bfc0e45b..ff2f82fb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ # Auto detect text files and perform LF normalization +.sh eol=lf * text=auto # Custom for Visual Studio diff --git a/src/cfml/system/util/FileSystem.cfc b/src/cfml/system/util/FileSystem.cfc index 0be71941..935fbfc5 100644 --- a/src/cfml/system/util/FileSystem.cfc +++ b/src/cfml/system/util/FileSystem.cfc @@ -370,18 +370,9 @@ component accessors="true" singleton { } } - // *nix needs to include first folder due to Lucee bug. - // So /usr/brad/foo.cfc becomes /usr + // On Unix, / is both the drive root and the lucee "webroot" so nothing needs done if( !isWindows() ) { - if( listLen( arguments.absolutePath, '/' ) > 1 ) { - var firstFolder = listFirst( arguments.absolutePath, '/' ); - var path = listRest( arguments.absolutePath, '/' ); - } else { - var firstFolder = ''; - var path = listChangeDelims( arguments.absolutePath, '/', '/' ); - } - var mapping = locateUnixDriveMapping( firstFolder ); - return mapping & '/' & path; + return arguments.absolutePath; } // UNC network path. @@ -420,17 +411,6 @@ component accessors="true" singleton { return mappingName; } - /** - * Accepts a Unix root folder and returns a CF Mapping - * Creates the mapping if it doesn't exist - */ - string function locateUnixDriveMapping( required string rootFolder ) { - var mappingName = '/' & arguments.rootFolder & '_root'; - var mappingPath = '/' & arguments.rootFolder & ( len( arguments.rootFolder ) ? '/' : '' ); - createMapping( mappingName, mappingPath ); - return mappingName; - } - /** * Accepts a Windows UNC network share and returns a CF Mapping * Creates the mapping if it doesn't exist diff --git a/src/java/cliloader/LoaderCLIMain.java b/src/java/cliloader/LoaderCLIMain.java index cd5592b5..f20c68d3 100644 --- a/src/java/cliloader/LoaderCLIMain.java +++ b/src/java/cliloader/LoaderCLIMain.java @@ -286,18 +286,19 @@ && new File( cliArguments.get( 0 ) ).isFile() ) { Security.insertProviderAt( p, 1 ); } ); + // The "webroot" is the drive root where CommandBox's home lives String webroot = Paths.get( uri ).toAbsolutePath().getRoot().toString(); - // On a *nix machine - if( webroot.equals( "/" ) ) { - // Include first folder like /usr/ - webroot += Paths.get( uri ).toAbsolutePath().subpath( 0, 1 ).toString() + "/"; - } // Escape backslash in webroot since replace uses a regular expression + // The bootstrap is the first .cfm file we will cfinclude from the "webroot" String bootstrap = "/" + Paths.get( uri ).toAbsolutePath().toString().replaceFirst( webroot.replace( "\\", "\\\\" ), "" ); - + + // contextroot sets lucee's "webroot" inside the scripting engine to be our drive root + System.setProperty( "lucee.cli.contextRoot", webroot ); + // These next two are the Lucee web context and server context homes System.setProperty( "lucee.web.dir", getLuceeCLIConfigWebDir().getAbsolutePath() ); System.setProperty( "lucee.base.dir", getLuceeCLIConfigServerDir().getAbsolutePath() ); + // A couple tweaks to make Felix faster System.setProperty( "felix.cache.locking", "false" ); System.setProperty( "felix.storage.clean", "none" ); @@ -313,10 +314,7 @@ && new File( cliArguments.get( 0 ) ).isFile() ) { String CFML = "loader = createObject( 'java', 'cliloader.LoaderCLIMain' ); \n" + "if( !isNull( loader.FRTrans ) ) { loader.FRTrans.close(); } \n" + "\n" - + "mappings = getApplicationSettings().mappings; \n" - + " mappings[ '/__commandbox_root/' ] = '" + webroot + "'; \n" - + " application mappings='#mappings#' action='update'; \n" - + " include '/__commandbox_root" + bootstrap.replace( "'", "''" ) + "'; \n"; + + " include '" + bootstrap.replace( "'", "''" ) + "'; \n"; if( debug ) { printStream.println( "" ); From 40f3c9118e16831b877432605d22fb34513c9459 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 17 Feb 2022 16:37:09 -0600 Subject: [PATCH 068/118] COMMANDBOX-1429 --- src/cfml/system/modules/globber/models/Globber.cfc | 13 +++++++++---- .../modules_app/system-commands/commands/dir.cfc | 10 ++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/modules/globber/models/Globber.cfc b/src/cfml/system/modules/globber/models/Globber.cfc index c133e2b9..7044862d 100644 --- a/src/cfml/system/modules/globber/models/Globber.cfc +++ b/src/cfml/system/modules/globber/models/Globber.cfc @@ -241,7 +241,11 @@ component accessors="true" { } 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' ? '/' : '' ) ); + if( row.directory == '/' ) { + return arr.append( row.directory & row.name & ( row.type == 'Dir' ? '/' : '' ) ); + } else { + return arr.append( row.directory & '/' & row.name & ( row.type == 'Dir' ? '/' : '' ) ); + } }, [] ); } } @@ -346,7 +350,6 @@ component accessors="true" { // Strip off the "not found" part var remainingPattern = findUnmatchedPattern( thisPattern, baseDir ) - var dl = directoryList ( listInfo='query', recurse=false, @@ -490,8 +493,10 @@ component accessors="true" { if( baseDir.listLen( '/' ) == 1 && baseDir contains ':' ) { baseDir = baseDir & '/'; } - - baseDir &= '/'; + + if( !baseDir.endsWith( '/' ) ) { + baseDir &= '/'; + } return baseDir; } 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 1cde7c19..c0d4220d 100644 --- a/src/cfml/system/modules_app/system-commands/commands/dir.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/dir.cfc @@ -53,7 +53,10 @@ component aliases="ls,ll,directory" { paths.setPattern( paths.getPatternArray().map( (p) => { if( directoryExists( p ) ){ - return p.listAppend( '*', '/', false ) & ( recurse ? '*' : '' ); + if( !p.endsWith( '/' ) && !p.endsWith( '\' ) ) { + p &= '/'; + } + return p &= '*' & ( recurse ? '*' : '' ); } return p; } ) @@ -62,7 +65,10 @@ component aliases="ls,ll,directory" { excludePaths = excludePaths.listMap( (p) => { p = fileSystemUtil.resolvePath( p ) if( directoryExists( p ) ){ - return p.listAppend( '*', '/', false ) & ( recurse ? '*' : '' ); + if( !p.endsWith( '/' ) && !p.endsWith( '\' ) ) { + p &= '/'; + } + return p &= '*' & ( recurse ? '*' : '' ); } return p; } ); From 54ed9597cb1da96a4fc264762191f18dd9315296 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 21 Feb 2022 12:43:52 -0600 Subject: [PATCH 069/118] COMMANDBOX-1422 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 326988b5..55ef66b4 100644 --- a/build/build.xml +++ b/build/build.xml @@ -730,7 +730,7 @@ External Dependencies: chdir="%OLDPWD%" icon="${src.dir}/resources/box.ico" stayAlive="true"> - + Date: Mon, 21 Feb 2022 17:34:17 -0600 Subject: [PATCH 070/118] COMMANDBOX-1426 --- src/cfml/system/services/PackageService.cfc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 9a5db0dd..b9845e20 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -822,9 +822,16 @@ component accessors="true" singleton { var boxJSON = readPackageDescriptor( arguments.currentWorkingDirectory ); // Get reference to appropriate dependency struct - if( arguments.dev ) { + // Save as dev if we have that flag OR if this is already saved as a dev dep + if( arguments.dev || !isNull( boxJSONRaw.devDependencies[ arguments.packageName ] ) ) { boxJSONRaw[ 'devDependencies' ] = boxJSONRaw.devDependencies ?: {}; boxJSON[ 'devDependencies' ] = boxJSON.devDependencies ?: {}; + + // If this package is also saved as a normal dev, remove it from "dependencies" + if( !isNull( boxJSONRaw.dependencies[ arguments.packageName ] ) ) { + boxJSONRaw.dependencies.delete( arguments.packageName ); + } + var dependenciesRaw = boxJSONRaw.devDependencies; var dependencies = boxJSON.devDependencies; } else { From 18ec76903ed4b3e21d32355c237ca71fe2b51326 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 28 Feb 2022 14:56:34 -0600 Subject: [PATCH 071/118] COMMANDBOX-1414 --- src/cfml/system/services/CommandService.cfc | 148 ++++++++++++++++++-- src/cfml/system/services/ModuleService.cfc | 21 +-- src/cfml/system/services/PackageService.cfc | 12 ++ 3 files changed, 158 insertions(+), 23 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index b7d77726..647e9d38 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -76,9 +76,9 @@ component accessors="true" singleton { /** * Initialize the commands. This will recursively call itself for subdirectories. - * @baseCommandDirectory.hint The starting directory - * @commandDirectory.hint The current directory we've recursed into - * @commandPath.hint The dot-delimited path so far-- only used when recursing + * @baseCommandDirectory The starting directory + * @commandDirectory The current directory we've recursed into + * @commandPath The dot-delimited path so far-- only used when recursing **/ CommandService function initCommands( required string baseCommandDirectory, @@ -105,7 +105,39 @@ component accessors="true" singleton { return this; } + /** + * Remove commands from the CommandService. This will recursively call itself for subdirectories. + * @baseCommandDirectory The starting directory + * @commandDirectory The current directory we've recursed into + * @commandPath The dot-delimited path so far-- only used when recursing + **/ + CommandService function removeCommands( + required string baseCommandDirectory, + string commandDirectory=baseCommandDirectory, + string commandPath='' + ){ + var varDirs = DirectoryList( + path = expandPath( arguments.commandDirectory ), + recurse = false, + listInfo = 'query', + sort = 'type desc, name asc' + ); + + for( var dir in varDirs ){ + // For CFC files, process them as a command + if( dir.type == 'File' && listLast( dir.name, '.' ) == 'cfc' ){ + removeCommand( baseCommandDirectory, dir.name, commandPath ); + // For folders, search them for commands + } else { + removeCommands( baseCommandDirectory, dir.directory & '\' & dir.name, listAppend( commandPath, dir.name, '.' ) ); + } + } + + return this; + } + function addToDictionary( required command, required commandPath ){ + // Build bracketed string of command path to allow special characters var commandPathBracket = ''; var commandName = ''; @@ -121,6 +153,54 @@ component accessors="true" singleton { instance.flattenedCommands[ trim(commandName) ] = command; } + function removeFromDictionary( required command, required commandPath ){ + + // Build bracketed string of command path to allow special characters + var commandPathBracket = ''; + var commandName = ''; + + commandPathArray = listToArray( commandPath, '.' ); + + for( var item in commandPathArray ){ + commandPathBracket &= '[ "#item#" ]'; + commandName &= "#item# "; + } + + // Here in this flat collection for help usage + instance.flattenedCommands.delete( trim(commandName) ); + + if( isDefined( "instance.commands#commandPathBracket#[ '$' ]" ) ) { + evaluate( "structDelete( instance.commands#commandPathBracket#, '$' )" ); + } + + + // Remove from the leaf nodes up, removing any empty namespaces as we go. + // We can't just kill the namespace, because a command that contributes a "server foobar" command would not want to remove the 'server' namespace. + while( commandPathArray.len() ) { + + // If there are other commands in this namespace, we're done + if( evaluate( "structCount( instance.commands#commandPathBracket# )" ) ) { + break; + } + + // If this namespace is empty, pop last item off the array and remove it + var lastItem = commandPathArray.pop(); + + commandPathBracket = ''; + for( var item in commandPathArray ){ + commandPathBracket &= '[ "#item#" ]'; + } + + evaluate( "structDelete( instance.commands#commandPathBracket#, lastItem )" ); + + // We'll keep climbing "up" in our while() until we run out of namespaces, or we reach a namespace that still populated + + } + + + } + + /** * run a command line * @line line to run @@ -162,7 +242,7 @@ component accessors="true" singleton { /** * run a command - * @commandChain.hint the chain of commands to run + * @commandChain the chain of commands to run * @captureOutput Temp workaround to allow capture of run command **/ function runCommand( required array commandChain, required string line, string piped, boolean captureOutput=false ){ @@ -555,8 +635,8 @@ component accessors="true" singleton { /** * Take an array of parameters and parse them out as named or positional - * @parameters.hint The array of params to parse. - * @commandParameters.hint valid params defined by the command + * @parameters The array of params to parse. + * @commandParameters valid params defined by the command **/ function parseParameters( parameters, commandParameters ){ return parser.parseParameters( parameters, commandParameters ); @@ -564,7 +644,7 @@ component accessors="true" singleton { /** * Figure out what command to run based on the user input string - * @line.hint A string containing the command and parameters that the user entered + * @line A string containing the command and parameters that the user entered **/ function resolveCommand( required string line, boolean forCompletion=false ){ // Turn the users input into an array of tokens @@ -575,7 +655,7 @@ component accessors="true" singleton { /** * Figure out what command to run based on the tokenized user input - * @tokens.hint An array containing the command and parameters that the user entered + * @tokens An array containing the command and parameters that the user entered **/ function resolveCommandTokens( required array tokens, string rawLine=tokens.toList( ' ' ), boolean forCompletion=false ){ @@ -875,7 +955,7 @@ component accessors="true" singleton { /** * Takes a struct of command data and lazy loads the actual CFC instance if necessary - * @commandData.hint Struct created by registerCommand() + * @commandData Struct created by registerCommand() **/ private function lazyLoadCommandCFC( commandData ){ @@ -909,7 +989,7 @@ component accessors="true" singleton { /** * Looks at the call stack to determine if we're currently "inside" a command. * Useful to prevent endless recursion. - * @command.hint Name of the command to look for as typed from the shell. If empty, returns true for any command + * @command Name of the command to look for as typed from the shell. If empty, returns true for any command **/ function inCommand( command='' ){ @@ -955,9 +1035,9 @@ component accessors="true" singleton { /** * load command CFC - * @baseCommandDirectory.hint The base directory for this command - * @cfc.hint CFC name that represents the command - * @commandPath.hint The relative dot-delimited path to the CFC starting in the commands dir + * @baseCommandDirectory The base directory for this command + * @cfc CFC name that represents the command + * @commandPath The relative dot-delimited path to the CFC starting in the commands dir **/ private function registerCommand( baseCommandDirectory, CFC, commandPath ){ @@ -995,6 +1075,48 @@ component accessors="true" singleton { } } + /** + * Remove a command from memory + * @baseCommandDirectory The base directory for this command + * @cfc CFC name that represents the command + * @commandPath The relative dot-delimited path to the CFC starting in the commands dir + **/ + private function removeCommand( baseCommandDirectory, CFC, commandPath ){ + + // Strip cfc extension from filename + var CFCName = mid( CFC, 1, len( CFC ) - 4 ); + var commandName = iif( len( commandPath ), de( commandPath & '.' ), '' ) & CFCName; + // Build CFC's path + var fullCFCPath = baseCommandDirectory & '.' & commandName; + + + try { + // Create a nice struct of command metadata + var commandData = createCommandData( fullCFCPath, commandName ); + // This will catch nasty parse errors so the shell can keep loading + } catch( any e ){ + shell.printString( 'Error loading command data [#fullCFCPath#]#cr#' ); + logger.error( 'Error loading command data [#fullCFCPath#]. #e.message# #e.detail ?: ''#', e.stackTrace ); + // pretty print the exception + shell.printError( e ); + return; + } + + // must be CommandBox CFC, can't be Application.cfc + if( CFCName == 'Application' || !isCommandCFC( commandData ) ){ + return; + } + + // Add it to the command dictionary + removeFromDictionary( commandData, commandPath & '.' & CFCName ); + + // Register the aliases + for( var alias in commandData.aliases ){ + // Alias is allowed to be anything. This means it may even overwrite another command already loaded. + removeFromDictionary( commandData, listChangeDelims( trim( alias ), '.', ' ' ) ); + } + } + /** * Create command metadata * @fullCFCPath the full CFC path diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index 9a3f9c96..48428d39 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -491,11 +491,6 @@ } } - // Register module routing entry point pre-pended to routes - /*if( shell.settingExists( 'sesBaseURL' ) AND len( mConfig.entryPoint ) AND NOT find( ":", mConfig.entryPoint ) ){ - interceptorService.getInterceptor( "SES", true ).addModuleRoutes( pattern=mConfig.entryPoint, module=arguments.moduleName, append=false ); - }*/ - // Call on module configuration object onLoad() if found if( structKeyExists( instance.mConfigCache[ arguments.moduleName ], "onLoad" ) ){ instance.mConfigCache[ arguments.moduleName ].onLoad(); @@ -580,6 +575,8 @@ // Check if module is loaded? if( NOT structKeyExists(getModuleData(),arguments.moduleName) ){ return false; } + var modules = getModuleData(); + var mConfig = modules[ arguments.moduleName ]; @@ -608,11 +605,6 @@ // Unregister Config object interceptorService.unregister( "ModuleConfig:#arguments.moduleName#" ); - // Remove SES if enabled. - /*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() ) { @@ -622,11 +614,20 @@ } ConfigService.setPossibleConfigSettings( possibleConfigSettings ); + // Register commands if they exist + if( directoryExists( mconfig.commandsPhysicalPath ) ){ + var commandPath = '/' & replace( mconfig.commandsInvocationPath, '.', '/', 'all' ); + CommandService.removeCommands( commandPath ); + } + // Remove configuration structDelete( getModuleData(), arguments.moduleName ); // Remove Configuration object from Cache structDelete( instance.mConfigCache, arguments.moduleName ); + + // Remove from module registry + structDelete( instance.moduleRegistry, arguments.moduleName ); //After unloading a module interception interceptorService.announceInterception( "postModuleUnload", iData ); diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index b9845e20..97eeb8ae 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -763,6 +763,18 @@ component accessors="true" singleton { // uninstall the package if( len( uninstallDirectory ) && directoryExists( uninstallDirectory ) ) { + + // If this package is being uninstalled anywhere south of the CommandBox system folder, unload the module first + if( fileSystemUtil.normalizeSlashes( uninstallDirectory ).startsWith( fileSystemUtil.normalizeSlashes( expandPath( '/commandbox' ) ) ) && fileExists( uninstallDirectory & '/ModuleConfig.cfc' ) ) { + consoleLogger.warn( 'Unloading module...' ); + try { + moduleService.unload( uninstallDirectory.listLast( '/\' ) ); + } catch( any e ) { + job.addErrorLog( 'Error Unloading module: ' & e.message & ' ' & e.detail ); + logger.error( '#e.message# #e.detail#' , e.stackTrace ); + } + } + // Catch this to gracefully handle where the OS or another program // has the folder locked. try { From bd8cb3303f345c60d0cceaeca251f125f6ad665f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 28 Feb 2022 17:25:51 -0600 Subject: [PATCH 072/118] COMMANDBOX-1432 --- src/cfml/system/BaseCommand.cfc | 8 +++--- src/cfml/system/Shell.cfc | 11 +++++++- src/cfml/system/services/CommandService.cfc | 29 ++++++++++++++++----- src/cfml/system/util/Watcher.cfc | 2 +- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/cfml/system/BaseCommand.cfc b/src/cfml/system/BaseCommand.cfc index 898e7f6a..2fc576e0 100644 --- a/src/cfml/system/BaseCommand.cfc +++ b/src/cfml/system/BaseCommand.cfc @@ -221,15 +221,15 @@ component accessors="true" singleton { function error( required message, detail='', clearPrintBuffer=false, exitCode=1 ) { wirebox.getInstance( "ConsolePainter" ).stop( message ); - print.line().toConsole(); + + if( !getSystemSetting( 'box_currentCommandPiped', false ) ) { + print.line().toConsole(); + } setExitCode( arguments.exitCode ); if( arguments.clearPrintBuffer ) { // 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", errorcode=arguments.exitCode ); } diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index b1953576..0ddb1fd8 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -805,7 +805,7 @@ component accessors="true" singleton { ConsolePainter.forceStop(); - printError( { message : e.message, detail: e.detail } ); + printError( { message : e.message, detail: e.detail, extendedInfo : e.extendedInfo ?: '' } ); } // This type of error means the user hit Ctrl-C, during a readLine() call. Duck out and move along. } catch (any e) { @@ -900,6 +900,13 @@ component accessors="true" singleton { setExitCode( 1 ); } + if( !isNull( err.extendedInfo ) && isJSON( err.extendedInfo ) ){ + var info = deserializeJSON( err.extendedInfo ); + if( info.keyExists( 'commandOutput' ) ) { + variables.reader.getTerminal().writer().print( info.commandOutput ); + } + } + var verboseErrors = true; try{ verboseErrors = configService.getSetting( 'verboseErrors', false ); @@ -912,6 +919,8 @@ component accessors="true" singleton { variables.logger.error( '#arguments.err.message# #arguments.err.detail ?: ''#', arguments.err.stackTrace ?: '' ); + variables.reader.getTerminal().writer().println(); + variables.reader.getTerminal().writer().println(); variables.reader.getTerminal().writer().print( variables.print.whiteOnRedLine( 'ERROR (#variables.version#)' ) ); variables.reader.getTerminal().writer().println(); variables.reader.getTerminal().writer().println( variables.print.boldRedText( variables.formatterUtil.HTML2ANSI( arguments.err.message, 'boldRed' ) ) ); diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 647e9d38..67b55c05 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -430,10 +430,11 @@ component accessors="true" singleton { interceptorService.announceInterception( 'preCommand', { commandInfo=commandInfo, parameterInfo=parameterInfo } ); // Run the command - var result = commandInfo.commandReference.CFC.run( argumentCollection = parameterInfo.namedParameters ); + var result = commandInfo.commandReference.CFC.run( argumentCollection = parameterInfo.namedParameters ); lastCommandErrored = commandInfo.commandReference.CFC.hasError(); } catch( any e ){ + FRTransService.errorTransaction( FRTrans, e.getPageException() ); lastCommandErrored = true; // If this command didn't already set a failing exit code... @@ -448,26 +449,42 @@ component accessors="true" singleton { } - // Dump out anything the command had printed so far var result = commandInfo.commandReference.CFC.getResult(); - if( len( result ) ){ - shell.printString( result & cr ); + // Add the command output thus far into the exception + if( len( result ) ) { + var originalInfo = e.extendedInfo + e.extendedInfo=serializeJSON( { + 'extendedInfo'=originalInfo, + 'commandOutput'=result + } ); } + // This is a little hacky, but basically if there are more commands in the chain that need to run, // just print an exception and move on. Otherwise, throw so we can unwrap the call stack all the way // back up. That is necessary for command expressions that fail like "echo `cat noExists.txt`" // since in that case I don't want to execute the "echo" command since the "cat" failed. if( arrayLen( commandChain ) > i && listFindNoCase( '||,;', commandChain[ i+1 ].originalLine ) ) { + + // Dump out anything the command had printed so far + if( len( result ) ){ + shell.printString( result & cr ); + } + // These are "expected" exceptions like validation errors that can be "pretty" if( e.type.toString() == 'commandException' ) { - shell.printError( { message : e.message, detail: e.detail } ); + shell.printError( { message : e.message, detail: e.detail, extendedInfo : e.extendedInfo ?: '' } ); // These are catastrophic errors that warrant a full stack trace. } else { shell.printError( e ); } // Unwind the stack to the closest catch } else { - rethrow; + + if( !captureOutput && len( result ) ) { + // Dump out anything the command had printed so far + shell.printString( result & cr ); + } + throw e; } } finally { // Remove it from the stack diff --git a/src/cfml/system/util/Watcher.cfc b/src/cfml/system/util/Watcher.cfc index ed2b5bed..92248933 100644 --- a/src/cfml/system/util/Watcher.cfc +++ b/src/cfml/system/util/Watcher.cfc @@ -139,7 +139,7 @@ component accessors=true { } // Handle "expected" exceptions from commands } catch( commandException e ) { - shell.printError( { message : e.message, detail: e.detail } ); + shell.printError( { message : e.message, detail: e.detail, extendedInfo : e.extendedInfo ?: '' } ); print .line() From c3d95bdc0f722f04bb57b8192605b4518e0cb717 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Mon, 28 Feb 2022 17:30:35 -0600 Subject: [PATCH 073/118] COMMANDBOX-1433 --- build/build.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build.properties b/build/build.properties index e3be6cc7..b1326416 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,14 +12,14 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.9.80-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.10 +cfml.loader.version=2.6.11 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org lucee.config.version=5.2.4.37 jre.version=jdk-11.0.14+9 launch4j.version=3.14 -runwar.version=4.7.1-SNAPSHOT +runwar.version=4.7.2-SNAPSHOT jline.version=3.21.0 jansi.version=2.3.2 jgit.version=5.11.0.202103091610-r From 1771a179928e822bb77955438e55071188a3cc7f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 1 Mar 2022 11:48:10 -0600 Subject: [PATCH 074/118] COMMANDBOX-1414 --- src/cfml/system/services/CommandService.cfc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index 67b55c05..006498a2 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -166,6 +166,11 @@ component accessors="true" singleton { commandName &= "#item# "; } + // This happens if a command is registered twice and we've already removed it + if( !isDefined( "instance.commands#commandPathBracket#" ) ) { + return; + } + // Here in this flat collection for help usage instance.flattenedCommands.delete( trim(commandName) ); From 29c4f15d53254db3ebc7478f8665a9317df4fd9e Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 1 Mar 2022 15:48:17 -0600 Subject: [PATCH 075/118] Use custom log4j file COMMANDBOX-1415 --- build/build.xml | 3 ++- src/java/cliloader/LoaderCLIMain.java | 3 ++- src/resources/log4j2.xml | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 src/resources/log4j2.xml diff --git a/build/build.xml b/build/build.xml index 55ef66b4..d3c1fa80 100644 --- a/build/build.xml +++ b/build/build.xml @@ -382,9 +382,9 @@ External Dependencies: + - @@ -394,6 +394,7 @@ External Dependencies: + @@ -625,9 +641,6 @@ // Remove Configuration object from Cache structDelete( instance.mConfigCache, arguments.moduleName ); - - // Remove from module registry - structDelete( instance.moduleRegistry, arguments.moduleName ); //After unloading a module interception interceptorService.announceInterception( "postModuleUnload", iData ); diff --git a/src/cfml/system/services/PackageService.cfc b/src/cfml/system/services/PackageService.cfc index 1514f0a5..d333071e 100644 --- a/src/cfml/system/services/PackageService.cfc +++ b/src/cfml/system/services/PackageService.cfc @@ -30,7 +30,7 @@ component accessors="true" singleton { property name='tempDir' inject='tempDir@constants'; property name='serverService' inject='serverService'; property name='moduleService' inject='moduleService'; - + /** * Constructor @@ -99,7 +99,7 @@ component accessors="true" singleton { arguments.production = arguments.production ?: true; var endpointData = endpointService.resolveEndpoint( arguments.ID, arguments.currentWorkingDirectory ); - + job.start( 'Installing package [#endpointData.ID#]', ( shell.getTermHeight() < 20 ? 1 : 5 ) ); if( verbose ) { @@ -385,7 +385,7 @@ component accessors="true" singleton { if( !serverDetails.serverIsNew && !(serverInfo.engineName contains 'lucee') ) { job.addWarnLog( "We did find a server, but the engine is [#serverInfo.engineName#] instead of 'lucee'" ); } - + } } @@ -624,10 +624,10 @@ component accessors="true" singleton { consoleLogger.warn( 'Activating your new module for instant use...' ); moduleService.registerAndActivateModule( installDirectory.listLast( '/\' ), fileSystemUtil.makePathRelative( installDirectory ).listToArray( '/\' ).slice( 1, -1 ).toList( '.' ) ); } - + interceptorService.announceInterception( 'postInstall', { installArgs=arguments, installDirectory=installDirectory } ); job.complete( verbose ); - + return true; } @@ -768,7 +768,7 @@ component accessors="true" singleton { if( fileSystemUtil.normalizeSlashes( uninstallDirectory ).startsWith( fileSystemUtil.normalizeSlashes( expandPath( '/commandbox' ) ) ) && fileExists( uninstallDirectory & '/ModuleConfig.cfc' ) ) { consoleLogger.warn( 'Unloading module...' ); try { - moduleService.unload( uninstallDirectory.listLast( '/\' ) ); + moduleService.unloadAndUnregisterModule( uninstallDirectory.listLast( '/\' ) ); // Heavy-handed workaround for the fact that the module service does not unload // WireBox mappings for this module so they stay in memory wirebox.getCacheBox().getCache( 'metadataCache' ).clearAll(); @@ -841,12 +841,12 @@ component accessors="true" singleton { if( arguments.dev || !isNull( boxJSONRaw.devDependencies[ arguments.packageName ] ) ) { boxJSONRaw[ 'devDependencies' ] = boxJSONRaw.devDependencies ?: {}; boxJSON[ 'devDependencies' ] = boxJSON.devDependencies ?: {}; - + // If this package is also saved as a normal dev, remove it from "dependencies" if( !isNull( boxJSONRaw.dependencies[ arguments.packageName ] ) ) { boxJSONRaw.dependencies.delete( arguments.packageName ); } - + var dependenciesRaw = boxJSONRaw.devDependencies; var dependencies = boxJSON.devDependencies; } else { @@ -908,7 +908,7 @@ component accessors="true" singleton { arguments.installDirectory = right( arguments.installDirectory, len( arguments.installDirectory ) - 1 ); } } - + var existingInstallPath = ''; if( installPaths.keyExists( arguments.packageName ) ) { existingInstallPath = fileSystemUtil.normalizeSlashes( fileSystemUtil.resolvePath( installPaths[ arguments.packageName ], arguments.currentWorkingDirectory ) ); @@ -920,7 +920,7 @@ component accessors="true" singleton { if( len( existingInstallPath ) && existingInstallPath.left( 1 ) == '/' ) { existingInstallPath = right( existingInstallPath, len( existingInstallPath ) - 1 ); } - } + } } // Just in case-- an empty install dir would be useless. @@ -1177,7 +1177,7 @@ component accessors="true" singleton { // Verify outdated dependency graph in parallel structEach( tree.dependencies, fOutdatedCheck, true ); - + return aAllDependencies; } From bdc986b03f26a132db5021733f8df7c6c36e3954 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 1 Apr 2022 14:57:10 -0500 Subject: [PATCH 098/118] COMMANDBOX-1451 --- src/cfml/system/Shell.cfc | 2 +- .../system-commands/commands/printTable.cfc | 4 +++- src/cfml/system/services/ConfigService.cfc | 1 + src/cfml/system/util/Print.cfc | 6 +++-- src/cfml/system/util/TablePrinter.cfc | 24 ++++++++++++------- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/cfml/system/Shell.cfc b/src/cfml/system/Shell.cfc index da63cc70..0fcff103 100644 --- a/src/cfml/system/Shell.cfc +++ b/src/cfml/system/Shell.cfc @@ -439,7 +439,7 @@ component accessors="true" singleton { * Get's terminal width **/ function getTermWidth() { - return variables.reader.getTerminal().getWidth(); + return configService.getSetting( "terminalWidth", variables.reader.getTerminal().getWidth() ); } /** diff --git a/src/cfml/system/modules_app/system-commands/commands/printTable.cfc b/src/cfml/system/modules_app/system-commands/commands/printTable.cfc index 1509d87e..041f5e41 100644 --- a/src/cfml/system/modules_app/system-commands/commands/printTable.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/printTable.cfc @@ -109,13 +109,15 @@ component { * @includedHeaders A list of headers to include. * @headerNames An list/array of column headers to use instead of the default specifically for array of arrays * @debug Only print out the names of the columns and the first row values + * @width Override the terminal width */ public string function run( required any data=[], any includedHeaders="", any headerNames="", - boolean debug=false + boolean debug=false, + width=-1 ) { // Treat input as a potential file path diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index 3ab47044..c3892d22 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -74,6 +74,7 @@ component accessors="true" singleton { 'nonInteractiveShell', 'tabCompleteInline', 'colorInDumbTerminal', + 'terminalWidth', // JSON 'JSON.indent', 'JSON.lineEnding', diff --git a/src/cfml/system/util/Print.cfc b/src/cfml/system/util/Print.cfc index 8fb7b0f7..03f8f2c7 100644 --- a/src/cfml/system/util/Print.cfc +++ b/src/cfml/system/util/Print.cfc @@ -103,7 +103,7 @@ component { if( isJSON( toString( text ) ) ) { text = formatterUtil.formatJson( json=toString( text ), ANSIColors=JSONService.getANSIColors() ); } - + } else if( isArray( text ) || isStruct( text ) || isQuery( text ) ) { text = serializeJSON( text, 'struct' ); text = formatterUtil.formatJson( json=text, ANSIColors=JSONService.getANSIColors() ); @@ -292,12 +292,14 @@ component { * @includedHeaders A list of headers to include. Used for query inputs * @headerNames An list/array of column headers to use instead of the default * @debug Only print out the names of the columns and the first row values + * @width Override the terminal width */ function table( required any data=[], any includedHeaders="", any headerNames="", - boolean debug=false + boolean debug=false, + width=-1 ){ return tablePrinter.print( argumentCollection=arguments ); } diff --git a/src/cfml/system/util/TablePrinter.cfc b/src/cfml/system/util/TablePrinter.cfc index 7476b0a8..a7edf8ca 100644 --- a/src/cfml/system/util/TablePrinter.cfc +++ b/src/cfml/system/util/TablePrinter.cfc @@ -43,18 +43,20 @@ component { * @includedHeaders A list of headers to include. Used for query inputs * @headerNames An list/array of column headers to use instead of the default * @debug Only print out the names of the columns and the first row values + * @width Override the terminal width */ public string function print( required any data=[], any includedHeaders="", any headerNames="", - boolean debug=false + boolean debug=false, + width=-1 ) { arguments.headerNames = isArray( arguments.headerNames ) ? arrayToList( arguments.headerNames ) : arguments.headerNames; var dataQuery = isQuery( arguments.data ) ? arguments.data : convert.toQuery( arguments.data, arguments.headerNames ); - + // Check for // printTable [] // printTable [{}] @@ -68,13 +70,13 @@ component { columns.listEach( (c)=> { c = trim( c ); // This expression will either evaluate to true or throw an exception - listFindNoCase( dataQuery.columnList, c ) + listFindNoCase( dataQuery.columnList, c ) || c == '*' || throw( message='Header name [#c#] not found.', detail='Valid header names are [#dataQuery.columnList#]', type='commandException' ); } ); dataQuery = queryExecute('SELECT #columns# FROM dataQuery',[],{ dbType : 'query' }); - + // Extract data in array of structs var dataRows = convert.queryToArrayOfOrderedStructs( dataQuery ); @@ -93,7 +95,7 @@ component { } dataRows = autoFormatData( dataHeaders, dataRows ); - dataHeaders = processHeaders( dataHeaders, dataRows, headerNames.listToArray() ) + dataHeaders = processHeaders( dataHeaders, dataRows, headerNames.listToArray(), width ) printHeader( dataHeaders ); printData( dataRows, dataHeaders ); @@ -111,10 +113,14 @@ component { public array function processHeaders( required array headers, required array data, - headerNames=[] + headerNames=[], + width=-1 ) { var headerData = arguments.headers.map( ( header, index ) => calculateColumnData( index, header, data, headerNames ), true ); - var termWidth = shell.getTermWidth()-1; + var termWidth = arguments.width; + if( termWidth <= 0 ) { + termWidth = shell.getTermWidth()-1; + } if( termWidth <= 0 ) { termWidth = 100; } @@ -163,7 +169,7 @@ component { // This happens if the first column is still so big it won't fit and the while loop above never entered if( totalWidth == 1 ) { // Cut down that one column so it fits - headerData[1].maxWidth=termWidth-11 + headerData[1].maxWidth=max( termWidth-11, 3) } } @@ -406,7 +412,7 @@ component { return '[#data.getClass().getName()#]'; } } - + function cellHasFormattingEmbedded( data ) { return isStruct( data ) && data.count() == 2 && data.keyExists( 'options' ) && data.keyExists( 'value' ) && isSimpleValue( data.options ); } From a6c29cea7be32c6933ffb2521616a833162df3cf Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 1 Apr 2022 15:17:31 -0500 Subject: [PATCH 099/118] COMMANDBOX-1414 --- src/cfml/system/services/CommandService.cfc | 50 +++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/cfml/system/services/CommandService.cfc b/src/cfml/system/services/CommandService.cfc index c141da9e..f8e727cf 100644 --- a/src/cfml/system/services/CommandService.cfc +++ b/src/cfml/system/services/CommandService.cfc @@ -158,50 +158,50 @@ component accessors="true" singleton { // Build bracketed string of command path to allow special characters var commandPathBracket = ''; var commandName = ''; - + commandPathArray = listToArray( commandPath, '.' ); for( var item in commandPathArray ){ commandPathBracket &= '[ "#item#" ]'; commandName &= "#item# "; } - + // This happens if a command is registered twice and we've already removed it if( !isDefined( "instance.commands#commandPathBracket#" ) ) { return; } - + // Here in this flat collection for help usage instance.flattenedCommands.delete( trim(commandName) ); - + if( isDefined( "instance.commands#commandPathBracket#[ '$' ]" ) ) { evaluate( "structDelete( instance.commands#commandPathBracket#, '$' )" ); } - // Remove from the leaf nodes up, removing any empty namespaces as we go. + // Remove from the leaf nodes up, removing any empty namespaces as we go. // We can't just kill the namespace, because a command that contributes a "server foobar" command would not want to remove the 'server' namespace. while( commandPathArray.len() ) { - + // If there are other commands in this namespace, we're done if( evaluate( "structCount( instance.commands#commandPathBracket# )" ) ) { break; } - + // If this namespace is empty, pop last item off the array and remove it var lastItem = commandPathArray.pop(); - - commandPathBracket = ''; + + commandPathBracket = ''; for( var item in commandPathArray ){ commandPathBracket &= '[ "#item#" ]'; } - + evaluate( "structDelete( instance.commands#commandPathBracket#, lastItem )" ); - + // We'll keep climbing "up" in our while() until we run out of namespaces, or we reach a namespace that still populated - + } - + } @@ -278,7 +278,7 @@ component accessors="true" singleton { previousCommandSeparator = commandInfo.originalLine; continue; } - + if( previousCommandSeparator == '&&' && lastCommandErrored ) { continue; return result ?: ''; @@ -439,11 +439,11 @@ component accessors="true" singleton { interceptorService.announceInterception( 'preCommand', { commandInfo=commandInfo, parameterInfo=parameterInfo } ); // Run the command - var result = commandInfo.commandReference.CFC.run( argumentCollection = parameterInfo.namedParameters ); + var result = commandInfo.commandReference.CFC.run( argumentCollection = parameterInfo.namedParameters ); lastCommandErrored = commandInfo.commandReference.CFC.hasError(); } catch( any e ){ - + FRTransService.errorTransaction( FRTrans, e.getPageException() ); lastCommandErrored = true; // If this command didn't already set a failing exit code... @@ -468,18 +468,18 @@ component accessors="true" singleton { 'commandOutput'=result } ); } - + // This is a little hacky, but basically if there are more commands in the chain that need to run, // just print an exception and move on. Otherwise, throw so we can unwrap the call stack all the way // back up. That is necessary for command expressions that fail like "echo `cat noExists.txt`" // since in that case I don't want to execute the "echo" command since the "cat" failed. if( arrayLen( commandChain ) > i && listFindNoCase( '||,;', commandChain[ i+1 ].originalLine ) ) { - + // Dump out anything the command had printed so far if( len( result ) ){ shell.printString( result & cr ); } - + // These are "expected" exceptions like validation errors that can be "pretty" if( e.type.toString() == 'commandException' ) { shell.printError( { message : e.message, detail: e.detail, extendedInfo : e.extendedInfo ?: '' } ); @@ -489,14 +489,14 @@ component accessors="true" singleton { } // Unwind the stack to the closest catch } else { - + if( !captureOutput && len( result ) ) { // Dump out anything the command had printed so far shell.printString( result & cr ); // If we're printing it now, remove it from the exception so the shell doesn't double-print it. e.extendedInfo=originalInfo; - - } + + } throw e; } } finally { @@ -1145,6 +1145,8 @@ component accessors="true" singleton { // Alias is allowed to be anything. This means it may even overwrite another command already loaded. removeFromDictionary( commandData, listChangeDelims( trim( alias ), '.', ' ' ) ); } + var mappingName = "command-" & fullCFCPath; + wirebox.getScope( 'singleton' ).getSingletons().delete( mappingName ); } /** @@ -1296,8 +1298,8 @@ component accessors="true" singleton { var newPath = originalPath.listMap( (p) => { p = fileSystemUtil.resolvePath( p ); // The globber won't match a dir if you include the trailing slash, so pull them off - // This allows - // > rm tests/ + // This allows + // > rm tests/ // or // > touch tests // to affect the "tests" folder itself From 3e335518811fec39c4f557c7eee6e09e4e06093f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 5 Apr 2022 11:45:37 -0500 Subject: [PATCH 100/118] Track installs from artifacts --- src/cfml/system/endpoints/ForgeBox.cfc | 9 ++++++++ src/cfml/system/util/ForgeBox.cfc | 29 -------------------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 005b34a9..2f1f3128 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -51,6 +51,15 @@ component accessors="true" implements="IEndpointInteractive" { job.addLog( "Package found in local artifacts!"); // Install the package var thisArtifactPath = artifactService.getArtifactPath( slug, version ); + + try { + var APIToken = getAPIToken(); + forgeBox.recordInstall( slug, version, APIToken ); + } catch( forgebox var e ) { + job.addLog( e.message ); + job.addLog( e.detail ); + } + // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); } else { diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index a8806637..4dbfe53f 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -355,35 +355,6 @@ or just add DEBUG to the root logger return results.response.data; } - /** - * Tracks a download - */ - function recordDownload( - required string slug, - string version, - string APIToken='' ) { - - var thisResource = "install/#arguments.slug#"; - if( len( arguments.version ) ) { - thisResource &= "/#arguments.version#"; - } - - var results = makeRequest( - resource=thisResource, - method='post', - headers = { - 'x-api-token' : arguments.APIToken - } ); - - // error - if( results.response.error ){ - throw( "Something went wrong tracking this download from #getEndpointName()#.", 'forgebox', arrayToList( results.response.messages ) ); - } - - return results.response.data; - } - - /** * Autocomplete for slugs */ From 791173fc9739d5a46703bd9ce434aeb069e54e2f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 6 Apr 2022 09:13:40 -0500 Subject: [PATCH 101/118] COMMANDBOX-1452 --- src/cfml/system/services/ModuleService.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cfml/system/services/ModuleService.cfc b/src/cfml/system/services/ModuleService.cfc index 366a7305..ca2ff7fb 100644 --- a/src/cfml/system/services/ModuleService.cfc +++ b/src/cfml/system/services/ModuleService.cfc @@ -696,9 +696,9 @@ 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 ); + oConfig.injectPropertyMixin( "getSystemSetting", ()=>systemSettings.getSystemSetting(argumentCollection=arguments) ); + oConfig.injectPropertyMixin( "getSystemProperty", ()=>systemSettings.getSystemProperty(argumentCollection=arguments) ); + oConfig.injectPropertyMixin( "getEnv", ()=>systemSettings.getEnv(argumentCollection=arguments) ); // Configure the module oConfig.configure(); From 435ef8ef5146a68796df6810c51c8a16f7f4dfaa Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 6 Apr 2022 14:37:17 -0500 Subject: [PATCH 102/118] COMMANDBOX-1453 --- src/cfml/system/endpoints/CFLib.cfc | 6 ++++++ src/cfml/system/endpoints/Git.cfc | 6 ++++++ src/cfml/system/endpoints/HTTP.cfc | 6 ++++++ src/cfml/system/endpoints/Jar.cfc | 6 ++++++ src/cfml/system/endpoints/Java.cfc | 6 ++++++ src/cfml/system/endpoints/Lex.cfc | 6 ++++++ src/cfml/system/endpoints/S3.cfc | 6 ++++++ .../system/modules_app/system-commands/commands/upgrade.cfc | 6 +++++- src/cfml/system/services/ConfigService.cfc | 1 + src/cfml/system/util/ForgeBox.cfc | 4 ++++ src/cfml/system/util/ProgressableDownloader.cfc | 4 ++++ 11 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/endpoints/CFLib.cfc b/src/cfml/system/endpoints/CFLib.cfc index ac423f5f..cc9971a9 100644 --- a/src/cfml/system/endpoints/CFLib.cfc +++ b/src/cfml/system/endpoints/CFLib.cfc @@ -17,6 +17,7 @@ component accessors="true" implements="IEndpoint" singleton { property name="progressBar" inject="ProgressBar"; property name="CR" inject="CR@constants"; property name='wirebox' inject='wirebox'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -27,6 +28,11 @@ component accessors="true" implements="IEndpoint" singleton { } public string function resolvePackage( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance( 'interactiveJob' ); var folderName = tempDir & '/' & 'temp#createUUID()#'; var fullPath = folderName & '/' & package & '.cfm'; diff --git a/src/cfml/system/endpoints/Git.cfc b/src/cfml/system/endpoints/Git.cfc index 613b8399..5fb94eaf 100644 --- a/src/cfml/system/endpoints/Git.cfc +++ b/src/cfml/system/endpoints/Git.cfc @@ -34,6 +34,7 @@ component accessors="true" implements="IEndpoint" singleton { property name='wirebox' inject='wirebox'; property name="semanticVersion" inject="provider:semanticVersion@semver"; property name='semverRegex' inject='semverRegex@constants'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -44,6 +45,11 @@ component accessors="true" implements="IEndpoint" singleton { } public string function resolvePackage( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t clone [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance( 'interactiveJob' ); var GitURL = replace( arguments.package, '//', '' ); GitURL = getProtocol() & GitURL; diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index 85e4297d..f155d9d8 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -20,6 +20,7 @@ component accessors=true implements="IEndpoint" singleton { property name='wirebox' inject='wirebox'; property name="semanticVersion" inject="provider:semanticVersion@semver"; property name='semverRegex' inject='semverRegex@constants'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -39,6 +40,11 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackageZip( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance( 'interactiveJob' ); var fileName = 'temp#createUUID()#.zip'; diff --git a/src/cfml/system/endpoints/Jar.cfc b/src/cfml/system/endpoints/Jar.cfc index bd2ba96b..2fd25893 100644 --- a/src/cfml/system/endpoints/Jar.cfc +++ b/src/cfml/system/endpoints/Jar.cfc @@ -19,6 +19,7 @@ component accessors=true implements="IEndpoint" singleton { property name='JSONService' inject='JSONService'; property name='wirebox' inject='wirebox'; property name='S3Service' inject='S3Service'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -30,6 +31,11 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackage( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance( 'interactiveJob' ); var folderName = tempDir & '/' & 'temp#createUUID()#'; var fullJarPath = folderName & '/' & getDefaultName( package ) & '.jar'; diff --git a/src/cfml/system/endpoints/Java.cfc b/src/cfml/system/endpoints/Java.cfc index 3fcd20d8..b2a8e793 100644 --- a/src/cfml/system/endpoints/Java.cfc +++ b/src/cfml/system/endpoints/Java.cfc @@ -36,6 +36,7 @@ component accessors=true implements="IEndpoint" singleton { property name='filesystemUtil' inject='fileSystem'; property name="folderEndpoint" inject="commandbox.system.endpoints.Folder"; property name="PackageService" inject="packageService"; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -46,6 +47,11 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackage( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var lockVersion = false; if( package.right( 12 ) == ':lockVersion' ) { var lockVersion = true; diff --git a/src/cfml/system/endpoints/Lex.cfc b/src/cfml/system/endpoints/Lex.cfc index aae58355..8eae652f 100644 --- a/src/cfml/system/endpoints/Lex.cfc +++ b/src/cfml/system/endpoints/Lex.cfc @@ -18,6 +18,7 @@ component accessors=true implements="IEndpoint" singleton { property name='JSONService' inject='JSONService'; property name='wirebox' inject='wirebox'; property name='S3Service' inject='S3Service'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -28,6 +29,11 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackage( required string package, boolean verbose=false ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance( 'interactiveJob' ); var folderName = tempDir & '/' & 'temp#createUUID()#'; var fullLexPath = folderName & '/' & getDefaultName( package ) & '.lex'; diff --git a/src/cfml/system/endpoints/S3.cfc b/src/cfml/system/endpoints/S3.cfc index a50c566d..f5ddf402 100644 --- a/src/cfml/system/endpoints/S3.cfc +++ b/src/cfml/system/endpoints/S3.cfc @@ -20,6 +20,7 @@ component accessors="true" implements="IEndpoint" singleton { property name='wirebox' inject='wirebox'; property name="semanticVersion" inject="provider:semanticVersion@semver"; property name='semverRegex' inject='semverRegex@constants'; + property name='configService' inject='configService'; // Properties property name="namePrefixes" type="string"; @@ -30,6 +31,11 @@ component accessors="true" implements="IEndpoint" singleton { } public string function resolvePackage(required string package, boolean verbose=false) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); + } + var job = wirebox.getInstance('interactiveJob'); var fileName = 'temp#createUUID()#.zip'; 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 7d476cc7..60ad5a0f 100644 --- a/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc +++ b/src/cfml/system/modules_app/system-commands/commands/upgrade.cfc @@ -34,7 +34,11 @@ component { * @force.hint Force the update even if the version on the server is the same as locally **/ function run( boolean latest, boolean force=false ) { - + + if( configService.getSetting( 'offlineMode', false ) ) { + error( 'Can''t check for updates, CommandBox is in offline mode. Go online with [config set offlineMode=false].' ); + } + if( isNull( arguments.latest ) ) { if( semanticVersion.isPreRelease( shell.getVersion() ) ) { print diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index c3892d22..9de9a9b8 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -88,6 +88,7 @@ component accessors="true" singleton { 'verboseErrors', 'debugNativeExecution', 'developerMode', + 'offlineMode', // Task Runners 'taskCaching' ]); diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 4dbfe53f..7c998cf5 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -428,6 +428,10 @@ or just add DEBUG to the root logger + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t access #getEndpointName()# resource [#resource#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'forgebox' ); + } + var results = {error=false,response={},message="",responseheader={},rawResponse=""}; var HTTPResults = ""; var param = ""; diff --git a/src/cfml/system/util/ProgressableDownloader.cfc b/src/cfml/system/util/ProgressableDownloader.cfc index 8cba4ed5..6bee7e8d 100644 --- a/src/cfml/system/util/ProgressableDownloader.cfc +++ b/src/cfml/system/util/ProgressableDownloader.cfc @@ -25,6 +25,10 @@ component singleton { required string destinationFile, any statusUDF, any redirectUDF='' ) { + + if( configService.getSetting( 'offlineMode', false ) ) { + throw( 'Can''t download [#downloadURL#], CommandBox is in offline mode. Go online with [config set offlineMode=false].' ); + } var data = getByteArray( 1024 ); var total = 0; From 7c31dcd31393a2cb1fed5411c6c580edcb2ca10a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 6 Apr 2022 14:40:40 -0500 Subject: [PATCH 103/118] COMMANDBOX-1454 --- src/cfml/system/endpoints/ForgeBox.cfc | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 2f1f3128..b273c2db 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -52,13 +52,7 @@ component accessors="true" implements="IEndpointInteractive" { // Install the package var thisArtifactPath = artifactService.getArtifactPath( slug, version ); - try { - var APIToken = getAPIToken(); - forgeBox.recordInstall( slug, version, APIToken ); - } catch( forgebox var e ) { - job.addLog( e.message ); - job.addLog( e.detail ); - } + recordInstall( slug, version ); // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); @@ -512,12 +506,7 @@ component accessors="true" implements="IEndpointInteractive" { job.addLog( "Installing version [#arguments.version#]." ); - try { - forgeBox.recordInstall( arguments.slug, arguments.version, APIToken ); - } catch( forgebox var e ) { - job.addLog( e.message ); - job.addLog( e.detail ); - } + recordInstall( arguments.slug, arguments.version ); var packageType = entryData.typeSlug; @@ -586,7 +575,7 @@ component accessors="true" implements="IEndpointInteractive" { throw( e.message, 'endpointException', e.detail ); } - job.addErrorLog( "Aww man, #getNamePrefixes()# ran into an issue."); + job.addErrorLog( "Aww man, #getNamePrefixes()# ran into an issue."); job.addLog( "#e.message# #e.detail#" ); job.addErrorLog( "We're going to look in your local artifacts cache and see if one of those versions will work."); @@ -598,6 +587,8 @@ component accessors="true" implements="IEndpointInteractive" { job.addLog( "Sweet! We found a local version of [#satisfyingVersion#] that we can use in your artifacts."); job.addLog( "" ); + recordInstall( arguments.slug, satisfyingVersion ); + var thisArtifactPath = artifactService.getArtifactPath( slug, satisfyingVersion ); // Defer to file endpoint return fileEndpoint.resolvePackage( thisArtifactPath, arguments.verbose ); @@ -715,5 +706,15 @@ component accessors="true" implements="IEndpointInteractive" { } } + function recordInstall( slug, version ) { + var job = wirebox.getInstance( 'interactiveJob' ); + try { + forgeBox.recordInstall( arguments.slug, arguments.version, getAPIToken() ); + } catch( forgebox var e ) { + job.addErrorLog( e.message ); + job.addErrorLog( e.detail ); + } + } + } From b493b4e6580e4bee692d11c11de81423a933fe24 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 6 Apr 2022 16:58:39 -0500 Subject: [PATCH 104/118] COMMANDBOX-1454 --- src/cfml/system/endpoints/ForgeBox.cfc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index b273c2db..acb6ed8d 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -23,6 +23,7 @@ component accessors="true" implements="IEndpointInteractive" { property name="fileEndpoint" inject="commandbox.system.endpoints.File"; property name="lexEndpoint" inject="commandbox.system.endpoints.Lex"; property name='wirebox' inject='wirebox'; + property name='logger' inject='logbox:logger:{this}'; // Properties property name="namePrefixes" type="string"; @@ -707,12 +708,12 @@ component accessors="true" implements="IEndpointInteractive" { } function recordInstall( slug, version ) { - var job = wirebox.getInstance( 'interactiveJob' ); - try { - forgeBox.recordInstall( arguments.slug, arguments.version, getAPIToken() ); - } catch( forgebox var e ) { - job.addErrorLog( e.message ); - job.addErrorLog( e.detail ); + thread name="#createUUID()#" slug="#arguments.slug#", version="#arguments.version#" { + try { + var foo = forgeBox.recordInstall( attributes.slug, attributes.version, getAPIToken() ); + } catch( any e ) { + logger.error( 'Error recording install', e ) + } } } From 3c8fdb9cd1e633beb3f0c83307d5604432896a9a Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Fri, 8 Apr 2022 13:33:21 -0500 Subject: [PATCH 105/118] COMMANDBOX-1455 --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index f263e659..2e9e6a98 100644 --- a/build/build.properties +++ b/build/build.properties @@ -19,7 +19,7 @@ lucee.version=${cfml.version} lucee.config.version=5.2.4.37 jre.version=jdk-11.0.14+9 launch4j.version=3.14 -runwar.version=4.7.2-SNAPSHOT +runwar.version=4.7.3-SNAPSHOT jline.version=3.21.0 jansi.version=2.3.2 jgit.version=5.13.0.202109080827-r From 0913db93ce81fe5b2ebd8bb4ee910a55fc0fdefb Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 8 Apr 2022 16:21:59 -0500 Subject: [PATCH 106/118] =?UTF-8?q?=F0=9F=93=A6=20NEW:=20This=20adds=20the?= =?UTF-8?q?=20ability=20to=20forward=20ALL=20arguments=20from=20the=20test?= =?UTF-8?q?box=20watch=20command=20to=20the=20testbox=20run=20command=20so?= =?UTF-8?q?=20it=20can=20be=20more=20explicit.=20(#308)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cfml/system/modules/jmespath/.gitignore | 1 - .../commands/testbox/watch.cfc | 34 ++++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 src/cfml/system/modules/jmespath/.gitignore diff --git a/src/cfml/system/modules/jmespath/.gitignore b/src/cfml/system/modules/jmespath/.gitignore deleted file mode 100644 index 279c4557..00000000 --- a/src/cfml/system/modules/jmespath/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/testbox/ \ 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 090028e1..1b9475ad 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 @@ -43,6 +43,12 @@ component { * @bundles The path or list of paths of the spec bundle CFCs to run and test * @labels The list of labels that a suite or spec must have in order to execute. * @verbose Display extra details including passing and skipped tests. + * @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. + * @options Add adhoc URL options to the runner as options:name=value options:name2=value2 + * @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! **/ function run( string paths, @@ -50,10 +56,16 @@ component { directory, bundles, labels, - boolean verbose + boolean verbose, + boolean recurse, + string reporter, + struct options={}, + string testBundles, + string testSuites, + string testSpecs ){ // Get testbox options from package descriptor - var boxOptions = packageService.readPackageDescriptor( getCWD() ).testbox; + var boxOptions = variables.packageService.readPackageDescriptor( getCWD() ).testbox; var getOptionsWatchers = function(){ // Return to List @@ -72,22 +84,6 @@ component { // Tabula rasa command( "cls" ).run(); - // Prepare test args - var testArgs = {}; - - if ( !isNull( arguments.verbose ) ) { - testArgs.verbose = arguments.verbose; - } - if ( !isNull( arguments.directory ) ) { - testArgs.directory = arguments.directory; - } - if ( !isNull( arguments.bundles ) ) { - testArgs.bundles = arguments.bundles; - } - if ( !isNull( arguments.labels ) ) { - testArgs.labels = arguments.labels; - } - // Start watcher watch() .paths( globbingPaths.listToArray() ) @@ -101,7 +97,7 @@ component { try { // Run the tests in the target directory command( "testbox run" ) - .params( argumentCollection = testArgs ) + .params( argumentCollection = arguments ) .inWorkingDirectory( getCWD() ) .run(); } catch ( commandException var e ) { From 53af97689d7e82d84d27d78871179228717e2b39 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Tue, 12 Apr 2022 09:44:26 -0400 Subject: [PATCH 107/118] Always pass tray icon for macOS Dock to use --- src/cfml/system/services/ServerService.cfc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 20047130..7dcb4d3f 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -129,7 +129,7 @@ component accessors="true" singleton { 'trayicon' : d.trayicon ?: '', // Duplicate so onServerStart interceptors don't actually change config settings via reference. 'trayOptions' : duplicate( d.trayOptions ?: [] ), - // Only default this on for Windows-- off for Linux and Mac due to crap unfixed bugs in the + // Only default this on for Windows-- off for Linux and Mac due to crap unfixed bugs in the // upstream Java library. https://github.com/dorkbox/SystemTray/issues/119 'trayEnable' : d.trayEnable ?: fileSystemUtil.isWindows(), 'dockEnable' : d.dockEnable ?: true, @@ -1400,12 +1400,12 @@ component accessors="true" singleton { return parser.replaceEscapedChars( parser.removeEscapedChars( parser.unwrapQuotes( i ) ) ); }), true ); - args.append( serverInfo.runwarArgsArray, true ); + args.append( serverInfo.runwarArgsArray, true ) + // Despite the name, the MacOS Dock also uses this setting. + .append( '--tray-icon' ).append( serverInfo.trayIcon ); if( serverInfo.trayEnable ) { - args - .append( '--tray-icon' ).append( serverInfo.trayIcon ) - .append( '--tray-config' ).append( serverInfo.trayOptionsFile ) + args.append( '--tray-config' ).append( serverInfo.trayOptionsFile ); } if( serverInfo.runwarXNIOOptions.count() ) { From 6514826c3f931f1a488839ce0a60096b86f27d0f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 12 Apr 2022 10:42:03 -0400 Subject: [PATCH 108/118] Only pass non-null values to the watcher, else they create havoc on the testbox run command. --- .../modules_app/testbox-commands/commands/testbox/watch.cfc | 5 +++-- 1 file changed, 3 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 1b9475ad..53fcb9cd 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 @@ -84,7 +84,8 @@ component { // Tabula rasa command( "cls" ).run(); - // Start watcher + // Start watcher with passed args only. + var testArgs = arguments.filter( (k,v) => !isNull( v ) ); watch() .paths( globbingPaths.listToArray() ) .inDirectory( getCWD() ) @@ -97,7 +98,7 @@ component { try { // Run the tests in the target directory command( "testbox run" ) - .params( argumentCollection = arguments ) + .params( argumentCollection = testArgs ) .inWorkingDirectory( getCWD() ) .run(); } catch ( commandException var e ) { From 2ccb067d11e845d5409ef19da0db6cc5b3263dd0 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 27 Apr 2022 13:21:01 -0500 Subject: [PATCH 109/118] COMMANDBOX-1456 --- src/cfml/system/services/ConfigService.cfc | 2 +- src/cfml/system/services/JSONService.cfc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/services/ConfigService.cfc b/src/cfml/system/services/ConfigService.cfc index 9de9a9b8..d8e9c2af 100644 --- a/src/cfml/system/services/ConfigService.cfc +++ b/src/cfml/system/services/ConfigService.cfc @@ -199,7 +199,7 @@ component accessors="true" singleton { return variables.configSettings; } - // env var/system property overrides which we want to keep seperate so we don't write them back to the JSON file. + // env var/system property overrides which we want to keep separate so we don't write them back to the JSON file. return JSONService.mergeData( duplicate( variables.configSettings ), getConfigSettingOverrides() ); } diff --git a/src/cfml/system/services/JSONService.cfc b/src/cfml/system/services/JSONService.cfc index 5a094f78..b6fe8e3d 100644 --- a/src/cfml/system/services/JSONService.cfc +++ b/src/cfml/system/services/JSONService.cfc @@ -120,7 +120,7 @@ component accessors="true" singleton { } // structs } else { - targetProperty.append( complexValue, true ); + mergeData( targetProperty, complexValue ); } results.append( '#propertyValue# appended to #prop#' ); continue; From 1ee75bbc25288fa18f7b636bb83059612bb1d9d2 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 27 Apr 2022 13:37:25 -0500 Subject: [PATCH 110/118] COMMANDBOX-1457 --- src/cfml/system/services/ServerService.cfc | 2 +- src/cfml/system/util/SystemSettings.cfc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 7dcb4d3f..34382d8e 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -314,7 +314,7 @@ component accessors="true" singleton { loadOverrides( serverJSON, serverInfo, serverProps.verbose ?: serverJSON.verbose ?: defaults.verbose ?: false ); // Load up our fully-realized server.json-specific env vars into CommandBox's environment - systemSettings.setDeepSystemSettings( serverDetails.serverJSON.env ?: {}, '' ); + systemSettings.setDeepSystemSettings( serverDetails.serverJSON.env ?: {}, '', '_' ); interceptorService.announceInterception( 'preServerStart', { serverDetails=serverDetails, serverProps=serverProps, serverInfo=serverDetails.serverInfo, serverJSON=serverDetails.serverJSON, defaults=defaults } ); diff --git a/src/cfml/system/util/SystemSettings.cfc b/src/cfml/system/util/SystemSettings.cfc index e10d75f2..78fecf06 100644 --- a/src/cfml/system/util/SystemSettings.cfc +++ b/src/cfml/system/util/SystemSettings.cfc @@ -241,14 +241,14 @@ component singleton { * * @dataStructure A string, struct, or array. Initial value should be a struct. */ - function setDeepSystemSettings( any dataStructure, string prefix='interceptData' ) { + function setDeepSystemSettings( any dataStructure, string prefix='interceptData', delim='.' ) { // If it's a struct... if( isStruct( dataStructure ) && !isObject( dataStructure ) ) { // Loop over and process each key for( var key in dataStructure ) { if( key != 'COMMANDREFERENCE' ) { - setDeepSystemSettings( dataStructure[ key ] ?: '', prefix.listAppend( key, '.' ) ); + setDeepSystemSettings( dataStructure[ key ] ?: '', prefix.listAppend( key, delim ), delim ); } } // If it's an array... @@ -257,7 +257,7 @@ component singleton { // Loop over and process each index for( var item in dataStructure ) { i++; - setDeepSystemSettings( item ?: '', prefix & '[#i#]' ); + setDeepSystemSettings( item ?: '', prefix & '[#i#]', delim ); } // If it's a string... } else if ( isSimpleValue( dataStructure ) ) { From 840f35984e82e4c5831257d8944682e3c091469f Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Wed, 27 Apr 2022 14:07:41 -0500 Subject: [PATCH 111/118] COMMANDBOX-1458 --- .../modules_app/package-commands/commands/package/init.cfc | 7 +++---- 1 file changed, 3 insertions(+), 4 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 7ed40702..d9b4f881 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 @@ -56,13 +56,12 @@ component aliases="init" { return; } + var endpointName = arguments.endpointName ?: configService.getSetting( 'endpoints.defaultForgeBoxEndpoint', 'forgebox' ); + // Clean this up so it doesn't get written as a property structDelete( arguments, "wizard" ); - var endpointName = arguments.endpointName; structDelete( arguments, "endpointName" ); - - endpointName = endpointName ?: configService.getSetting( 'endpoints.defaultForgeBoxEndpoint', 'forgebox' ); - + try { var oEndpoint = endpointService.getEndpoint( endpointName ); } catch( EndpointNotFound var e ) { From 2800f7704aef8c0f087b9f0907886b436c655ff5 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 22:57:00 -0500 Subject: [PATCH 112/118] COMMANDBOX-1459 --- src/cfml/system/services/ServerService.cfc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cfml/system/services/ServerService.cfc b/src/cfml/system/services/ServerService.cfc index 34382d8e..3bfad0d5 100644 --- a/src/cfml/system/services/ServerService.cfc +++ b/src/cfml/system/services/ServerService.cfc @@ -1373,6 +1373,13 @@ component accessors="true" singleton { // Add java agent if( len( trim( javaAgent ) ) ) { argTokens.append( javaagent ); } + // TODOL Temp stopgap for Java regression that prevents Undertow from starting. + // https://issues.redhat.com/browse/UNDERTOW-2073 + // https://bugs.openjdk.java.net/browse/JDK-8285445 + if( !argTokens.filter( (a)=>a contains 'jdk.io.File.enableADS' ).len() ) { + argTokens.append( '-Djdk.io.File.enableADS=true' ); + } + args .append( '-jar' ).append( serverInfo.runwarJarPath ) .append( '--background=#background#' ) From 8967c29e12f3cdf6f12b1a5d43076d8e15da1634 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 22:57:18 -0500 Subject: [PATCH 113/118] Latest java and undertow --- build/build.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build.properties b/build/build.properties index 2e9e6a98..7cad2fcb 100644 --- a/build/build.properties +++ b/build/build.properties @@ -12,14 +12,14 @@ java.debug=true dependencies.dir=${basedir}/lib cfml.version=5.3.9.116-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 -cfml.loader.version=2.6.15 +cfml.loader.version=2.6.16 cfml.cli.version=${cfml.loader.version}.${cfml.version} lucee.version=${cfml.version} # Don't bump this version. Need to remove this dependency from cfmlprojects.org lucee.config.version=5.2.4.37 -jre.version=jdk-11.0.14+9 +jre.version=jdk-11.0.15+10 launch4j.version=3.14 -runwar.version=4.7.3-SNAPSHOT +runwar.version=4.7.4 jline.version=3.21.0 jansi.version=2.3.2 jgit.version=5.13.0.202109080827-r From 9d24511d7bf65e3a745bc5016cccd7b9525eb7b6 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 23:10:28 -0500 Subject: [PATCH 114/118] Move to Adoptium --- build/build.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/build.xml b/build/build.xml index d3c1fa80..5365c44e 100644 --- a/build/build.xml +++ b/build/build.xml @@ -819,7 +819,7 @@ External Dependencies: - @@ -837,7 +837,7 @@ External Dependencies: - @@ -852,7 +852,7 @@ External Dependencies: - @@ -867,7 +867,7 @@ External Dependencies: - From 78511b495f7690d1b07ae9598d960f6b2f70dedf Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 23:24:28 -0500 Subject: [PATCH 115/118] no build 15 for 32 bit win --- build/build.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/build.xml b/build/build.xml index 5365c44e..b451e574 100644 --- a/build/build.xml +++ b/build/build.xml @@ -845,17 +845,17 @@ External Dependencies: - + Windows x32 JRE found! Windows x32 JRE not found, downloading artifact - + - - + @@ -880,7 +880,7 @@ External Dependencies: - + From c06e02dde694b5009c9889b2ce3eb9c8eaece83c Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 23:31:34 -0500 Subject: [PATCH 116/118] Missed one --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index b451e574..bbca43ef 100644 --- a/build/build.xml +++ b/build/build.xml @@ -880,7 +880,7 @@ External Dependencies: - + From 1b76e6c05fed9c9203837acc4de78f65bc102dd1 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 23:43:43 -0500 Subject: [PATCH 117/118] Bump to final Lucee --- build/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.properties b/build/build.properties index 7cad2fcb..299b4719 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,7 +10,7 @@ java.debug=true #dependencies dependencies.dir=${basedir}/lib -cfml.version=5.3.9.116-SNAPSHOT +cfml.version=5.3.9.133-SNAPSHOT cfml.extensions=8D7FB0DF-08BB-1589-FE3975678F07DB17 cfml.loader.version=2.6.16 cfml.cli.version=${cfml.loader.version}.${cfml.version} From 1c6a64efa81323197a26e4540279c7e253897460 Mon Sep 17 00:00:00 2001 From: Brad Wood Date: Thu, 28 Apr 2022 23:56:30 -0500 Subject: [PATCH 118/118] Final bump for 5.5.0 --- build/build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build.xml b/build/build.xml index bbca43ef..bdc0d7cd 100644 --- a/build/build.xml +++ b/build/build.xml @@ -16,8 +16,8 @@ External Dependencies: - - + +