diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1eb91dd..bcf46a6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,7 +4,7 @@ on:
pull_request:
jobs:
ci:
- name: CI for Pirate
+ name: CI for Preside CommandBox Commands
runs-on: ubuntu-latest
steps:
- name: Setup flow variables
@@ -12,7 +12,7 @@ jobs:
branch=${GITHUB_REF##*/}
publish=false
if [[ "{{ env.event.name }}" != "pull_request" ]] ; then
- if [[ $branch == v* ]] ; then
+ if [[ $branch == release-* ]] || [[ $branch == v* ]] ; then
publish=true
fi
fi
@@ -39,7 +39,7 @@ jobs:
- name: Zip project
if: "env.PUBLISH == 'true'"
- run: zip -rq $ZIP_FILE * -x *.log
+ run: zip -rq $ZIP_FILE * -x jmimemagic.log -x .* -x *.sh -x *.log -x tests/**\*
shell: bash
env:
ZIP_FILE: ${{ steps.versiongen.outputs.semver_release_number }}.zip
@@ -51,7 +51,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- tag_name: ${{ github.ref }}
+ tag_name: ${{ steps.versiongen.outputs.semver_release_string }}
release_name: Release ${{ steps.versiongen.outputs.semver_release_string }}
draft: false
prerelease: ${{ steps.versiongen.outputs.semver_release_is_snapshot }}
@@ -81,4 +81,4 @@ jobs:
uses: pixl8/github-action-box-publish@v3
with:
forgebox_user: ${{ secrets.FORGEBOX_USER }}
- forgebox_pass: ${{ secrets.FORGEBOX_PASS }}
+ forgebox_pass: ${{ secrets.FORGEBOX_PASS }}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e05c06b..d1fae95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 7.0.0
+
+Rewrite of core commands to bring up to date with latest changes and approaches from Commandbox. We now use cfconfig
+for `preside server start` and have resolved the issues with datasource prompts overlapping Commandbox text
+
## 6.1.6
* Fix for broken paths in Gruntfile generated for new extension command when choosing to manage static assets with grunt
diff --git a/_resources/lucee-web.xml.cfm b/_resources/lucee-web.xml.cfm
deleted file mode 100644
index 92f8f38..0000000
--- a/_resources/lucee-web.xml.cfm
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${datasource}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/commands/preside/new/site.cfc b/commands/preside/new/site.cfc
index 24097fc..e3833b0 100644
--- a/commands/preside/new/site.cfc
+++ b/commands/preside/new/site.cfc
@@ -8,6 +8,7 @@ component {
property name="wirebox" inject="wirebox";
property name="forgeBox" inject="ForgeBox";
+
/**
* @skeleton.hint The name of the app skeleton to use. Options: basic, nocms
**/
@@ -15,29 +16,31 @@ component {
var directory = shell.pwd();
var templates = _getSkeletonTemplates();
- while( arguments.skeleton == "" ) {
+ if ( !Len( arguments.skeleton ) ) {
print.yellowLine( "Looking up available skeletons from forgebox.io... (hint: register a template by adding a forgebox package matching the pattern, 'preside-skeleton-*')" );
- print.line();
-
+ print.line().toConsole();
+
if ( templates.isEmpty() ) {
print.line( "" );
print.redLine( "No preside skeleton templates could be found! Ensure you are online and that https://www.forgebox.io is up and running." );
print.line( "" );
- }
+ } else {
+ var options = [];
+ var i=0;
+ for( var templateId in templates ) {
+ var template = templates[ templateId ];
- print.line( "" );
- print.line( "Available skeleton templates from which to build your new site/application:" );
- print.line( "" );
- for( var templateId in templates ) {
- print.text( " * " );
- print.yellowText( "#templateId#" );
- print.line( ": #templates[ templateId ].description#" );
- }
- print.line( "" );
+ ArrayAppend( options, {
+ value = templateId
+ , display = template.name & ( template.official ? " (OFFICIAL)" : " (by #template.author#)" ) & ": " & template.description
+ , accessKey = ++i
+ } );
+ }
+
+ arguments.skeleton = multiselect( "Choose a skeleton template to use: " ).options( options ).required().ask();
+
+ print.line( "" );
- arguments.skeleton = ask( "Enter the skeleton template to use: " );
- if ( !templates.keyExists( arguments.skeleton ) ) {
- arguments.skeleton = "";
}
}
@@ -102,15 +105,31 @@ component {
private struct function _getSkeletonTemplates() {
var templates = {};
var forgeboxEntries = forgebox.getEntries( typeSlug = "preside-skeletons" );
+ var official = [ "preside-skeleton-basic", "preside-skeleton-webapp" ];
+ var ordered = StructNew( "linked" );
for( var entry in forgeboxEntries.results ) {
templates[ entry.slug.replace( "preside-skeleton-", "" ) ] = {
name = entry.title
, description = entry.summary
, package = entry.slug
+ , author = entry.user.fullName ?: "unknown"
+ , official = ArrayFindNoCase( official, entry.slug )
};
}
- return templates;
+ if ( StructKeyExists( templates, "basic" ) ) {
+ ordered[ "basic" ] = templates.basic;
+ }
+ if ( StructKeyExists( templates, "basic" ) ) {
+ ordered[ "webapp" ] = templates.webapp;
+ }
+ for( var key in templates ) {
+ if ( !ArrayFind( [ "basic", "webapp" ], key ) ) {
+ ordered[ key ] = templates[ key ];
+ }
+ }
+
+ return ordered;
}
}
diff --git a/commands/preside/start.cfc b/commands/preside/start.cfc
index 47610f9..6e8f921 100644
--- a/commands/preside/start.cfc
+++ b/commands/preside/start.cfc
@@ -1,12 +1,11 @@
/**
- * Start a PresideCMS server
+ * Start a Preside Application server. This is proxy to server start
+ * with some specific cfconfig configuration for Preside.
**/
component {
- property name="serverService" inject="ServerService";
- property name="interceptorService" inject="interceptorService";
- property name="commandboxHomeDirectory" inject="HomeDir@constants";
- property name="interactive" default=true;
+ property name="interceptorService" inject="interceptorService";
+ property name="moduleService" inject="moduleService";
/**
* @port.hint port number
@@ -22,25 +21,29 @@ component {
function run(
String directory = ""
, Numeric heapSize = 1024
- , Boolean saveSettings = false
, Boolean interactive = true
- , Numeric port
- , Boolean openbrowser
- , String name
- , Numeric stopPort
- , Boolean force
- , Boolean debug
+ , String serverConfigFile = "server.json"
, String trayIcon
){
+ if ( !moduleService.isModuleActive( "commandbox-cfconfig") ) {
+ print.redLine( "=================================================================" );
+ print.redLine( "CRITICAL ERROR: cfconfig not installed/enabled." );
+ print.redLine( "The preside start command relies on cfconfig to persist settings." );
+ print.line();
+ print.redLine( "Either:" );
+ print.redLine( "1. Ensure CommandBox is up to date (comes with cfconfig)" );
+ print.redLine( "2. Install cfconfig separately: box install commandbox-cfconfig" );
+ print.redLine( "=================================================================" ).toConsole();
+ return;
+ }
var serverProps = arguments;
- var resourceDir = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "/../../_resources";
var osInfo = CreateObject("java", "java.lang.System").getProperties();
+ var resourceDir = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "/../../_resources";
- serverProps.directory = fileSystemUtil.resolvePath( arguments.directory );
- serverProps.name = serverProps.name is "" ? listLast( serverProps.directory, "\/" ) : serverProps.name;
- serverProps.rewritesEnable = true;
- serverProps.rewritesConfig = serverProps.directory & "/urlrewrite.xml";
- this.interactive = arguments.interactive;
+ serverProps.directory = fileSystemUtil.resolvePath( arguments.directory );
+ serverProps.saveSettings = true;
+ serverProps.rewritesEnable = true;
+ serverProps.rewritesConfig = serverProps.rewritesConfig ?: ( serverProps.directory & "/urlrewrite.xml" );
if ( !serverProps.keyExists( "trayIcon" ) ) {
if ( osInfo['os.name'].findNoCase( "Mac OS" ) || osInfo['os.name'].findNoCase( "Linux" ) ) {
@@ -50,161 +53,133 @@ component {
}
}
- interceptorService.registerInterceptor( this );
- serverService.start( serverProps=serverProps );
- }
+ _ensureCfConfigSetup( argumentCollection=serverProps );
- function onServerStart( event, interceptData ) {
- _prepareDirectories( interceptData.serverInfo ?: {} );
- }
-
- /**
- * Private method to setup the web config directories with Preside specific configuration
- *
- */
- private void function _prepareDirectories( required struct serverInfo ) {
- var webConfigDir = serverInfo.webConfigDir;
-
- if ( webConfigDir.startsWith( "/WEB-INF" ) ) {
- webConfigDir = ( serverInfo.serverHomeDirectory ?: "" ) & webConfigDir;
+ if ( serverProps.directory == fileSystemUtil.resolvePath( "" ) ) {
+ StructDelete( serverProps, "directory" );
}
- var presideServerDir = webConfigDir & "/preside";
- var resourceDir = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "/../../_resources";
- var presideInitedFile = webConfigDir & "/.presideinitialized";
-
- if ( !FileExists( presideInitedFile ) ) {
- if ( !DirectoryExists( webConfigDir ) ) {
- DirectoryCreate( webConfigDir, false, true );
-
- var sourceWebConfigDirectory = commandBoxHomeDirectory & "/engine/cfml/cli/cfml-web";
- if ( !DirectoryExists( sourceWebConfigDirectory ) ) {
- print.line();
- print.redLine("*************************************************************************************************************************************************************************");
- print.redLine("Could not find server files. Please ensure you have the latest version of CommandBox. Expected to find files at [#sourceWebConfigDirectory#]");
- print.redLine("*************************************************************************************************************************************************************************");
- print.line();
+ interceptorService.registerInterceptor( this );
- return {};
- }
+ command( "server start" ).params( argumentCollection=serverProps ).run();
+ }
- DirectoryCopy( sourceWebConfigDirectory, webConfigDir, true );
+ public void function onServerStart( interceptData ) {
+ var path = interceptData.serverInfo.webroot;
+ var rootAppCfc = path.listAppend( "application/config/Config.cfc", "/" );
+
+ if ( FileExists( rootAppCfc ) ) {
+ var regPattern = ".*\bsettings\.preside_admin_path\s*=\s*[""'](.*?)[""'].*";
+ var adminPath = ReReplaceNoCase( FileRead( rootAppCfc ), regPattern, "\1" );
+
+ if ( Len( adminPath ) ) {
+ interceptData.serverInfo.trayOptions = interceptData.serverInfo.trayOptions ?: [];
+ ArrayInsertAt( interceptData.serverInfo.trayOptions, ArrayLen( interceptData.serverInfo.trayOptions ), {
+ "label":"Preside",
+ "items": [
+ { 'label':'Site Home', 'action':'openbrowser', 'url': interceptData.serverInfo.openbrowserURL },
+ { 'label':'Site Admin', 'action':'openbrowser', 'url': '#interceptData.serverInfo.openbrowserURL#/#adminPath#/' }
+ ],
+ "image" : ""
+ } );
}
- var presideLocation = _setupPresideLocation( webConfigDir, serverInfo.webroot );
- var datasource = this.interactive ? _setupDatasource() : "";
-
- var luceeWebXml = FileRead( resourceDir & "/lucee-web.xml.cfm" );
- luceeWebXml = ReplaceNoCase( luceeWebXml, "${presideLocation}", presideLocation );
- luceeWebXml = ReplaceNoCase( luceeWebXml, "${datasource}", datasource );
- FileWrite( webConfigDir & "/lucee-web.xml.cfm", luceeWebXml );
- FileWrite( webConfigDir & "/lucee-web.xml.cfm", luceeWebXml );
- FileWrite( presideInitedFile, "" );
}
}
- private string function _setupPresideLocation( required string webConfigDir, required string webroot ) {
- var presideLocation = arguments.webroot.reReplace( "[\\/]$", "" ) & "/preside";
+ private function _ensureCfConfigSetup() {
+ var cfconfigFilePath = _getCfConfigFilePath( argumentCollection=arguments );
- if ( FileExists( presideLocation & "/system/Bootstrap.cfc" ) ) {
- print.line().toConsole();
- print.yellowLine( "Using Preside location [#presideLocation#]..." ).toConsole();
- print.line().toConsole();
+ print.line( "Checking/creating your cfconfig file at: [#cfconfigFilePath#]..." );
+ print.line( "NOTE: this is used to set Preside specific configuration and save your datasource. You should almost certainly ensure that this file is NOT commited to version control." ).toConsole();
+ print.line( " You can also consult the CFConfig documentation to use this file to control other aspects of your Commandbox server." ).toConsole();
- return presideLocation;
+ if ( !FileExists( cfconfigFilePath ) ) {
+ FileWrite( cfconfigFilePath, "{}" );
}
- if ( !this.interactive ) {
- return "";
- }
+ var cfconfig = DeserializeJson( FileRead( cfconfigFilePath ) );
- print.line().toConsole();
- print.yellowLine( "PresideCMS core installation" ).toConsole();
- print.yellowLine( "============================" ).toConsole();
- print.line().toConsole();
+ if ( !Len( Trim( cfconfig.datasources.preside.database ?: "" ) ) ) {
+ cfconfig[ "datasources" ] = cfconfig.datasources ?: {};
+ cfconfig.datasources[ "preside" ] = _setupDatasource( argumentCollection=arguments );
- print.line().toConsole();
- var useLocalVersion = shell.ask( "Install fresh version of Preside [Y/n]? " ) == "n";
- if ( useLocalVersion ) {
- print.line().toConsole();
- presideLocation = shell.ask( "Enter the path to Preside: " );
- while( !DirectoryExists( presideLocation ) || !FileExists( presideLocation & "/system/Bootstrap.cfc" ) ) {
- print.redLine( "The path you entered is not a valid Preside path!").toConsole();
- presideLocation = shell.ask( "Enter the path to Preside: " );
- }
+ print.linLine( " " );
+ print.greenLine( "Thank you! If you have any issues with your datasource, you can configure in [#cfconfigFilePath#]" ).toConsole();
+ }
- } else {
- var validVersion = false;
- var presideVersion = "";
-
- while ( !validVersion ) {
- validVersion = true;
-
- print.line().toConsole();
- while( ![ "s", "b" ].findNoCase( presideVersion ) ) {
- presideVersion = shell.ask( "Which version of preside do you wish to install, (S)table or (B)leeding edge? [(S)/b]:" );
- if ( !Len( Trim( presideVersion ) ) ) {
- presideVersion = "s";
- }
- }
- presideLocation = "http://downloads.presidecms.com/presidecms/" & ( presideVersion == "b" ? "bleeding-edge.zip" : "release.zip" );
-
- var presideZip = GetTempDirectory() & "/PresideCMS.zip";
- try {
- print.line()
- .yellowLine( "Downloading Preside from [#presideLocation#]... please be patient" ).toConsole();
- http getasBinary=true file=presideZip url=presideLocation throwOnError=true;
- } catch ( any e ) {
- validVersion = false;
- print.redLine( "Invalid preside version [#presideVersion#]. No download found at [#presideLocation#]." ).toConsole();
- }
- }
+ cfconfig[ "templateCharset" ] = cfconfig.templateCharset ?: "UTF-8";
+ cfconfig[ "webCharset" ] = cfconfig.webCharset ?: "UTF-8";
+ cfconfig[ "resourceCharset" ] = cfconfig.resourceCharset ?: "UTF-8";
+ cfconfig[ "resourceCharset" ] = cfconfig.resourceCharset ?: "UTF-8";
+ cfconfig[ "dotNotationUpperCase" ] = false;
- print.yellowLine( "Download complete. Installing to [#arguments.webConfigDir#/preside]..." ).toConsole();
+ FileWrite( cfconfigFilePath, formatterUtil.formatJson( cfconfig ) );
- zip action="unzip" file="#presideZip#" destination=arguments.webConfigDir & "/preside";
+ print.line()
+ print.line( "Checks complete. Starting your server now..." ).toConsole();
+ }
+
+ private string function _getCfConfigFilePath() {
+ var serverConfPath = arguments.directory & arguments.serverConfigFile;
+ if ( !FileExists( serverConfPath ) ) {
+ FileWrite( serverConfPath, formatterUtil.formatJson( { "web"={ "webroot"=arguments.directory }} ) );
+ }
+ var serverConf = SerializeJson( FileRead( serverConfPath ) );
+ var possibleKeys = [ "file", "server", "web" ];
+ var relFilePath = "";
- var subDirs = DirectoryList( arguments.webConfigDir & "/preside", false, "query" );
- var versionDir = "";
- for( var subDir in subDirs ){
- if ( subDir.type == "Dir" && ReFindNoCase( "^presidecms-[0-9\.]+$", subDir.name ) ) {
- versionDir = "/#subDir.name#";
- break;
- }
+ for( var key in possibleKeys ) {
+ if ( Len( serverConfig.cfconfig[ key ] ?: "" ) ) {
+ relFilePath = serverConfig.cfconfig[ key ];
}
+ }
+
+ if ( !Len( relFilePath ) && Len( serverConfig.cfconfigFile ?: "" ) ) {
+ relFilePath = serverConfig.cfconfigFile;
+ }
+
+ if ( !Len( relFilePath ) ) {
+ relFilePath = ".cfconfig.json";
+ serverConfig[ "cfconfig" ] = serverConfig[ "cfconfig" ] ?: {};
+ serverConfig.cfconfig[ "file" ] = relFilePath;
- presideLocation = "{lucee-web}/preside#versionDir#";
+ FileWrite( serverConfPath, formatterUtil.formatJson( serverConfig ) );
}
- return presideLocation;
+ return arguments.directory & relFilePath;
+
}
- private string function _setupDatasource() {
- print.line().toConsole();
- print.yellowLine( "PresideCMS datasource setup (MySQL Only)" ).toConsole();
- print.yellowLine( "========================================" ).toConsole();
+ private function _setupDatasource() {
+ print.line();
+ print.greenLine( "PRESIDE DATASOURCE SETUP" );
+ print.greenLine( "========================" );
+ print.greenLine( "No Preside Datasource found. Starting wizard to create one." );
+ print.greenLine( "NOTE: You can configure using your datasource independently in your .cfconfig file if you require a more complex datasource configuration." );
print.line().toConsole();
- if ( shell.ask( "Setup MySQL datasource now [Y/n]? " ) == "n" ) {
- return "";
- }
+ var config = {}
- print.line().toConsole();
- print.yellowLine( "If you have not done so already, please create your database and have credentials ready." ).toConsole();
- print.line().toConsole();
+ config[ "dbdriver" ] = multiselect( 'Select your database engine: ' ).options( [
+ { display='MySQL/MariaDB', value='mysql', selected=true },
+ { display='PostgreSQL', value='postgres' },
+ { display='Microsoft SQL Server', value='MSSQL' }
+ ] ).required().ask();
- var db = shell.ask( "Database name: " );
- var usr = shell.ask( "Username: " );
- var pass = shell.ask( "Password: " );
- var host = shell.ask( "Host (localhost): " );
- var port = shell.ask( "Port (3306): " );
- while( Len( Trim( port ) ) && !IsNumeric( port ) ) {
- print.redLine( "Invalid port number!" ).toConsole();
- port = shell.ask( "Port (3306): " );
- }
+ config[ "database" ] = ask( message="Database name: ", required=true );
+ config[ "username" ] = ask( message="Username: " );
+ config[ "password" ] = ask( message="Password: ", mask='*' );
+ config[ "host" ] = ask( message="Host: ", defaultResponse="localhost" );
+ config[ "port" ] = ask( message="Port: ", defaultResponse=_getDefaultPortForDb( config.dbdriver ) );
- if( !Len( Trim( host ) ) ) { host = "localhost"; }
- if( !Len( Trim( port ) ) ) { port = "3306"; }
+ return config;
+ }
- return '';
+ private function _getDefaultPortForDb( dbdriver ) {
+ switch( arguments.dbdriver) {
+ case "mssql": return 1433;
+ case "postgres": return 5432;
+ default: return 3306;
+ }
}
}